🚀 LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
🎓 COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.
HTML MASTER CLASS /// LEARN TAGS /// BUILD STRUCTURE /// SEMANTIC WEB /// HTML MASTER CLASS /// LEARN TAGS ///

Feature Detection: Asking Capability, Not Identity

Understand why browser sniffing via user agent strings is fragile and unreliable, how to detect JavaScript and HTML API support directly, and how CSS's native @supports at-rule provides the same detection capability for styling.

Total XP: 0|💻 html XP: 0

Skill Matrix

UNLOCK NODES BY LEARNING NEW TAGS.

Feature Detection

Capability over identity.


🚀 LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
🎓 COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.

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.

// Fragile: breaks silently as browsers change their UA strings
if (navigator.userAgent.includes('Safari')) { ... }
localhost:3000
⚠ Requires Ongoing MaintenanceUser agent string matching breaks as browsers evolve, requiring constant updates to stay accurate.

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.

// Future-proof: works for any browser implementing this API
if ('showPicker' in HTMLInputElement.prototype) {
  input.showPicker();
} else {
  input.focus(); // fallback
}
localhost:3000
✓ Accurate For Any Browser, Present Or FutureThe check remains correct regardless of which specific browser or version is running it.

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.

@supports (gap: 1rem) {
  .grid { gap: 1rem; }
}
@supports not (gap: 1rem) {
  .grid > * { margin: 0.5rem; }
}
localhost:3000
CSS-native detection:
@supports — no JavaScript required

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

ChromeSupported

Fully supported.

FirefoxSupported

Fully supported.

SafariSupported

Fully supported.

EdgeSupported

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

THE BUG

A feature works in Chrome during testing but the browser-sniffing logic incorrectly treats a new Chromium-based browser as unsupported.

THE FIX

Replace user agent string matching with direct feature detection, checking for the actual capability rather than inferring support from browser identity.

THE BUG

A CSS layout looks broken in a browser lacking support for a newer CSS property, with no fallback applied.

THE FIX

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); }
}

Interview Prep

?Frequently Asked Questions

Pascual Vila

Pascual Vila

Frontend Instructor // Code Syllabus

Common Pitfalls & Errors

The Error //

Using navigator.userAgent to infer feature support

if ('showPicker' in HTMLInputElement.prototype) { ... }

The Solution //

Check the actual capability directly instead of inferring it from browser identity.

The Error //

Shipping modern CSS with no @supports fallback for unsupported browsers

@supports not (gap: 1rem) { .grid > * { margin: 0.5rem; } }

The Solution //

Wrap modern CSS properties in @supports, with an explicit @supports not fallback where needed.

Lesson Glossary

[01]Feature Detection

Checking for a capability directly rather than browser identity.

Code Preview
'x' in object

[02]Browser Sniffing

Inferring capability from the user agent string (unreliable).

Code Preview
navigator.userAgent

[03]@supports

CSS's native at-rule for conditional feature-based styling.

Code Preview
@supports (prop: value)

[04]Progressive Enhancement

Layering capability-detected features on a working baseline.

Code Preview
Connects to Best Practices module

Continue Learning