Live, in-browser detection of modern CSS support for selectors, features, and at-rules. Applies support-based classes, exposes a results object, and allows custom tests.
Inspired by the legacy of Modernizr, this script evaluates a user's browser for cutting-edge modern CSS support beyond the capabilities of @supports.
Classes are added to <html> as either supports-[feature] or no-[feature], allowing easier progressive enhancement and build strategies
Checks for selectors like :has(), properties like text-box-trim, features like relative color syntax, and at-rules like @layer - see full test suite
Allows adding custom tests
Exposes a results object to iterate over detected support, as well as individual results for quick conditional checks in JS
When To Use SupportsCSS
While @supports exists to detect support in CSS itself, it notably doesn't (yet) cover at-rules, such as @container or @layer. Also, @supports cannot reliably test for partial implementations. Additionally, the use of classes simplifies creating selectors.
Plus the support classes eliminate the need to guess and test for the right selector combination to use within an @supports block. You might also enjoy the results collection created for easy-access in your JavaScript.
As Progressive Enhancement
Since the classes rely on JavaScript loading and succeeding, you will want to treat any styles based on the support classes as progressive enhancements. This is not too different than including @supports in your styles directly.
However, if you have more critical styles and you do expect that most of your audience will have support, consider using a regular @supports block in your stylesheets. Then the styles are available as soon as your stylesheet is loaded.
Be sure to also consider if you need feature detection. Many of the modern CSS features are "nice to haves" when they work, but are also ok to fail or use a simple fallback.
You can copy any of the tests from the SupportsCSS test suite that use CSS.supports and use those within @supports.
Features classes are added to <html> and can be used within your stylesheets to modify selectors. They are also the keys to include in the tests array.
Supported: .supports-[feature]
Unsupported: .no-[feature]
Global names are the keys to access results directly for conditional checks in JavaScript, such as SupportsCSSTests.ContainerUnits, which return a boolean.
The test conditions use a combination of CSS API features exposed on the window (at-rules and a few others) and the CSS.supports function.
CSS.supports('selector(:has(+ *))') (Possible false positive in Firefox 112)
houdini-paint-api
HoudiniPaintApi
window.CSS.paintWorklet
individual-transforms
IndividualTransforms
CSS.supports('transform: scale(1)')
light-dark
LightDark
CSS.supports('color: light-dark(black, white)')
logical-properties
LogicalProperties
CSS.supports('border-start-start-radius: 1px')
media-range-syntax
MediaRangeSyntax
window.matchMedia('(width >= 1px)')
nesting
Nesting
CSS.supports('selector(& a)')
nth-of-s
NthOfS
CSS.supports('selector(:nth-child(1 of .a))')
overscroll-behavior
OverscrollBehavior
CSS.supports('overscroll-behavior: none')
relative-color-syntax
RelativeColorSyntax
CSS.supports('color: rgb(from red r g b / 1%)')
scroll-timeline
ScrollTimeline
CSS.supports('scroll-timeline-name: --a')
subgrid
Subgrid
CSS.supports('grid-template-rows: subgrid')
text-box-trim
TextBoxTrim
CSS.supports('text-box-trim: both')
trigonometry
Trigonometry
CSS.supports('width: calc(1px * cos(1deg))')
user-invalid
UserInvalid
CSS.supports('selector(:user-invalid)')
user-valid
UserValid
CSS.supports('selector(:user-valid)')
view-timeline
ViewTimeline
CSS.supports('view-timeline-name: --a'),
view-transitions
ViewTransitions
window.ViewTransition
AtContainerStyleProperties Test
Support for container size queries was available prior to the availability of container style queries. And style queries are presently limited to work with only custom property values. Consequently, detecting for window.CSSContainerRule does not cover availability of style queries.
To evaluate the availability of container style queries, an SVG is temporarily created and destroyed in order to provide an isolated test environment without side effects.
The following styles are tested, and if the correct value for top is returned, then container style queries are considered supported.
The testEnv() function is exported for you to use in your own tests if you encounter another scenario that cannot be accurately assessed through the current CSS API.
How were these features selected?
Features were selected based on:
@supports limitations
instability of the spec
freshness to the language
impact on CSS architecture
impact on progressive enhancement
Installation
Important - When using a CDN, be sure to version-lock since future releases may remove or modify tests as the specs and browser support stabilizes.
The init function does a check for window before attempting the tests.
Host on your server
Grab a copy from the /dist/ folder as appropriate for your environment.
bundle.min.js - for use via a browser script include
bundle.js - for use as a module
Options
The following can be passed to the init() function:
tests - required array of feature class names that indicate which tests to perform, ex. ['nth-of-s', 'scroll-timeline'], or pass 'all' to include the whole test suite
supportsPrefix - pass a string to customize the prefix for supported features, or false to remove the prefix
unsupportedClasses - pass false to skip adding classes for unsupported features
Example initialization with options:
const tests =["nth-of-s","scroll-timeline"];// Or, test the whole suite with tests: 'all'
SupportsCSS.init({ tests,unsupportedClasses:false,supportsPrefix:"css"});
Usage
After install and initialization, SupportsCSSTests will be available for global access in client-side scripts. Review the test suite for a list of all features tested.
Get all results
An object of all test results is available as SupportsCSSTests.results.
const resultsList = document.createDocumentFragment();const list = document.createElement("ol");
resultsList.appendChild(list);for(const name in SupportsCSSTests.results){const li = document.createElement("li");const result = SupportsCSSTests.results[name];
li.textContent =`${name}: ${result ?"✅":"❌"}`;
list.appendChild(li);}
document.body.appendChild(resultsList);
JavaScript conditional checks
Access results directly via the "global name", such as SupportsCSSTests.AtContainerStyleProperties.
Example JS conditional
if(SupportsCSS.AtContainerStyleProperties){// Container style queries with custom properties are supported}
Add a custom test
Custom tests can be added by choosing a name and creating a test condition that will return a boolean. Add as many as you like using SupportsCSS.addTest().
Custom tests allow overriding the choices for supportsPrefix (3rd argument) and
unsupportedClasses (4th argument) made during intialization.
Use with caution: testEnv()
The testEnv() function is also available for testing that requires an isolated environment due to lack of sufficient exposure via the CSS API. An example is described in the section about the container style queries test.
This should really only be used when absolutely necessary, meaning there is not another readily-available, reliable method. For most selectors, properties, values, and functions, you can likely devise a test that uses the CSS.supports function.
Use of testEnv() requires the following arguments, in order:
styleBlock - a string containing the style block (rules) to use for the test
el - the DOM element to create to test against, ex. p
prop - the property to assess with getPropertyValue
value - the exact value that should be returned for the prop