aboutsummaryrefslogtreecommitdiff
path: root/files/zh-cn/learn/tools_and_testing/cross_browser_testing/feature_detection/index.html
blob: 34f3e66ba45c5302dea6632423f259e6f8b8c372 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
---
title: Implementing feature detection
slug: Learn/Tools_and_testing/Cross_browser_testing/Feature_detection
translation_of: Learn/Tools_and_testing/Cross_browser_testing/Feature_detection
---
<div>{{LearnSidebar}}</div>

<div>{{PreviousMenuNext("Learn/Tools_and_testing/Cross_browser_testing/Accessibility","Learn/Tools_and_testing/Cross_browser_testing/Automated_testing", "Learn/Tools_and_testing/Cross_browser_testing")}}</div>

<p class="summary">特性检测包括计算浏览器是否支持一个特定块中的代码,基于是否可以运行来运行不同的代码,以使所有的浏览器都可以正常工作,而不是在某些浏览器中崩溃或出错。本文列举了如何写出一个你自己的简单的特性检测,如何使用库来加速实现,以及对于特性间的的原生特性,如 <code>@supports</code></p>

<table class="learn-box standard-table">
 <tbody>
  <tr>
   <th scope="row">Prerequisites:</th>
   <td>Familiarity with the core <a href="/en-US/docs/Learn/HTML">HTML</a>, <a href="/en-US/docs/Learn/CSS">CSS</a>, and <a href="/en-US/docs/Learn/JavaScript">JavaScript</a> languages; an idea of the high-level <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Introduction">principles of cross-browser testing</a>.</td>
  </tr>
  <tr>
   <th scope="row">Objective:</th>
   <td>To understand what the concept of feature detection is, and be able to implement suitable solutions in CSS and JavaScript.</td>
  </tr>
 </tbody>
</table>

<h2 id="特性检测的概念">特性检测的概念</h2>

<p>功能检测的思想是,您可以运行一个测试来确定当前浏览器是否支持某个特性,然后有条件地运行代码,以便在支持该功能的浏览器和不支持该功能的浏览器中提供可接受的体验,如果不这样做,在不支持您在代码中使用的功能的浏览器中将无法正确地显示您的网站,从而产生糟糕的用户体验。</p>

<p>Let's recap and look at the example we touched on in our <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/JavaScript#Feature_detection">Handling common JavaScript problems</a> — the <a href="/en-US/docs/Web/API/Geolocation/Using_geolocation">Geolocation API</a> (which exposes available location data for the device the web browser is running on) has the main entry point for its use, a <code>geolocation</code> property available on the global <a href="/en-US/docs/Web/API/Navigator">Navigator</a> object. Therefore, you can detect whether the browser supports geolocation or not by using something like the following:</p>

<pre class="language-js notranslate">if ("geolocation" in navigator) {
  navigator.geolocation.getCurrentPosition(function(position) {
    // show the location on a map, perhaps using the Google Maps API
  });
} else {
  // Give the user a choice of static maps instead perhaps
}</pre>

<p>It is probably better to use an established feature detection library however, rather than writing your own all the time. Modernizr is the industry standard for feature detection tests, and we'll look at that later on.</p>

<p>Before we move on, we'd like to say one thing upfront — don't confuse feature detection with <strong>browser sniffing</strong> (detecting what specific browser is accessing the site) — this is a terrible practice that should be discouraged at all costs. See <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/JavaScript#Using_bad_browser_sniffing_code">Using bad browser sniffing code</a> for more details.</p>

<h2 id="Writing_your_own_feature_detection_tests">Writing your own feature detection tests</h2>

<p>In this section, we'll look at implementing your own feature detection tests, in both CSS and JavaScript.</p>

<h3 id="CSS">CSS</h3>

<p>You can write tests for CSS features by testing for the existence of <em><a href="/en-US/docs/Web/API/HTMLElement/style">element.style.property</a></em> (e.g. <code>paragraph.style.transform</code>) in JavaScript.</p>

