20 — Browser Compatibility: Prefixes, @supports & Progressive Enhancement
Vendor prefixes are mostly obsolete. The production approach: Autoprefixer (driven by browserslist) adds the few remaining prefixes; @supports for feature detection; fallbacks before new properties. Safari (WebKit) is the laggard — test it specifically.
Vendor Prefixes — let tooling handle them
json
{
"browserslist": ["last 2 versions", "> 1%", "not dead"]
}
css
/* Don't hand-write prefixes. Autoprefixer reads browserslist and adds only what's needed. */
/* The few properties still needing -webkit- for Safari (2024): */
.glass {
-webkit-backdrop-filter: blur(10px); /* Safari */
backdrop-filter: blur(10px); /* standard */
}
.gradient-text {
-webkit-background-clip: text; /* Safari */
background-clip: text;
-webkit-text-fill-color: transparent; /* Safari */
color: transparent;
}
@supports — feature detection (not UA sniffing)
css
/* Fallback for ALL browsers (including those without @support) */
.card { display: flex; flex-direction: column; }
/* Enhanced if grid is supported. IE doesn't support @supports → gets the fallback. */
@supports (display: grid) {
.card { display: grid; grid-template-columns: 1fr 2fr; }
}
/* Negation: browsers WITHOUT the feature */
@supports not (display: grid) { .card { display: block; } }
/* Selector support detection */
@supports selector(:has(> *)) { .card:has(img) { padding-block-start: 0; } }
/* Combine with and/or */
@supports (display: grid) and (gap: 1rem) { .grid { display: grid; gap: 1rem; } }
Property Fallbacks — fallback BEFORE the new property
css
.box {
width: 300px; /* fallback — applies if the next line is unsupported */
display: block; /* fallback */
display: grid; /* enhanced — if unsupported, ignored, fallback stays */
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
}
/* The cascade: the last SUPPORTED value wins. Unsupported values are ignored, not errors. */
The Safari Laggard Trap
Anti-pattern: missing -webkit- prefix breaks Safari
css
/* ❌ backdrop-filter without -webkit- → Safari (versions needing the prefix) shows no blur. */
.glass { background: rgba(255,255,255,0.2); backdrop-filter: blur(10px); }
css
/* ✓ Include -webkit- (before standard, so the standard wins when supported). Or use Autoprefixer. */
.glass { background: rgba(255,255,255,0.2); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); }
text
Safari is often the laggard for newer CSS:
:has() → Safari 15.4 (Chrome 105)
container queries → Safari 16 (Chrome 105)
subgrid → Safari 16 (Chrome 117)
backdrop-filter → needs -webkit- in older Safari
background-clip:text → needs -webkit- in Safari
Always check Safari support specifically on caniuse.com.
💡 Tips & Tricks
- Idiom: Autoprefixer with
browserslist(not hand-written prefixes) — configure your target (last 2 versions, > 1%, not dead) and let it add/remove prefixes. Hand-writing is error-prone and leaves obsolete ones. - Idiom:
@supportsfor progressive enhancement — fallback for all, enhanced if supported. Better than UA sniffing (fragile). IE doesn't support@supports→ gets the fallback (outside@supports). - Idiom: fallbacks before new properties —
width: 300px; display: grid;. Ifgridis unsupported, the browser ignores it and uses the earlier value. The cascade's "last supported value wins" handles fallbacks. - Idiom: check caniuse.com before using a newer feature — shows support across browsers with version numbers and known issues.
- Idiom: test in Safari (WebKit) — Chrome (Blink) and Safari (WebKit) differ. Safari is the laggard for newer CSS. Test both for cross-engine correctness.
⚠️ Edge Cases & Gotchas
- Prefixes are mostly obsolete: don't add
-webkit-/-moz-to everything — it clutters and some prefixed versions have bugs. Use Autoprefixer with a currentbrowserslist. @supportsisn't supported in IE: IE gets the CSS outside@supports(the fallback), and the@supports (display: grid)block is ignored — usually what you want.- Prefixed and unprefixed can differ:
-webkit-background-clip: textandbackground-clip: textcan have slightly different behavior in older WebKit. Test both. - Feature detection isn't bug detection:
@supports (gap: 1rem)checks if the browser claims support, not if it works correctly. Some features have partial/buggy support (gap in flexbox was buggy in early Chrome). - Forking by
@supportscan bloat CSS: too many@supportsbranches make the CSS large. Use for major enhancements (grid vs flex), not every property. browserslistaffects Autoprefixer output:last 2 versionsadds few prefixes;> 1%adds more for popular older browsers. Choose your target realistically.
🧠 Spot the Bug
css
.glass {
background: rgba(255, 255, 255, 0.2);
backdrop-filter: blur(10px);
}
Answer
Safari (older versions, and some current contexts) requires -webkit-backdrop-filter. Without it, Safari ignores the unprefixed backdrop-filter → no blur, just a translucent panel. Fix: include the -webkit- prefix before the standard (so the standard wins when supported), or use Autoprefixer with a browserslist that includes Safari. Some features (backdrop-filter, background-clip: text, mask) still need -webkit- in Safari even today.