Feature detection is the robust, future-proof alternative to browser sniffing — querying a browser's actual capabilities directly rather than trying to infer them from an unreliable identity string.
1Why Browser Sniffing Fails Over Time
Checking navigator.userAgent to identify a specific browser and branch logic accordingly seems intuitive, but is structurally fragile in several ways: user agent strings can be deliberately spoofed by users, proxies, or testing tools; browsers periodically change their exact identification string format for privacy or compatibility reasons; and many differently-branded browsers share the same underlying rendering engine (Chromium powers Chrome, Edge, Brave, Opera, and others), making 'is this browser X' an increasingly poor proxy for 'does this browser support feature Y'.
Code written against specific user agent strings requires ongoing maintenance as browsers evolve and new ones launch — a maintenance burden feature detection eliminates entirely.
2Detecting JavaScript And HTML API Support Directly
Feature detection replaces the identity question with a direct capability question: instead of 'is this browser X', ask 'does this browser support capability Y' by checking directly for the property, method, or element behavior you actually need — if ('showPicker' in HTMLInputElement.prototype), or if (window.IntersectionObserver).
This approach is inherently future-proof: any browser, including ones released after the code was written, that implements the checked capability will correctly pass the check, with zero ongoing maintenance required as the browser landscape evolves.
3CSS's Native @supports Detection
CSS provides its own dedicated feature-detection mechanism: the @supports at-rule, which conditionally applies a block of styles based on whether the browser actually supports a specific CSS property and value combination — directly mirroring the JavaScript feature-detection pattern, but native to CSS with no JavaScript required.
@supports not (...) provides the inverse, letting a stylesheet supply an explicit fallback styling strategy for browsers lacking a given capability, completing a full progressive-enhancement pattern entirely within CSS itself.
4Step-by-Step Breakdown
Ask What The Browser Can Do, Not Who It Is. Instead of asking 'is this Safari?' (browser sniffing, an unreliable, spoofable, high-maintenance approach), feature detection asks the browser directly: 'do you support this specific capability?' — a more robust, future-proof way to make compatibility decisions at runtime.
Browser Sniffing Is Fragile And Unreliable. Checking navigator.userAgent to identify a specific browser is fragile: user agent strings can be spoofed, browsers change their identification strings over time, and the same browser engine (like Chromium) powers many differently-branded browsers with potentially different feature sets.
Why Browser Sniffing Fails. What's a core structural problem with using navigator.userAgent string matching to make compatibility decisions?
- →It's actually fully reliable; there's no real problem
- →User agent strings can be spoofed and change over time, making detection unreliable
- →It only ever works correctly for Safari specifically
Feature Detection In JavaScript. Instead of identifying the browser, check directly whether the specific capability you need exists — 'if ("dialog" in HTMLElement.prototype)' or checking for a method's existence on an object — a check that remains accurate regardless of which browser or future browser version is running it.
JavaScript Feature Detection. Why does checking if ('showPicker' in HTMLInputElement.prototype) remain accurate even for browsers that don't exist yet at the time the code was written?
- →It's checking against a hardcoded list of known browser versions
- →It directly queries the actual capability, independent of browser identity
- →It's coincidental and not actually reliable long-term
@supports For CSS Feature Detection. CSS has its own native feature detection mechanism, the @supports at-rule, letting a stylesheet apply styles conditionally based on whether the browser actually supports a given CSS property or value — the CSS equivalent of the JavaScript feature-detection pattern.
CSS Feature Detection. What does the CSS @supports at-rule allow a stylesheet to do?
- →Check which specific browser is rendering the page
- →Apply styles conditionally based on whether a CSS property/value is actually supported
- →Execute arbitrary JavaScript from within a stylesheet
Feature Detection Mastered. You now understand why feature detection is more robust than browser sniffing, how to detect JavaScript API and HTML element support directly, and how CSS's native @supports at-rule provides the same capability at the styling layer — completing the Web Standards module.
Detect Module Support At The HTML Level. nomodule marks a fallback script that only runs in browsers without ES module support.
Level Up 🚀
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1Feature Detection Enables Reliable Progressive Enhancement For Accessibility-Related APIs Too
Capabilities like the Intersection Observer API (used for accessible lazy-loading patterns) or newer ARIA-related features can be detected directly and enhanced conditionally, keeping a functional baseline intact regardless of support gaps.
SEO Implications
- 1
Reliable Feature Detection Helps Ensure Crawlers Receive The Same Functional Baseline As Older Or Non-Standard Browsers
Since crawler rendering engines don't always match the latest consumer browser capabilities exactly, feature-detection-based progressive enhancement helps ensure core content remains accessible to crawlers as well as real users.
Best Practices
Always Prefer Feature Detection Over Browser/User-Agent Sniffing For Compatibility Decisions
It's inherently more accurate (checking the actual capability rather than inferring it from an unreliable proxy) and requires zero ongoing maintenance as the browser landscape evolves.
Use CSS's Native @supports For Styling-Layer Feature Detection Rather Than JavaScript-Based Style Toggling
It keeps the detection logic in CSS where it belongs, avoiding unnecessary JavaScript execution and a flash of incorrectly-styled content while JS loads and runs.
Frequent Bugs
A feature works in Chrome during testing but the browser-sniffing logic incorrectly treats a new Chromium-based browser as unsupported.
Replace user agent string matching with direct feature detection, checking for the actual capability rather than inferring support from browser identity.
A CSS layout looks broken in a browser lacking support for a newer CSS property, with no fallback applied.
Wrap the modern CSS in an @supports block with a corresponding @supports not fallback for browsers lacking that specific capability.
Real-World Examples
Combined JS And CSS Feature Detection
A component using both JavaScript and CSS feature detection together for a fully progressively-enhanced experience.
// JS: detect API support directly
if (window.IntersectionObserver) {
observeLazyImages();
}
/* CSS: detect property support directly */
@supports (aspect-ratio: 1) {
img { aspect-ratio: attr(width) / attr(height); }
}