<p>A classic example might be to test for <a href="/en-US/docs/Learn/CSS/CSS_layout/Flexbox">Flexbox</a> support in a browser; for browsers that support the newest Flexbox spec, we could use a flexible and robust flex layout. For browsers that don't, we could use a floated layout that works OK, although it is slightly more brittle and hacky, and not as cool-looking.</p>

<p>Let's implement something that demonstrates this, although we'll keep it simple for now.</p>

<ol>
 <li>Start by making local copies of our <code><a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/feature-detection/css-feature-detect.html">css-feature-detect.html</a></code>, <code><a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/feature-detection/flex-layout.css">flex-layout.css</a></code>, <code><a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/feature-detection/float-layout.css">float-layout.css</a></code>, and <code><a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/feature-detection/basic-styling.css">basic-styling.css</a></code> files. Save them in a new directory.</li>
 <li>We will add the HTML5 Shiv to our example too so that the HTML5 semantic elements will style properly in older versions of IE. Download the latest version (see <a href="https://github.com/aFarkas/html5shiv#manual-installation">Manual installation</a>), unzip the ZIP file, copy the <code>html5shiv-printshiv.min.js</code> and <code>html5shiv.min.js</code> files into your example directory, and link to one of the files by putting the following under your {{htmlelement("title")}} element:
  <pre class="notranslate">&lt;script src="html5shiv.min.js"&gt;&lt;/script&gt;</pre>
 </li>
 <li>Have a look at your example CSS files — you'll see that <code>basic-styling.css</code> handles all the styling that we want to give to every browser, whereas the other two CSS files contain the CSS we want to selectively apply to browser depending on their support levels. You can look at the different effects these two files have by manually changing the CSS file referred to by the second {{htmlelement("link")}} element, but let's instead implement some JavaScript to automatically swap them as needed.</li>
 <li>First, remove the contents of the second <code>&lt;link&gt;</code> element's <code>href</code> attribute. We will fill this in dynamically later on.</li>
 <li>Next, add a <code>&lt;script&gt;&lt;/script&gt;</code> element at the bottom of your body (just before the closing <code>&lt;/body&gt;</code> tag).</li>
 <li>Give it the following contents:
  <pre class="brush: js notranslate">const conditional = document.querySelector('.conditional');
const testElem = document.createElement('div');
if (testElem.style.flex !== undefined &amp;&amp; testElem.style.flexFlow !== undefined) {
  conditional.setAttribute('href', 'flex-layout.css');
} else {
  conditional.setAttribute('href', 'float-layout.css');
}</pre>
 </li>
</ol>

<p>Here we are grabbing a reference to the second <code>&lt;link&gt;</code> element, and creating a <code>&lt;div&gt;</code> element as part of our test. In our conditional statement, we test that the {{cssxref("flex")}} and {{cssxref("flex-flow")}} properties exist in the browser. Note how the JavaScript representations of those properties that are stored inside the {{domxref("HTMLElement.style")}} object use lower camel case, not hyphens, to separate the words.</p>

<div class="note">
<p><strong>Note</strong>: If you have trouble getting this to work, you can compare it to our <a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/feature-detection/css-feature-detect-finished.html">css-feature-detect-finished.html</a> code (see also the <a href="http://mdn.github.io/learning-area/tools-testing/cross-browser-testing/feature-detection/css-feature-detect-finished.html">live version</a>).</p>
</div>

<p>When you save everything and try out your example, you should see the flexbox layout applied to the page if the browser supports modern flexbox, and the float layout if not.</p>

<div class="note">
<p><strong>Note</strong>: Often such an approach is overkill for a minor feature detection problem — you can often get away with using multiple vendor prefixes and fallback properties, as described in <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/HTML_and_CSS#CSS_fallback_behaviour">CSS fallback behavior</a> and <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/HTML_and_CSS#Handling_CSS_prefixes">Handling CSS prefixes</a>.</p>
</div>

