Movatterモバイル変換


[0]ホーム

URL:


  1. Learn
  2. Extension modules
  3. Testing
  4. Feature detection

Implementing feature detection

Feature detection involves working out whether a browser supports a certain block of code, and running different code depending on whether it does (or doesn't), so that the browser can always provide a working experience rather than crashing/erroring in some browsers. This article details how to write your own simple feature detection, how to use a library to speed up implementation, and native features for feature detection such as@supports.

Prerequisites: Familiarity with the coreHTML,CSS, andJavaScript languages; an idea of the high-levelprinciples of cross-browser testing.
Objective: To understand what the concept of feature detection is, and be able to implement suitable solutions in CSS and JavaScript.

The concept of feature detection

The idea behind feature detection is that you can run a test to determine whether a feature is supported in the current browser, and then conditionally run code to provide an acceptable experience both in browsers thatdo support the feature, and browsers thatdon't. If you don't do this, browsers that don't support the features you are using in your code may not display your sites properly or might fail altogether, creating a bad user experience.

Let's recap and look at the example we touched on in ourJavaScript debugging and error handling article — theGeolocation API (which exposes available location data for the device the web browser is running on) has the main entry point for its use, ageolocation property available on the globalNavigator object. Therefore, you can detect whether the browser supports geolocation or not by using something like the following:

js
if ("geolocation" in navigator) {  navigator.geolocation.getCurrentPosition((position) => {    // show the location on a map, such as the Google Maps API  });} else {  // Give the user a choice of static maps}

Before we move on, we'd like to say one thing upfront — don't confuse feature detection withbrowser sniffing (detecting what specific browser is accessing the site) — this is a terrible practice that should be discouraged at all costs. SeeBrowser detection using the user agent string (UA sniffing) for more details.

Writing your own feature detection tests

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

CSS

You can write tests for CSS features by testing for the existence ofelement.style.property (e.g.,paragraph.style.rotate) in JavaScript.

A classic example might be to test forSubgrid support in a browser; for browsers that support thesubgrid value for a subgrid value forgrid-template-columns andgrid-template-rows, we can use subgrid in our layout. For browsers that don't, we could use regular grid that works fine but is not as cool-looking.

Using this as an example, we could include a subgrid stylesheet if the value is supported and a regular grid stylesheet if not. To do so, we could include two stylesheets in the head of our HTML file: one for all the styling, and one that implements the default layout if subgrid is not supported:

html
<link href="basic-styling.css" rel="stylesheet" /><link href="grid-layout.css" rel="stylesheet" />

Here,basic-styling.css handles all the styling that we want to give to every browser. We have two additional CSS files,grid-layout.css andsubgrid-layout.css, which contain the CSS we want to selectively apply to browsers depending on their support levels.

We use JavaScript to test the support for the subgrid value, then update thehref of our conditional stylesheet based on browser support.

We can add a<script></script> to our document, filled with the following JavaScript

js
const conditional = document.querySelector(".conditional");if (CSS.supports("grid-template-columns", "subgrid")) {  conditional.setAttribute("href", "subgrid-layout.css");}

In our conditional statement, we test to see if thegrid-template-columns property supports thesubgrid value usingCSS.supports().

@supports

CSS has a native feature detection mechanism: the@supports at-rule. This works in a similar manner tomedia queries except that instead of selectively applying CSS depending on a media feature like a resolution, screen width oraspect ratio, it selectively applies CSS depending on whether a CSS feature is supported, similar toCSS.supports().

For example, we could rewrite our previous example to use@supports:

css
@supports (grid-template-columns: subgrid) {  main {    display: grid;    grid-template-columns: repeat(9, 1fr);    grid-template-rows: repeat(4, minmax(100px, auto));  }  .item {    display: grid;    grid-column: 2 / 7;    grid-row: 2 / 4;    grid-template-columns: subgrid;    grid-template-rows: repeat(3, 80px);  }  .subitem {    grid-column: 3 / 6;    grid-row: 1 / 3;  }}

This at-rule block applies the CSS rule within only if the current browser supports thegrid-template-columns: subgrid; declaration. For a condition with a value to work, you need to include a complete declaration (not just a property name) and NOT include the semicolon on the end.

@supports also hasAND,OR, andNOT logic available — the other block applies the regular grid layout if the subgrid option is not available:

css
@supports not (grid-template-columns: subgrid) {  /* rules in here */}

This is 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. For this reason it is the preferred method of determining browser support for CSS features.

JavaScript

We already saw an example of a JavaScript feature detection test earlier on. Generally, such tests are done via one of a few common patterns.

Common patterns for detectable features include:

Members of an object

Check whether a particular method or property (typically an entry point into using the API or other feature you are detecting) exists in its parentObject.

Our earlier example used this pattern to detectGeolocation support by testing thenavigator object for ageolocation member:

js
if ("geolocation" in navigator) {  // Access navigator.geolocation APIs}
Properties of an element

Create an element in memory usingDocument.createElement() and then check if a property exists on it.

This example shows a way of detectingCanvas API support:

js
function supportsCanvas() {  return !!document.createElement("canvas").getContext;}if (supportsCanvas()) {  // Create and draw on canvas elements}

Note:The doubleNOT in the above example (!!) is a way to force a return value to become a "proper" boolean value, rather than aTruthy/Falsy value that may skew the results.

Specific return values of a method on an element

Create an element in memory usingDocument.createElement() and then check if a method exists on it. If it does, check what value it returns.

Retention of assigned property value by an element

Create an element in memory usingDocument.createElement(), set a property to a specific value, then check to see if the value is retained.

Bear in mind that some features are, however, known to be undetectable. In these cases, you'll need to use a different approach, such as using apolyfill.

matchMedia

We also wanted to mention theWindow.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:

js
if (window.matchMedia("(width <= 480px)").matches) {  // run JavaScript in here.}

As an example, ourSnapshot 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 themedia attribute to only apply the Brick CSS to the page if the page width is 480px or less:

html
<link href="dist/brick.css" rel="stylesheet" media="(width <= 480px)" />

We then usematchMedia() 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).

js
if (window.matchMedia("(width <= 480px)").matches) {  deck.shuffleTo(1);}

Summary

This article covered feature detection in a reasonable amount of detail, going through the main concepts and showing you how to implement your own feature detection tests.

Next up, we'll start looking at automated testing.

Help improve MDN

Learn how to contribute

This page was last modified on byMDN contributors.


[8]ページ先頭

©2009-2025 Movatter.jp