2022, A Great Year for CSS! Video by Google

DeluxeNamesDeluxeNames AdminAdministrator
edited October 2022 in Coding Languages

The year 2022 is set to be one of CSS's greatest years, in both features and cooperative browser feature releases, with a collaborative goal to implement 14 features!

Here's a link to watch the State of CSS from Google I/O '22:

Overview #
This post is the article form of the talk given at Google IO 2022. It's not meant to be an in-depth guide on each feature, rather an introduction and brief overview to pique your interest, providing breadth instead of depth. If your interest is piqued, check the end of a section for resource links to more information.

Table of contents #
Use the list bel

Fresh in 2022 2022 and beyond
2022 Browser compatibility @scope
@layer @nest
subgrid @media (prefers-reduced-data)
@container @custom-media
hwb() Media query ranges
lch, oklch, lab, oklab, display-p3, etc @property
color-mix() scroll-start
color-contrast() :snap-target
Relative color syntax snapChanging() and snapChanged()
Gradient color spaces toggle()
accent-color anchor()
Color fonts v1
Viewport unit variants
Browser compatibility #
A primary reason so many CSS features are set to cooperatively release is due to the efforts of Interop 2022. Before studying the Interop efforts, it's important to look at Compat 2021’s efforts.

Compat 2021 #
The goals for 2021, driven by developer feedback via surveys, were to stabilize current features, improve the test suite and increase passing scores of browsers for five features:

sticky positioning
aspect-ratio sizing
flex layout
grid layout
transform positioning and animation
Test scores were raised across the board, demonstrating upgraded stability and reliability. Big congratulations to the teams here!

Interop 2022 #
This year, browsers met together to discuss the features and priorities they intended to work on, uniting their efforts. They planned to deliver the following web features for developers:

Color spaces and functions

Form compatibility
Viewport units
Web compat
This is an exciting and ambitious list that I can't wait to see unfold.

Fresh for 2022 #
Unsurprisingly, the state of CSS 2022 is dramatically impacted by the Interop 2022 work.

Before @layer, the discovered order of loaded stylesheets was very important, as styles loaded last can overwrite previously loaded styles. This led to meticulously managed entry stylesheets, where developers needed to load less important styles first and more important styles later. Entire methodologies exist to assist developers in managing this importance, such as ITCSS.

With @layer, the entry file can pre-define layers, and their order, ahead of time. Then, as styles load, are loaded or defined, they can be placed within a layer, allowing a preservation of style override importance but without the meticulously managed loading orchestration.

The video shows how the defined cascade layers allow for a more liberated and freestyle authoring and loading process, while still maintaining the cascade as needed.

Chrome DevTools is helpful for visualizing which styles are coming from which layers:

Before subgrid, a grid inside of another grid couldn't align itself to its parent cells or grid lines. Each grid layout was unique. Many designers place a single grid over their whole design and constantly align items within it, which couldn't be done in CSS.

After subgrid, a child of a grid can adopt its parents’ columns or rows as its own, and align itself or children to them!

In the following demo, the body element creates a classic grid of three columns: the middle column is called main, and the left and right columns name their lines fullbleed. Then, each element in the body,


nav> and

, adopts the named lines from body by setting grid-template-columns: subgrid.

