CSS Conditions Today
Reiterating on my idea for CSS conditions
I found a new way for creating such conditions using existing CSS features.
You probably know Roman Komarov’s article “Conditions for CSS Variables”
where he describes how you can create binary conditions
for properties that support calc()
.
This was a great inspiration and together with a CSS trick
I learned from Lea Verou called “Static Interpolation”
I was able to create CSS conditions that are similar to media queries
and support (nearly) all CSS properties.
Binary Conditions
First, lets take look at an example of a binary condition:
:root {
--is-fancy: 0;
}
.is-fancy {
--is-fancy: 1;
}
.component {
font-family: Arial;
animation: 1s component-is-fancy paused;
animation-delay: calc((1 - var(--is-fancy)) * 1s);
}
@keyframes component-is-fancy {
from {
font-family: Comic Sans MS;
}
}
Here every .component
that is somewhere inside an .is-fancy
element
gets a different font-family applied.
This works because if --is-fancy
is 0
the animation delay gets set to 1s
and no animation will be applied,
but if the variable is set to 1
the delay gets set to 0s
and therefore the animation takes effect.
By using the paused
play state the animation will never actually animate.
This technique can be applied to all properties
that can be used inside a @keyframes
animation
(which seems to differ between browsers).
Media Query Like Conditions
Now, lets say we have a --width
variable
that tells our component how much space is available.
We could then create conditions
that work like (min-width)
media queries:
.component {
animation: 10000s step-end component paused;
animation-delay: calc((0 - var(--width)) * 1s);
}
@keyframes component {
/* (min-width: 400px) */ 4% {
font-size: 20px;
}
/* (min-width: 650px) */ 6.5% {
text-align: center;
}
}
Here we use a negative delay between 0s
and -10000s
to control at which point in the animation we want to start.
One second is corresponding to one pixel in this case,
so the 4%
step in the animation gets applied
only if --width
is 400
or greater.
Did we just invent Container Queries in plain CSS?
Well, sort of.
The big thing that’s missing for calling it a container query
is where the value for --width
should come from.
One way would be to start at the html
element with --width: 100vw;
and let every layout element update the value for its children.
Like --width: calc(parent-var(--width) / 2);
for a 50%
container.
But since we need a unit-less number for our animation delay
and calc(100vw / 1px)
is invalid in CSS
we have to use a bunch of media queries
that set the initial value of --width
for us:
@media (width: 1px) { :root { --width: 1; } }
@media (width: 2px) { :root { --width: 2; } }
@media (width: 3px) { :root { --width: 3; } }
/* … and thousands more … */
Sadly parent-var()
isn’t a thing yet in CSS,
so layout elements would need an extra <div>
to achieve the same functionality:
<div class="layout-element">
<div class="inherit-vars">
…
</div>
</div>
.layout-element {
width: 50%;
--set-width: calc(var(--width) / 2);
}
.inherit-vars {
--width: var(--set-width);
}
You can take a look at the following example
that shows how this works for a simple component
that is styled based on the context it was placed in:
codepen.io/ausi/pen/rPBNwJ
More ideas on how to use CSS conditions as container queries
can be found in my previous article.
Should we use this in production?
I would say it depends.
Using thousands of media queries to set a CSS variable
is probably one of the parts that shouldn’t go in production.
But depending on the project
there might be simpler ways to set the --width
variable.
Another caveat to be aware of is that the properties
that can be used inside @keyframes
seem to vary a lot between browsers.
Why isn’t this a native feature of CSS yet?
I proposed a native variation of this about two years ago to the WICG but it didn’t get much traction. Maybe this technique of “faking” CSS conditions can finally push the topic forward as it shows that browsers are already able to handle them. If you like it, please spread the word so that browser vendors can become aware of how great CSS conditions would be for us web developers.