Skip to content

Commit cacffcd

Browse files
committed
enhance feature & browser detection page - fixes jquery#92
1 parent f989df7 commit cacffcd

File tree

1 file changed

+89
-51
lines changed

1 file changed

+89
-51
lines changed
Lines changed: 89 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,117 @@
11
---
2-
title: What is Feature Detection
3-
attribution: Connor Montgomery
2+
title: Feature & Browser Detection
3+
attribution: Connor Montgomery & bobholt
44
---
55

6-
### What is feature detection?
6+
### Can I Use This Browser Feature?
77

8-
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:
99

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
1112

12-
### User-agent testing
13+
In general, we recommend specific feature detection. Let's look at why.
1314

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
1516

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 User Agent (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:
1718

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.
1936

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.
2138

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?
2348

2449
### How to go about feature detection
2550

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:
2752

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:
2860

2961
```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');
3264

33-
// we can create this helper to detect whether the <canvas> tag is available or not
65+
if ( elem.getContext && elem.getContext('2d') ) {
3466

35-
function hasCanvas() {
36-
var elem = document.createElement('canvas');
37-
return !!(elem.getContext && elem.getContext('2d'));
38-
};
67+
showGraph();
3968

40-
// now we can use that knowledge within our application
69+
} else {
4170

42-
hasCanvas() ? showGraphWithCanvas() : showTable();
71+
showTable();
72+
73+
}
4374
```
4475

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.
4677

47-
```js
48-
function hasCanvas() {
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?
5379

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
5581

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.
5987
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?
6189

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
6391

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.
6593

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:
6795

6896
```js
69-
Modernizr.canvas ? showGraphWithCanvas() : showTable();
97+
if ( Modernizr.canvas ) {
98+
99+
showGraphWithCanvas();
100+
101+
} else {
102+
103+
showTable();
104+
105+
}
70106
```
71107

72-
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.
73109

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:
75115

76116
```js
77117
Modernizr.load({
@@ -81,25 +121,23 @@ Modernizr.load({
81121
});
82122
```
83123

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.
85125

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.
87127

88-
Below is a list of commonly used tools that aid in the feature detection process.
128+
### Other Resources
129+
130+
#### Feature Detection Tools
89131

90132
- [modernizr](http://modernizr.com/) - conditionally check to see if a specific feature is available in a browser
91-
- [yepnope](http://yepnopejs.com/) - conditional polyfill loader
92133
- [html5please](http://html5please.com/) - use the new and shiny responsibly
93134
- [html5please api](http://api.html5please.com/) - an API you can query to see how good (or bad) support for a specific feature is.
94135
- [caniuse](http://caniuse.com/) - browser compatibility tables for HTML5, CSS3, SVG, etc…
136+
- [yepnope](http://yepnopejs.com/) - conditional polyfill loader
95137

96-
### Feature detection & jQuery
97-
98-
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
138+
#### Helpful Articles
103139

140+
- [Browser Feature Detection](https://developer.mozilla.org/en-US/docs/Browser_Feature_Detection)
141+
- [Using Modernizr to detect HTML5 and CSS3 browser support](http://www.adobe.com/devnet/dreamweaver/articles/using-modernizr.html)
104142
- [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

Comments
 (0)