​​body {
display: grid;
auto [main-start] min(90%, 60ch) [main-end] auto

body > * {
display: grid;
grid-template-columns: subgrid;
Lastly, children of


nav> or

can align or size themselves using the fullbleed and main columns and lines.

.main-content {
grid-column: main;

.fullbleed {
grid-column: fullbleed;

Devtools can help you see the lines and subgrids (Firefox only at the moment). In the following image, the parent grid and subgrids have been overlaid. It now resembles how designers were thinking about the layout.

Screenshot of a subgrid demo, using the Chrome Devtools grid overlay tooling to show the lines defined by CSS.
In the elements panel of devtools you can see which elements are grids and subgrids, which is very helpful for debugging or validating layout.

Screenshot of the Chrome Devtools Elements panel labelling which elements have grid or subgrid layouts.
Screenshot from Firefox Devtools
Resources #
Subgrid specification
Subgrid on MDN
Bramus: Practical CSS Subgrid Video Tutorials
Container queries #
Browser support:
Before @container, elements of a webpage could only respond to the size of the whole viewport. This is great for macro layouts, but for micro layouts, where their outer container isn't the whole viewport, it's impossible for the layout to adjust accordingly.

After @container, elements can respond to a parent container size or style! The only caveat is the containers must declare themselves as possible query targets, which is a small requirement for a large benefit.

/* establish a container */
.day {
container-type: inline-size;
container-name: calendar-day;
These styles are what make the Mon, Tues, Wed, Thurs, and Fri columns in the following video able to be queried by the event elements.

Demo by Una Kravets
Here is the CSS for querying the calendar-day container for its size, then adjusting a layout and font sizes:

@container calendar-day (max-width: 200px) {
.date {
display: block;

.date-num {
font-size: 2.5rem;
display: block;
Here's another example: one book component adapts itself to the space available in the column that it's dragged to:

Demo by Max Böck
Una is correct in assessing the situation as the new responsive. There are many exciting and meaningful design decisions to make when using @container.

Resources #
Container Queries specification
Container Queries explainer
Container Queries on MDN
The new responsive on web.dev
Calendar demo by Una
Awesome container queries collection
How we built Designcember on web.dev
Ahmad Shadeed: Say Hello To CSS Container Queries
accent-color #
Browser support:
Before accent-color, when you wanted a form with brand matching colors, you could end up with complex libraries or CSS solutions that became hard to manage over time. While they gave you all the options, and hopefully included accessibility, the choice to use the built-in components or adopt your own becomes tedious to continue to choose.

After accent-color, one line of CSS brings a brand color to the built-in components. In addition to a tint, the browser intelligently chooses proper contrasting colors for ancillary parts of the component and adapts to system color schemes (light or dark).

/* tint everything */
:root {
accent-color: hotpink;

/* tint one element */
progress {
accent-color: indigo;
Light and dark accented HTML elements side by side for comparison.
To learn more about accent-color, check out my post on web.dev where I explore many more aspects of this useful CSS property.

Resources #
accent-color specification
accent-color on MDN
accent-color on web.dev
Bramus: Tint User-Interface Controls with CSS accent-color
Color level 4 and 5 #
The web has been dominated by sRGB for the past decades, but in an expanding digital world of high-definition displays and mobile devices pre-equipped with OLED or QLED screens, sRGB is not enough. Furthermore, dynamic pages that adapt to user preferences are expected, and color management has been a growing concern for designers, design systems, and code maintainers.

Not in 2022 though—CSS has a number of new color functions and spaces:

Colors that reach into the HD color capabilities of displays.
Color spaces that match an intent, such as perceptual uniformity.
Color spaces for gradients that drastically change the interpolation outcomes.
Color functions to help you mix and contrast, and choose which space you do the work in.
Before all these color features, design systems needed to precalculate proper contrasting colors, and ensure appropriately vibrant palettes, all while preprocessors or JavaScript did the heavy lifting.

After all these color features, the browser and CSS can do all the work, dynamically and just in time. Instead of sending many KBs of CSS and JavaScript to users to enable theming and data visualization colors, CSS can do the orchestrating and calculations. CSS is also better equipped to check for support before usage or handle fallbacks gracefully.

@media (dynamic-range: high) {
.neon-pink {
--neon-glow: color(display-p3 1 0 1);

@supports (color: lab(0% 0 0)) {
.neon-pink {
--neon-glow: lab(150% 160 0);
hwb() #
Browser support:
HWB stands for hue, whiteness, and blackness. It presents itself as a human-friendly way of articulating color, as it's just a hue and an amount of white or black to lighten or darken. Artists who mix colors with white or black may find themselves appreciating this color syntax addition.

Using this color function results in colors from the sRGB color space, the same as HSL and RGB. In terms of newness for 2022, this doesn’t give you new colors, but it may make some tasks easier for fans of the syntax and mental model.

Resources #
HWB specification
Stefan Judis: hwb() – a color notation for humans?
Color spaces #
The way colors are represented is done with a color space. Each color space offers various features and trade-offs for working with color. Some may pack all the bright colors together; some may line them up first based on their lightness.

2022 CSS is set to offer 10 new color spaces, each with unique features to assist designers and developers in displaying, picking, and mixing colors. Previously, sRGB was the only option for working with color, but now CSS unlocks new potential and a new default color space, LCH.

Before color-mix(), developers and designers needed preprocessors like Sass to mix the colors before the browser saw them. Most color-mixing functions also didn't provide the option to specify which color space to do the mixing in, sometimes resulting in confusing results.

After color-mix(), developers and designers can mix colors in the browser, alongside all their other styles, without running build processes or including JavaScript. Additionally, they can specify which color space to do the mixing in, or use the default mixing color space of LCH.

Often, a brand color is used as a base and variants are created from it, such as lighter or darker colors for hover styles. Here's what that looks like with color-mix():

.color-mix-example {
--brand: #0af;

--darker: color-mix(var(--brand) 25%, black);
--lighter: color-mix(var(--brand) 25%, white);
and if you wanted to mix those colors in a different color space, like srgb, change it:

.color-mix-example {
--brand: #0af;

--darker: color-mix(in srgb, var(--brand) 25%, black);
--lighter: color-mix(in srgb, var(--brand) 25%, white);
Here follows a theming demo using color-mix(). Try changing the brand color and watch the theme update:

Enjoy mixing colors in various color spaces in your stylesheets in 2022!

Before color-contrast(), stylesheet authors needed to know accessible colors ahead of time. Often a palette would show black or white text on a color swatch, to indicate to a user of the color system which text color would be needed to properly contrast with that swatch.

Screenshot of 3 Material palettes, showing 14 colors and their appropriate white or black contrast colors for text.
Example from 2014 Material Design color palettes
After color-contrast(), stylesheet authors can offload the task entirely to the browser. Not only can you employ the browser to automatically pick a black or white color, you can give it a list of design system appropriate colors and have it pick the first to pass your desired contrast ratio.

Here's a screenshot of an HWB color palette set demo where the text colors are automatically chosen by the browser based on the swatch color:

Screenshot of the HWB demo where each palette has a different pairing of light or dark text, as determined by the browser.
Try the demo
The basics of the syntax look like this, where gray is passed to the function and the browser determines if black or white have the most contrast:

color: color-contrast(gray);
The function can also be customized with a list of colors, from which it will pick the highest contrasting color.

Lastly, in case it's preferable not to pick the highest contrasting color from the list, a target contrast ratio can be provided, and the first color to pass it is chosen:

color: color-contrast(
var(--text-lightest), var(--text-light), var(--text-subdued)
to AA /* 4.5 could also be passed */
This function can be used for more than just text color, though I estimate that will be its primary use case. Think about how much easier it will be to deliver accessible and legible interfaces once the choosing of proper contrasting colors is built into the CSS language itself.

Resources #
color-contrast() specification
color-contrast() on MDN

Before relative color syntax, to compute on color and make adjustments, the color channels needed to be individually placed into custom properties. This limitation also made HSL the primary color function for manipulating colors because the hue, saturation, or lightness could all be adjusted in a straightforward way with calc().

After relative color syntax, any color in any space can be deconstructed, modified, and returned as a color, all in one line of CSS. No more limitations to HSL—manipulations can be done in any color space desired, and many less custom properties need to be created to facilitate it.

In the following syntax example, a base hex is provided and two new colors are created relative to it. The first color --absolute-change creates a new color in LCH from the base color, then proceeds to replace the base color’s lightness with 75%, maintaining the chroma (c) and hue (h). The second color --relative-change creates a new color in LCH from the base color, but this time reduces the chroma (c) by 20%.

.relative-color-syntax {
--color: #0af;
--absolute-change: lch(from var(--color) 75% c h);
--relative-change: lch(from var(--color) l calc(c-20%) h);
It's akin to mixing colors, but it's more similar to alterations than it is mixing. You get to cast a color from another color, getting access to the three channel values as named by the color function used, with an opportunity to adjust those channels. All in all, this is a very cool and powerful syntax for color.

In the following demo I've used relative color syntax to create lighter and darker variants of a base color, and used color-contrast() to ensure the labels have proper contrast:

Screenshot with 3 columns, each column is either darker or lighter than the center column.
Try the demo
This function can also be used for color palette generation. Here is a demo where entire palettes are generated off a provided base color. This one set of CSS powers all the various palettes, each palette simply provides a different base. As a bonus, since I've used LCH, look at how perceptually even the palettes are—no hot or dead spots to be seen, thanks to this color space.

:root {
--_color-base: #339af0;

--color-0: lch(from var(--_color-base) 98% 10 h);
--color-1: lch(from var(--_color-base) 93% 20 h);
--color-2: lch(from var(--_color-base) 85% 40 h);
--color-3: lch(from var(--_color-base) 75% 46 h);
--color-4: lch(from var(--_color-base) 66% 51 h);
--color-5: lch(from var(--_color-base) 61% 52 h);
--color-6: lch(from var(--_color-base) 55% 57 h);
--color-7: lch(from var(--_color-base) 49% 58 h);
--color-8: lch(from var(--_color-base) 43% 55 h);
--color-9: lch(from var(--_color-base) 39% 52 h);
--color-10: lch(from var(--_color-base) 32% 48 h);
--color-11: lch(from var(--_color-base) 25% 45 h);
--color-12: lch(from var(--_color-base) 17% 40 h);
--color-13: lch(from var(--_color-base) 10% 30 h);
--color-14: lch(from var(--_color-base) 5% 20 h);
--color-15: lch(from var(--_color-base) 1% 5 h);
Screenshot of 15 palettes all generated dynamically by CSS.
Try the demo
Hopefully by now you can see how color spaces and different color functions can all be used for different purposes, based on their strengths and weaknesses.

Resources #
Relative color syntax specification
Building color palettes with relative color syntax
Building color variants with relative color syntax
Gradient color spaces #
Before gradient color spaces, sRGB was the default color space used. sRGB is generally reliable, but does have some weaknesses like the gray dead zone.

4 gradients in a grid, all from cyan to deeppink. LCH and LAB have more consistent vibrancy, where sRGB goes a bit desaturated in the middle.
After gradient color spaces, tell the browser which color space to use for the color interpolation. This gives developers and designers the ability to choose the gradient they prefer. The default color space also changes to LCH instead of sRGB.

The syntax addition goes after the gradient direction, uses the new in syntax, and is optional:

background-image: linear-gradient(
to right in hsl,
black, white

background-image: linear-gradient(
to right in lch,
black, white
Here's a basic and essential gradient from black to white. Look at the range of results in each color space. Some reach dark black earlier than others, some fade to white too late.

11 color spaces shown comparing black to white.
In this next example, black is transitioned to blue because it's a known problem space for gradients. Most color spaces creep into purple during color interpolation or, as I like to think of it, as colors travel inside their color space from point A to point B. Since the gradient will take a straight line from point A to point B, the shape of the color space drastically changes the stops that the path takes along the way.

okLCH and okLAB are specialized color spaces that account for various drifts, like this one into purple, making them especially accurate for gradients.
11 color spaces shown comparing blue to black.
For more deep explorations, examples and comments, read this Twitter thread.

Before inert, it was good practice to guide the user's focus to areas of the page or app that needed immediate attention. This guided focus strategy became known as focus trapping because developers would place focus into an interactive space, listen for focus change events and, if the focus left the interactive space, then it was forced back in. Users on keyboards or screen readers are guided back to the interactive space to ensure the task is complete before moving on.

Sign In or Register to comment.