<h4 id="supports">@supports</h4>

<p>In recent times, CSS has had its own native feature detection mechanism introduced — the {{cssxref("@supports")}} at-rule. This works in a similar manner to <a href="/en-US/docs/Web/CSS/Media_Queries">media queries</a> (see also <a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/HTML_and_CSS#Responsive_design_problems">Responsive design problems</a>) — except that instead of selectively applying CSS depending on a media feature like a resolution, screen width or aspect ratio, it selectively applies CSS depending on whether a CSS feature is supported.</p>

<p>For example, we could rewrite our previous example to use <code>@supports</code> — see <code><a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/feature-detection/supports-feature-detect.html">supports-feature-detect.html</a></code> and <code><a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/feature-detection/supports-styling.css">supports-styling.css</a></code>. If you look at the latter, you'll see a couple of <code>@supports</code> blocks, for example:</p>

<pre class="brush: css notranslate">@supports (flex-flow: row) and (flex: 1) {

  main {
    display: flex;
  }

  main div {
    padding-right: 4%;
    flex: 1;
  }

  main div:last-child {
    padding-right: 0;
  }

}</pre>

<p>This at-rule block applies the CSS rule within only if the current browser supports both the <code>flex-flow: row</code> and <code>flex: 1</code> declarations. For each condition to work, you need to include a complete declaration (not just a property name) and NOT include the semi-colon on the end.</p>

<p><code>@supports</code> also has <code>OR</code> and <code>NOT</code> logic available — the other block applies the float layout if the flexbox properties are not available:</p>

<pre class="brush: css notranslate">@supports not (flex-flow: row) and (flex: 1) {

  /* rules in here */

}</pre>

<p>This may look a lot more convenient than the previous example — we can do all of our feature detection in CSS, no JavaScript required, and we can handle all the logic in a single CSS file, cutting down on HTTP requests. the problem here is browser support — <code>@supports</code> is not supported at all in IE, and only supported in very recent versions of Safari/iOS WebKit (9+/9.2+), whereas the JavaScript version should work in much older browsers (probably back to IE8 or 9, although older versions of IE will have additional problems, such as not supporting {{domxref("Document.querySelector")}}, and having a messed up box model).</p>

<h3 id="JavaScript">JavaScript</h3>

<p>We already saw an example of a JavaScript feature detection test earlier on. Generally, such tests are done via one of the following common patterns:</p>

<table class="standard-table">
 <caption>Summary of JavaScript feature detection techniques</caption>
 <thead>
  <tr>
   <th scope="col">Feature detection type</th>
   <th scope="col">Explanation</th>
   <th scope="col">Example</th>
  </tr>
 </thead>
 <tbody>
  <tr>
   <td><em>If member in object</em></td>
   <td>Check whether a certain method or property (typically an entry point into using the API or other feature you are detecting for) exists in its parent Object.</td>
   <td>
    <p><code>if("geolocation" in navigator) { ... }</code></p>
   </td>
  </tr>
  <tr>
   <td><em>Property on element</em></td>
   <td>Create an element in memory using {{domxref("Document.createElement()")}} and then check if a property exists on it. The example shown is a way of detecting <a href="/en-US/docs/Web/API/Canvas_API">HTML5 Canvas</a> support.</td>
   <td><code>function supports_canvas() {<br>
    return !!document.createElement('canvas').getContext;<br>
    }<br>
    <br>
    if(supports_canvas()) { ... }</code></td>
  </tr>
  <tr>
   <td><em>Method on element return value</em></td>
   <td>Create an element in memory using {{domxref("Document.createElement()")}} and then check if a method exists on it. If it does, check what value it returns.</td>
   <td>See <a href="http://diveinto.html5doctor.com/detect.html#video-formats">Dive Into HTML5 Video Formats detection</a> test.</td>
  </tr>
  <tr>
   <td><em>Property on element retains value</em></td>
   <td>Create an element in memory using {{domxref("Document.createElement()")}}, set a property to a certain value, then check to see if the value is retained.</td>
   <td>See <a href="http://diveinto.html5doctor.com/detect.html#input-types">Dive into HTML5 <code>&lt;input&gt;</code> types detection</a> test.</td>
  </tr>
 </tbody>
</table>

<div class="note">
<p><strong>Note</strong>: The double <code>NOT</code> in the above example (<code>!!</code>) is a way to force a return value to become a "proper" boolean value, rather than a {{glossary("Truthy")}}/{{glossary("Falsy")}} value that may skew the results.</p>
</div>

<p>The <a href="http://diveinto.html5doctor.com/detect.html">Dive into HTML5 Detecting HTML5 Features</a> page has a lot more useful feature detection tests besides the ones listed above, and you can generally find a feature detection test for most things by searching for "detect support for YOUR-FEATURE-HERE" in your favorite search engine. Bear in mind though that some features, however, are known to be undetectable — see Modernizr's list of <a href="https://github.com/Modernizr/Modernizr/wiki/Undetectables">Undetectables</a>.</p>

<h4 id="matchMedia">matchMedia</h4>

<p>We also wanted to mention the {{domxref("Window.matchMedia")}} JavaScript feature at this point too. This is a property that allows you to run media query tests inside JavaScript. It looks like this:</p>

<pre class="brush: js notranslate">if (window.matchMedia("(max-width: 480px)").matches) {
  // run JavaScript in here.
}</pre>

<p>As an example, our <a href="https://github.com/chrisdavidmills/snapshot">Snapshot</a> demo makes use of it to selectively apply the Brick JavaScript library and use it to handle the UI layout, but only for the small screen layout (480px wide or less). We first use the <code>media</code> attribute to only apply the Brick CSS to the page if the page width is 480px or less:</p>

<pre class="brush: css notranslate">&lt;link href="dist/brick.css" type="text/css" rel="stylesheet" media="all and (max-width: 480px)"&gt;</pre>

<p>We then use <code>matchMedia()</code> in the JavaScript several times, to only run Brick navigation functions if we are on the small screen layout (in wider screen layouts, everything can be seen at once, so we don't need to navigate between different views).</p>

<pre class="brush: js notranslate">if (window.matchMedia("(max-width: 480px)").matches) {
  deck.shuffleTo(1);
}</pre>

<h2 id="Using_Modernizr_to_implement_feature_detection">Using Modernizr to implement feature detection</h2>

<p>It is possible to implement your own feature detection tests using techniques like the ones detailed above. You might as well use a dedicated feature detection library however, as it makes things much easier. The mother of all feature detection libraries is <a href="https://modernizr.com/">Modernizr</a>, and it can detect just about everything you'll ever need. Let's look at how to use it now.</p>

<p>When you are experimenting with Modernizr you might as well use the development build, which includes every possible feature detection test. Download this now by:</p>

<ol>
 <li>Clicking on the <a href="https://modernizr.com/download?do_not_use_in_production">Development build</a> link.</li>
 <li>Clicking the big pink <em>Build</em> button on the page that comes up.</li>
 <li>Clicking the top <em>Download</em> link in the dialog box that appears.</li>
</ol>

<p>Save it somewhere sensible, like the directory you've been creating your other examples for in this article.</p>

<p>When you are using Modernizr in production, you can go to the <a href="https://modernizr.com/download">Download page</a> you've already visited and click the plus buttons for only the features you need feature detects for. Then when you click the <em>Build</em> button, you'll download a custom build containing only those feature detects, making for a much smaller file size.</p>

<h3 id="CSS_2">CSS</h3>

<p>Let's have a look at how Modernizr works in terms of selectively applying CSS.</p>

<ol>
 <li>First, make a copy of <code><a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/feature-detection/supports-feature-detect.html">supports-feature-detect.html</a></code> and <code><a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/feature-detection/supports-styling.css">supports-styling.css</a></code>. Save them as <code>modernizr-css.html</code> and <code>modernizr-css.css</code>.</li>
 <li>Update your {{htmlelement("link")}} element in your HTML so it points to the correct CSS file (you should also update your {{htmlelement("title")}} element to something more suitable!):
  <pre class="brush: html notranslate">&lt;link href="modernizr-css.css" rel="stylesheet"&gt;</pre>
 </li>
 <li>Above this <code>&lt;link&gt;</code> element, add a {{htmlelement("script")}} element to apply the Modernizr library to the page, as shown below. This needs to be applied to the page before any CSS (or JavaScript) that might make use of it.
  <pre class="brush: html notranslate">&lt;script src="modernizr-custom.js"&gt;&lt;/script&gt;</pre>
 </li>
 <li>Now edit your opening <code>&lt;html&gt;</code> tag, so that it looks like this:
  <pre class="brush: html notranslate">&lt;html class="no-js"&gt;</pre>
 </li>
</ol>

<p>At this point, try loading your page, and you'll get an idea of how Modernizr works for CSS features. If you look at the DOM inspector of your browser's developer tools, you'll see that Modernizr has updated your <code>&lt;html&gt;</code> <code>class</code> value like so:</p>

<pre class="notranslate">&lt;html class="js no-htmlimports sizes flash transferables applicationcache blobconstructor
blob-constructor cookies cors ...AND LOADS MORE VALUES!&gt;</pre>

<p>It now contains a large number of classes that indicate the support status of different technology features. As an example, if the browser didn't support flexbox at all, <code>&lt;html&gt;</code> would be given a class name of <code>no-flexbox</code>. If it did support modern flexbox, it would get a class name of <code>flexbox</code>. If you search through the class list, you'll also see others relating to flexbox, like:</p>

<ul>
 <li><code>flexboxlegacy</code> for the old flexbox spec (2009).</li>
 <li><code>flexboxtweener</code> for 2011 in between syntax supported by IE10.</li>
 <li><code>flexwrap</code> for the {{cssxref("flex-wrap")}} property, which isn't present in some implementations.</li>
</ul>

<div class="note">
<p><strong>Note</strong>: You can find a list of what all the class names mean — see <a href="https://modernizr.com/docs#features">Features detected by Modernizr</a>.</p>
</div>

<p>Moving on, let's update our CSS to use Modernizr rather than <code>@supports</code>. Go into <code>modernizr-css.css</code>, and replace the two <code>@supports</code> blocks with the following:</p>

<pre class="brush: css notranslate">/* Properties for browsers with modern flexbox */

.flexbox main {
  display: flex;
}

.flexbox main div {
  padding-right: 4%;
  flex: 1;
}

.flexbox main div:last-child {
  padding-right: 0;
}

/* Fallbacks for browsers that don't support modern flexbox */

.no-flexbox main div {
  width: 22%;
  float: left;
  padding-right: 4%;
}

.no-flexbox main div:last-child {
  padding-right: 0;
}

.no-flexbox footer {
  clear: left;
}</pre>

<p>So how does this work? Because all those class names have been put on the <code>&lt;html&gt;</code> element, you can target browsers that do or don't support a feature using specific descendant selectors. So here we're applying the top set of rules only to browsers that do support flexbox, and the bottom set of rules only to browsers that don't (<code>no-flexbox</code>).</p>

<div class="note">
<p><strong>Note</strong>: Bear in mind that all of Modernizr's HTML and JavaScript feature tests are also reported in these class names, so you can quite happily apply CSS selectively based on whether the browser supports HTML or JavaScript features, if needed.</p>
</div>

<div class="note">
<p><strong>Note</strong>: If you have trouble getting this to work, check your code against our <code><a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/feature-detection/modernizr-css.html">modernizr-css.html</a></code> and <code><a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/feature-detection/modernizr-css.css">modernizr-css.css</a></code> files (see this running live also).</p>
</div>

<h3 id="JavaScript_2">JavaScript</h3>

<p>Modernizr is also equally well-prepared for implementing JavaScript feature detects too. It does this by making the global <code>Modernizr</code> object available to the page it is applied to, which contains results of the feature detects as <code>true</code>/<code>false</code> properties.</p>

<p>For example, load up our <code><a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/feature-detection/modernizr-css.html">modernizr-css.html</a></code> example in your browser, then try going to your JavaScript console and typing in <code>Modernizr.</code> followed by some of those class names (they are the same here too). For example:</p>

<pre class="notranslate">Modernizr.flexbox
Modernizr.websqldatabase
Modernizr.xhr2
Modernizr.fetch</pre>

<p>The console will return <code>true</code>/<code>false</code> values to indicate whether your browser supports those features or not.</p>

<p>Let's look at an example to show how you'd use those properties.</p>

<ol>
 <li>First of all, make a local copy of the <code><a href="https://github.com/mdn/learning-area/blob/master/tools-testing/cross-browser-testing/feature-detection/modernizr-js.html">modernizr-js.html</a></code> example file.</li>
 <li>Attach the Modernizr library to the HTML using a <code>&lt;script&gt;</code> element, as we have done in previous demos. Put it above the existing <code>&lt;script&gt;</code> element, which is attaching the Google Maps API to the page.</li>
 <li>Next, fill in the <code>YOUR-API-KEY</code> placeholder text in the second <code>&lt;script&gt;</code> element (as it is now) with a valid Google Maps API key. To get a key, sign in to a Google account, go to the <a href="https://developers.google.com/maps/documentation/javascript/get-api-key">Get a Key/Authentication</a> page, then click the blue <em>Get a Key</em> button and follow the instructions.</li>
 <li>Finally, add another <code>&lt;script&gt;</code> element at the bottom of the HTML body (just before the <code>&lt;/body&gt;</code> tag), and put the following script inside the tags:
  <pre class="brush: js notranslate">if (Modernizr.geolocation) {

  navigator.geolocation.getCurrentPosition(function(position) {

    let latlng = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);
    let myOptions = {
      zoom: 8,
      center: latlng,
      mapTypeId: google.maps.MapTypeId.TERRAIN,
      disableDefaultUI: true
    }
    let map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
  });

} else {
  const para = document.createElement('p');
  para.textContent = 'Argh, no geolocation!';
  document.body.appendChild(para);
}</pre>
 </li>
</ol>

<p>Try your example out! Here we use the <code>Modernizr.geolocation</code> test to check whether geolocation is supported by the current browser. If it is, we run some code that gets your device's current location, and plots it on a Google Map.</p>

<h2 id="Summary">Summary</h2>

<p>This article covered feature detection in a reasonable amount of detail, going through the main concepts and showing you how to both implement your own feature detection tests and use the Modernizr library to implement tests more easily.</p>

<p>Next up, we'll start looking at automated testing.</p>

<p>{{PreviousMenuNext("Learn/Tools_and_testing/Cross_browser_testing/Accessibility","Learn/Tools_and_testing/Cross_browser_testing/Automated_testing", "Learn/Tools_and_testing/Cross_browser_testing")}}</p>

<h2 id="In_this_module">In this module</h2>

<ul>
 <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Introduction">Introduction to cross browser testing</a></li>
 <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Testing_strategies">Strategies for carrying out testing</a></li>
 <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/HTML_and_CSS">Handling common HTML and CSS problems</a></li>
 <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/JavaScript">Handling common JavaScript problems</a></li>
 <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility">Handling common accessibility problems</a></li>
 <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Feature_detection">Implementing feature detection</a></li>
 <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Automated_testing">Introduction to automated testing</a></li>
 <li><a href="/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Your_own_automation_environment">Setting up your own test automation environment</a></li>
</ul>