Conditional Rules in CSS?

CSS conditional rules? It's well known that web technologies are evolving over time, we are almost not surprised about the new features coming to our technologies no matter how unbelievable they seem to be. We are in the magic era.
Often times we have been worried about how to create a fallback solution for some specific sets of CSS rules.
As a developer, you might have thought that making an if...else
cases in CSS will be a good idea, isn't it? But CSS is a stylesheet language, and adding such a procedure would be nothing better than weird.
Property Value Fallback
Firstly, let's talk about writing a fallback if a specific CSS property value is not supported.
Let's look at these two scenarios.
.color-red {
background-color: blue;
background-color: red;
}
As you know, the final property for background-color
is red
because in CSS specificity, the browser uses the last read supported value. Let's look at the second scenario:
When you write an unsupported property value in CSS, the browser ignores and uses the last known supported one.
In this case, the browser first sees background-color: red;
which it understands, and then sees background-color: asdf;
which does make a color sense even to humans, and ignores it. In this sense, a fallback value can be defined in CSS thus:
.color-red {
background: url('transparent-red.png') no-repeat;
background: rgba(255, 0, 0, .5);
}
The more the browser keeps understanding the next values of a property, it interprets it, else, it sticks to the last value understood.
In the CSS rule above, if the browser is new enough to understand the rgba()
it interprets this, instead, sticks to the url()
function to fetch the background image, which is new enough for any old browser in town, in 2021.
Just recently (In CSS Level 4), the rgb()
is slightly modified to now have the same capability as rgba()
function and also allows the whitespace syntax. We can check for this compatibility like this:
.color-red {
background: rgba(255, 0, 0, .5);
background: rgb(255, 0, 0, .5);
}
Checking for the whitespace syntax:
.color-red {
background: rgb(255, 0, 0, .4);
background: rgb(255 0 0 / 50%);
}
The code above will pick background: rgb(255 0 0 / 50%);
if the browser supports the whitespace syntax.
All the above codes are based on creating a fallback value for one specific CSS property, it doesn't provide a way to define sets of properties and values to be used when a particular property is not supported by a browser.
The @supports Property
The @supports
is a feature query that solves the problem. This query receives some declarations to determine whether the browser supports or not, one or more specific CSS features. Added in CSS Conditional Rules Module LevelĀ 3.
Syntax
@supports (declaration) {
/* CSS rules here */
}
Let's put this to code
@supports (background: rgb(255 0 0 / 50%)) {
.grid {
background: rgb(255 0 0 / 50%);
}
}
The selector() function
The @support
s query also comes with a function syntax. We only have the selector()
as the time of this writing, which was added in CSS Conditional Rules Module Level 4.
The selector()
function allows you to check for browser support for specific CSS selectors. This should not be directly used on selectors, you can just specify the two operands and A
and B
.
For example, to check if a browser supports the adjacent sibling combinator, we can use the following query:
@supports selector(A + B) {
/* CSS rules to execute if the browser supports adjacent child combinator */
ul + ol {
border-bottom: dashed 1px red;
}
}
Check for more than one condition?
Let's try to check if the browser supports checking a specific declaration and another specific declaration.
We can intrinsically achieve this in this way:
@supports (display: table) {
@supports(display: table-header) {
// Haven't tested this out though.
.table-display {
display: table;
}
.table-display h3 {
display: table-header;
}
}
}
This looks good and also readable, but what happens to it if we have more than two nested feature queries?
You can combine declarations with conjunctions(and
) , disjunctions(or
) , negations (not
) and just as in a normal programming language, precedence can be defined with parenthesis ()
.
Let's rewrite the code above
@supports (display: tabel) and (display: table-header) {
.table-display {
display: table;
}
.table-display h3 {
display: table-header;
}
}
}
More examples on conjunctions and disjunctions, preceding the order with parenthesis.
@supports not (display: grid) and ((display: flex)) {
// CSS applied if display:grid is not supported but display:flex is.
.flexbox {
display: flex;
}
.flexbox div {
flex: 1;
}
}
If...else Conditions?
The @supports
feature does not implement if..else
conditions but we can achieve this with the not
negation.
@supports(display: grid) {
.parent {
display: grid;
gap: 20px;
grid-column-templates: repeat(3, 1fr);
height: 200px;
}
} @supports not (display: grid) {
.parent {
display: block;
}
.parent .child {
margin-right: 20px;
width: 33.33%;
height: 200px;
float: left;
}
.parent .child:last-child {
margin-right: 0;
}
}
The first rule of codes executes if our browser supports display: grid
It sets repeated grid columns of three equal widths and height of 200px;
The same thing can be achieved with some of couple of CSS properties if the browser does not support the declaration display: grid
.
JavaScript API
Conditional rules in CSS also comes with a JavaScript API that lets you programmatically check for the browser's feature support using the CSS.supports()
method. It takes two parameters propertyName
and value
or just one parameter supportCondition
.
Syntax
CSS.supports(propertyName, value);
CSS.supports(supportCondition);
This method returns true
if the browser supports the declaration, else false
. Let's look at an example:
if(CSS.supports('display', 'grid')) {
// JavaScript to be executed if browser supports the display:grid declaration
}
Check if the browser does not support the display:grid
declaration. As discussed, with can use the not
negation in our CSS to check this. We can also negate the condition in our JavaScript to check the same:
if(!CSS.supports('display', 'grid')) {
// JavaScript to be executed if browser supports the display:grid declaration
}
Real-Life Examples
Let's put @supports
into use by creating some real-life examples with it.
This example will:
- Checks if the browser supports the
-webkit-line-clamp: 3
,display:-webkit-box
and-webkit-box-orient: vertical
declarations, if true:- Set
-webkit-line-clamp
to3
. - Set
display
to-webkit-box
. - Set
-webkit-box-orient
tovertical
. - Display a message in the
::after
that indicates that the browser supports-webkit-line-clamp: 3
.
- Set
- If not true:
- Check if the browser supports the
text-overflow: ellipsis
property, if true:- Set overflow to hidden.
- Set
text-overflow
toellipsis
white-space
tonowrap
- Display a message in the
::after
that indicates that the browser does not support-webkit-line-clamp: 3
but supportstext-overflow: ellipsis
.
- if not true:
- Set
display
toblock
.
- Set overflow to hidden.
- Set height to
100px
- Display a message in the
::after
that indicates that the browser does not support-webkit-line-clamp: 3
andtext-overflow: ellipsis
.
- Set
- Check if the browser supports the
We have made a live demo for this:
Conclusion
The CSS conditional rules are a neat way to make better design decisions in just CSS. I see this as something cool enough to make quick decisions that are meant to be made only with JavaScript before the @supports
feature. Another brilliant use case is to determine the type of browser that is being used and display a message like "You are on Firefox" or "You are using Google Chrome or a Chromium-based browser". Cool right? What is the first hack that comes into your mind this mind-blowing feature? Please share your thoughts in the comment session below.
Comments (0)