CSS @supports
In this page:
@supports (property: value) {
selector {
property: value;
}
}
Basic @supports Syntax
@supports wraps a block of CSS rules in a condition that tests whether the browser can parse and apply a given property-value pair, only applying the enclosed rules if the test passes. The condition itself looks like a real declaration inside parentheses.
- Accepted values:
- @supports (property: value) — tests a declaration
- @supports not (...) — negates the test
- @supports (...) and (...) — both must match
- @supports (...) or (...) — either matches
- @supports selector(...) — tests selector support
Example: Basic @supports Syntax
<style>
.cell { background: #cfe8ff; border: 2px solid #1e6fd9; padding: 10px; }
@supports (display: grid) {
.container {
display: grid;
}
}
</style>
<div class="container"><div class="cell">A</div><div class="cell">B</div><div class="cell">C</div></div>
Combining Conditions with and/or/not
Multiple feature tests can be combined with and (all must pass), or (any must pass), and not (negates a single test), letting a feature query express fairly precise support requirements in one rule.
- Accepted values:
- and — every condition must be supported
- or — at least one must be supported
- not — negates one condition
- ( ) — parentheses are required around each condition
- mixing and and or — needs extra parentheses
Example: Combining Conditions with and/or/not
<style>
p { background: #cfe8ff; border: 2px solid #1e6fd9; margin: 0; padding: 8px; }
@supports (display: grid) and (gap: 1rem) {
.container {
display: grid;
gap: 1rem;
}
}
</style>
<div class="container"><p>Grid with gap</p><p>Grid with gap</p></div>
The not Operator
Prefixing a condition with not applies the enclosed rules only when the feature is NOT supported, which is the natural way to write a true fallback path for genuinely old browsers.
- Accepted values:
- not (property: value) — matches when unsupported
- not (A) and (B) — invalid; wrap as not ((A) and (B))
- @supports not (display: grid) — fallback styles
- note: the not operand must be wrapped in parentheses
Example: The not Operator
<style>
.container { background: #cfe8ff; border: 2px solid #1e6fd9; padding: 10px; }
@supports not (display: grid) {
.container {
display: block;
}
}
</style>
<div class="container">Shown as block where grid is unsupported</div>
Progressive Enhancement Use Case
The standard pattern is to write baseline CSS that works everywhere first, then layer @supports blocks on top to opt modern browsers into enhanced layouts or effects -- rather than writing modern-only CSS and trying to patch old browsers afterward.
- Accepted values:
- default declarations first — the fallback
- @supports (display: grid) { ... } — enhanced styles
- @supports (gap: 1rem) — feature-test individual properties
- later @supports — override the fallback
Example: Progressive Enhancement Use Case
<style>
.cell { background: #cfe8ff; border: 2px solid #1e6fd9; padding: 10px; }
.container {
display: block;
}
@supports (display: flex) {
.container {
display: flex;
}
}
</style>
<div class="container"><span class="cell">A</span><span class="cell">B</span></div>
Testing Selector Support
@supports selector(...) tests whether the browser understands a given CSS selector syntax (not just a property), useful for newer selectors like :has() that have uneven adoption.
- Accepted values:
- @supports selector(:has(a)) — tests :has() support
- @supports selector(:focus-visible) — tests :focus-visible
- selector(<selector>) — any single complex selector
- not selector(...) — negation is allowed
Example: Testing Selector Support
<style>
.card { background: #cfe8ff; border: 2px solid #1e6fd9; padding: 12px; margin-bottom: 8px; width: 200px; }
@supports selector(:has(a)) {
.card:has(a) {
cursor: pointer;
}
}
</style>
<div class="card"><a href="#">Card with a link</a></div>
<div class="card">Card without a link</div>
- Forgetting the parentheses around the condition, as in
@supports display: grid, which is invalid. - Forgetting the parentheses around the declaration, as in
@supports display: grid, when it must be@supports (display: grid). - Putting the fallback style after the
@supportsblock, where it overrides the modern style.
Supported in all modern browsers: Chrome, Firefox, Safari, Edge and Opera.
Chapter Quiz — Complete all 25 topics to unlock
0/25 topics done
Complete these topics first:
- CSS Container Queries
- CSS Subgrid
- CSS Logical Properties
- CSS Logical Sizing
- CSS Writing Modes
- CSS Aspect Ratio
- CSS Object Fit
- CSS object-position
- CSS Masking
- CSS Math Functions
- CSS Motion Path
- CSS @supports
- CSS @property
- CSS At-Rules
- CSS Cursor
- CSS Will Change
- CSS User Interface
- CSS Print Styles
- CSS Pagination (Print)
- CSS Dark Mode
- CSS Accessibility
- CSS Performance
- CSS Preprocessors
- CSS Frameworks Overview
- CSS Interview Prep