Quick Summary: 2022 is shaping up to be a pretty great year for CSS, with a plethora of new features on the horizon. Some are already starting to land in browsers, others are likely to gain widespread browser support in 2022, while for one or two the process may be a little longer. In this article we’ll take a look at a few of them.
Container queries enable us to style an element depending on the size of its parent — a crucial difference from media queries, which only query the viewport. This has long been a problem for responsive design, as often we want a component to adapt to its context.
Think of a card which might be shown in a wide content area or a narrow sidebar. We’d probably want to show something more akin to the card’s mobile layout in the sidebar, while perhaps showing style when there is sufficient horizontal space. But media queries aren’t aware of the component’s context. For this reason, container queries have been on many a developer’s wish list for some time.
For a container query, we need to specify an element as our container, using the container
property (shorthand for container-type
and container-name
). The container-type
can be width
, height
, inline-size
or block-size
. inline-size
and block-size
are logical properties, which may produce different results according to the document’s writing mode.
main, aside {
container: inline-size;
}
Then we can use the @container
at-rule in a way that’s similar to a media query. Note the different way the rule can be expressed within the brackets (inline-size > 30em
rather than min-width: 30em
). This is part of the Media Queries Level 4 specification. For the card layout example above, when the container is wider than 30rem we switch to a horizontal layout using flexbox:
@container (inline-size > 30em) {
.card {
display: flex;
}
}
The CSS Containment Level 3 specification is currently in working draft, which means the syntax could change at any point — in fact, it’s changed since some articles on container queries were published on it last year. The examples here are in line with the proposed syntax at the time of writing.
Chrome claims to support container queries behind a flag, but the working implementation doesn’t appear to be consistent with the current spec. There’s a polyfill, but it doesn’t work with the latest syntax. So the short answer is “no”, I would definitely urge you to wait a while before using them in production. But there’s a lot of momentum behind container queries, so I would expect more general support soon.
:has()
#Often known as the “parent selector”, this pseudo-class enables us to select an element depending on its descendants. As Bramus Van Damme wrote last year, it has some pretty interesting use cases beyond that. For instance, we could style an image differently in a <figure>
depending on whether or not it’s accompanied by a <figcaption>
. Or we could target labels in a form that are followed by invalid inputs. The possibilities are endless.
To style <section>
elements that contain an <h2>
:
section:has(h2) {
background: lightgray;
}
To style an <img>
, only if its parent <section>
also contains an <h2>
:
section:has(h2) img {
border: 5px solid lime;
}
No mainstream browser support yet, but you can play with it to your heart’s content in Safari Technology Preview. Check out this demo in supporting browsers.
@when/@else
#An at-rule for conditionals in CSS, similar to if/else logic in other programming languages. It could make writing complex media queries far more logical, for example. @when
was chosen instead of @if
to avoid conflict with Sass.
We can query for multiple media conditions or supported features, such as whether a user’s viewport is over a certain width and their browser supports subgrid. When using @when/@else
, we drop the @
from the query rule:
@when media(min-width: 30em) and supports(display: subgrid) {
/* Styles for viewports over 30em, where the browser also supports subgrid */
} @else {
/* Styles for browsers that do not meet the condition */
}
Not yet. It’s very early days, and still under discussion. I wouldn’t expect browser support to be widely rolled out this year, but it’s definitely one to watch.
accent-color
#The accent-color
property makes it quick and easy to roll out our brand colors to certain form inputs by leveraging user agent styles. Think checkboxes, radio buttons, range inputs and progress bars. Historically, these are kind of a pain to style, and all browsers render them slightly differently. As developers the go-to option, more often than not, is hiding the default input and rolling our own using pseudo-elements. accent-color
enables us to keep the browser’s default input, but apply a color to fit with our brand.
Usage is simple, and the property is inherited, so you can set it at the root level to apply it everywhere:
:root {
accent-color: lime;
}
Or on individual elements:
form {
accent-color: lime;
}
input[type="checkbox"] {
accent-color: hotpink;
}
CAN I USE IT? #
Yes! accent-color
is supported in Chrome, Edge, Firefox and Safari Technology Preview. Browsers that don’t support it will simply get the default colors, and the inputs will remain perfectly usable — great for progressive enhancement.
accent-color
#The accent-color
property makes it quick and easy to roll out our brand colors to certain form inputs by leveraging user agent styles. Think checkboxes, radio buttons, range inputs and progress bars. Historically, these are kind of a pain to style, and all browsers render them slightly differently. As developers the go-to option, more often than not, is hiding the default input and rolling our own using pseudo-elements. accent-color
enables us to keep the browser’s default input, but apply a color to fit with our brand.
Usage is simple, and the property is inherited, so you can set it at the root level to apply it everywhere:
:root {
accent-color: lime;
}
Or on individual elements:
form {
accent-color: lime;
}
input[type="checkbox"] {
accent-color: hotpink;
}
CAN I USE IT? #
Yes! accent-color
is supported in Chrome, Edge, Firefox and Safari Technology Preview. Browsers that don’t support it will simply get the default colors, and the inputs will remain perfectly usable — great for progressive enhancement.
You might already be familiar with Hex, RGB and HSL color formats. The CSS Color Module Levels 4 and 5 include a whole host of new color functions that enable us to specify and manipulate colors in CSS like never before. They include:
hwb()
: Hue, Whiteness, Blackness.lab()
: Lightness, along with a and b values, which determine the hue.lch()
: Lightness, Chroma, Hue.color-mix()
: Mix two colors together.color-contrast()
: From a list of colors, output the one with the highest contrast compared to the first argument.color()
: Specify a color in a different color space (e.g.display-p3
).There’s a lot to dig into this illuminating subject — I wrote an article all about it last year. Added to that, there’s also relative color syntax, which lets us take a color and tweak it to make another.
hwb()
, lab()
and lch()
can be used much in the same way as the rgb()
and hsl()
functions we’re accustomed to, with an optional alpha parameter:
.my-element {
background-color: lch(80% 100 50); // opaque color
}
.my-element {
background-color: lch(80% 100 50 / 0.5); // color with 50% transparency
}
color-mix()
outputs a color as a result of mixing two others. We need to specify a color interpolation method as the first argument:
.my-element {
background-color: color-mix(in lch, blue, lime);
}
color-contrast()
requires a base color with which to compare the others. It will output the color with the highest contrast, or in the case where an additional keyword is provided, the first color in the list that meets the corresponding contrast ratio:
/* Output the color with the highest contrast */
.my-element {
color: white;
background-color: color-contrast(white vs, lightblue, lime, blue);
}
/* Output the first color that meets AA contrast ratio */
.my-element {
color: white;
background-color: color-contrast(white vs, lightblue, lime, blue to AA);
}
This is great for accessible color schemes. For example, we can let our CSS select whether black or white text is most suitable (i.e. provides the most contrast) for a button with a given background color.
Safari is leading the way on browser support right now, with hwb()
, lch()
, lab()
, and color()
all supported since version 15. color-mix()
and color-contrast()
can be enabled with a flag. Firefox supports hwb()
, and also has flagged support for color-mix()
and color-contrast()
. The surprising outlier is Chrome, which doesn’t support any of these right now. However, it’s not too hard to provide fallbacks in your code: Given two color rules, the browser will ignore the second one if it doesn’t support it.
.my-element {
background-color: rgb(84.08% 0% 77.36%);
background-color: lch(50% 100 331);
}
It means that when support does come in, your code will be ready.
Source: Smashing Magazine