You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Feature detection is the concept of detecting if a specific feature is available, instead of developing against a specific browser. This way, developers can write their code for two cases: the browser **does** support said feature, or the browser **does not** support said feature.
8
+
There are a couple of common ways to check whether or not a particular feature is supported by a user's browser:
9
9
10
-
Developing against specific features, instead of developing against a specific browser, not only clears up the peripheral logic of your application, but also makes your job easier as a developer, for several reasons.
10
+
* Browser Detection
11
+
* Specific Feature Detection
11
12
12
-
### User-agent testing
13
+
In general, we recommend specific feature detection. Let's look at why.
13
14
14
-
Without getting into too many specifics, there are two reasons why User-Agent testing (developing against a specific browser) is looked down upon, instead of checking to see if a specific feature is supported: they are inconvenient and unreliable.
15
+
### Browser Detection
15
16
16
-
First, let's take a look at a User-Agent string (you can see yours by running `navigator.userAgent` in a JavaScript console). This is Chrome 18's User-Agent string on Mac OS X Lion:
17
+
Browser detection is a method where the browser's UserAgent (UA) string is checked for a particular pattern unique to a browser family or version. For example, this is Chrome 18's UA string on Mac OS X Lion:
17
18
18
-
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.142 Safari/535.19
19
+
```
20
+
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.142 Safari/535.19
21
+
```
22
+
23
+
Browser UA detection may check this string for something like "Chrome" or "Chrome/18" or any other part the developer feels identifies the browser they intend to target.
24
+
25
+
While this seems to be an easy solution, there are several problems:
26
+
27
+
#### Other browsers other than your target may have the same issue.
28
+
29
+
If we target a specific browser for different functionality, we implicitly exclude any browser we did not account for. This is also not future-proof. If the browser we target receives a bug fix or change, we may not be able to discern between a 'working' and 'non-working' UA string. We may also need to update our test for each new release. This isn't a maintainable solution.
30
+
31
+
#### User Agents are unreliable.
32
+
33
+
User Agents are set by the client browser. In the early days of the web, browsers would mimic each others' UA strings in order to bypass exactly this type of detection. It is still possible that a browser with very different capabilities may mimic just the portion of the UA string you're targeting.
34
+
35
+
The UA string is also user-configurable. While the user may change this string, the browser's feature support remains the same.
19
36
20
-
I think it goes without saying that User-Agent strings don't look very easy to work with. On top of that, if we were to use the User-Agent as the base case for our code, we would most likely have to double-check the functionality, or refactor our code when there was a browser update or a new browser. This is especially true now that Chrome and Firefox have a rapid release schedule.
37
+
In general, we do not recommend UA string-based feature detection.
21
38
22
-
The second (and more important) reason we recommend you not to use User-Agent testing is becuase it can be easily modified by the client, and it is **not very reliable at all**. This unreliability is due to historical reasons: as more early browsers were created, their authors would dishonestly identify their new browser by returning an incorrect User-Agent string when executing `navigator.userAgent`. It's also user-configurable, so we really cannot trust this.
39
+
### Specific Feature Detection
40
+
41
+
Specific feature detection checks if a specific feature is available, instead of developing against a specific browser. This way, developers can write their code for two cases: the browser **does** support said feature, or the browser **does not** support said feature.
42
+
43
+
Developing against specific features, instead of developing against a specific browser, not only clears up the peripheral logic of your application, but also makes your job easier as a developer.
44
+
45
+
We recommend specific feature detection over UA string detection.
46
+
47
+
Now how would you go about doing that?
23
48
24
49
### How to go about feature detection
25
50
26
-
There are several ways to go about feature detection. Let's take a look at how to check whether or not a `<canvas>` element exists in a specific browser, without using a helper library:
51
+
There are several ways to go about feature detection:
27
52
53
+
* Straight JavaScript
54
+
* $.support
55
+
* A Helper Library
56
+
57
+
#### Straight JavaScript
58
+
59
+
Let's take a look at how to check whether or not a `<canvas>` element exists in a specific browser, without using a helper library. We do this by specifically querying whether the method or property exists:
28
60
29
61
```js
30
-
//code taken from Michael Mahemoff's article on feature detection
31
-
// on HTML5Rocks: http://www.html5rocks.com/en/tutorials/detection/index.html
62
+
//We want to show a graph in browsers that support canvas, but a data table in browsers that don't.
63
+
var elem =document.createElement('canvas');
32
64
33
-
// we can create this helper to detect whether the <canvas> tag is available or not
65
+
if ( elem.getContext&&elem.getContext('2d') ) {
34
66
35
-
functionhasCanvas() {
36
-
var elem =document.createElement('canvas');
37
-
return!!(elem.getContext&&elem.getContext('2d'));
38
-
};
67
+
showGraph();
39
68
40
-
// now we can use that knowledge within our application
69
+
} else {
41
70
42
-
hasCanvas() ?showGraphWithCanvas() :showTable();
71
+
showTable();
72
+
73
+
}
43
74
```
44
75
45
-
Now, let's walk through this chunk of code piece by piece.
76
+
This is a very simple way to provide conditional experiences, depending on the features present in the user's browser. We can extract this into a helper function for reuse, but still have to write a test for every feature we're concerned about. This can be time-consuming and error-prone.
46
77
47
-
```js
48
-
functionhasCanvas() {
49
-
var elem =document.createElement('canvas');
50
-
return!!(elem.getContext&&elem.getContext('2d'));
51
-
};
52
-
```
78
+
What if someone else wrote all of that for us?
53
79
54
-
Here, we're creating a helper called `detectCanvas` that returns `true` or `false`, depending if the browser is able to perform a `getContext` on a `canvas` we create. This second line is imperative, because browsers let us create DOM elements it doesn't quite recognize. It's our job to make sure it knows what to do with them, and that's why we use the `getContext` method on the canvas to return true or false.
80
+
#### $.support
55
81
56
-
```js
57
-
hasCanvas() ?showGraphWithCanvas() :showTable();
58
-
```
82
+
jQuery performs many tests to determine feature support to allow cross-browser use of many of the features we've come to love. jQuery's internal feature detection can be accessed through [jQuery.support](http://api.jquery.com/jQuery.support/).
83
+
84
+
However, we do not recommend this for general use. As the API page says:
85
+
86
+
> Since jQuery requires these tests internally, they must be performed on every page load. Although some of these properties are documented below, they are not subject to a long deprecation/removal cycle and may be removed once internal jQuery code no longer needs them.
59
87
60
-
This line of code will execute the function `detectCanvas`, and depending on if that returns a `true` or `false`, it will execute `showGraphWithCanvas` and `showTable`, respectively.
88
+
This detection may be removed from jQuery without notice. That's reason enough not to use it. What other options do we have?
61
89
62
-
As you can tell, this is a very simple way to provide conditional experiences, depending on the features present in the user's browser.
90
+
#### A Helper Library
63
91
64
-
While writing our own feature detection tests is great, it can be time consuming and error prone. Thankfully, there are some great helper libraries (like [Modernizr](http://modernizr.com)) that provide a simple, high-level API for determining if a browser has a specific feature available or not.
92
+
Thankfully, there are some great helper libraries (like [Modernizr](http://modernizr.com)) that provide a simple, high-level API for determining if a browser has a specific feature available or not.
65
93
66
-
For example, utilizing Modernizr, we are able to do the same canvas detection test with this line of code:
94
+
For example, utilizing Modernizr, we are able to do the same canvas detection test with this code:
So, while that syntax is great, there are a few problems with this approach. First, it can end up being quite cumbersome to have several conditionals. Secondly, we're sending extra data over, regardless if we'll need it or not.
108
+
That's it. Easy.
73
109
74
-
The Modernizr object exposes a `load()` method that many prefer over the syntax mentioned previously. This is due to the awesomeness of [yepnope](http://yepnopejs.com/), and actually utilizes yepnope internally. Testing for canvas now becomes something like this:
110
+
### Performance Considerations
111
+
112
+
So, while the Modernizr syntax is great, it can end up being quite cumbersome to have several conditionals. Secondly, we're sending the code for both conditions to every browser, regardless if we'll need it or not.
113
+
114
+
The Modernizr object exposes a `load()` method that many prefer over the syntax mentioned previously. This is due to the another library that Modernizr now uses internally: [yepnope](http://yepnopejs.com/). Testing for canvas can now become something like this:
75
115
76
116
```js
77
117
Modernizr.load({
@@ -81,25 +121,23 @@ Modernizr.load({
81
121
});
82
122
```
83
123
84
-
Using the `load` method allows us to send only the required polyfills and code over the wire. I think it is extremely useful because developers can pass an array of objects as an argument to `.load()`, and it will serve the correct files to the correct audience.
124
+
Using the `load` method allows us to send only the required polyfills and code over the wire. You can also pass an array of objects as an argument to `.load()`, and it will serve the correct files to the correct audience.
85
125
86
-
### Tools commonly used to aid in feature detection
126
+
Additionally, Modernizr has a [production build configurator](http://modernizr.com/download/) that allows you to specify exactly what parts of Modernizr you want to include and exclude the parts you don't.
87
127
88
-
Below is a list of commonly used tools that aid in the feature detection process.
128
+
### Other Resources
129
+
130
+
#### Feature Detection Tools
89
131
90
132
-[modernizr](http://modernizr.com/) - conditionally check to see if a specific feature is available in a browser
jQuery exposes two objects that help developers know about the user's environment (although one has been deprecated): `$.support` and `$.browser` (which has been deprecated). Many developers mistakenly believe using `$.support` is sufficient for detecting the support of a specific feature. Actually, jQuery uses `$.support` only for support tests **jQuery** needs to function properly (for example, the box model).
99
-
100
-
With that being said, it is recommended that you utilize a proven method of feature detection, such as [Modernizr](http://modernizr.com).
101
-
102
-
### Other resources to check out re: feature detection
-[Using Modernizr to detect HTML5 and CSS3 browser support](http://www.adobe.com/devnet/dreamweaver/articles/using-modernizr.html)
104
142
-[polyfilling the html5 gap](http://addyosmani.com/polyfillthehtml5gaps/slides/#1) by Addy Osmani
105
-
-[feature, browser, and form factor detection](http://addyosmani.com/polyfillthehtml5gaps/slides/#1) by Michael Mahemoff
143
+
-[Feature, Browser, and Form Factor Detection: It's Good for the Environment](http://www.html5rocks.com/en/tutorials/detection/index.html) by Michael Mahemoff
0 commit comments