What is new with CSS in 2022?

# The Hotlist (Cross-Browser Support)

I’m quite confident the following features will see support across all browsers sometime in 2022. Some features already have support in one or more browsers, with others to follow. Learning one of the following CSS features listed below in 2022 will pay off.

# Container Queries

Container Queries — part of css-contain-3 — allow authors to style elements according to the size or appearance of a container. For size-based container queries this is similar to a @media query, except that it will evaluate against the size of a parent container instead of the viewport.

For style-based container queries, you conditionally apply styles based on the calculated value of another CSS property.

main, aside {
  container: inline-size;

.media-object {
  display: grid;
  grid-template: `img` auto `content` auto / 100%;

@container (inline-size > 45em) {
  .media-object {
    grid-template: `img content` auto / auto 1fr;


More info: CSS Container Queries: A First Look + Demo →

Relevant Issues:

# Cascade Layers

With Cascade Layers, you can control cascade ordering for same-origin rules properly. You do this by layering your styles using the @layer at-rule. Layers appear before specificity and order of appearance in the cascade.

@import(reset.css) layer(reset); /* 1st layer */

@layer base { /* 2nd layer */
  form input {
    font-size: inherit; 

@layer theme { /* 3rd layer */
  input {
    font-size: 2rem;

Cascade layers will be supported in Chromium 99 and Firefox 97. They’re also supported in Safari TP 133 (behind a flag), and I expect them to ship in the first quarter of 2022.

More info: The Future of CSS: Cascade Layers (CSS @layer) →

Relevant Issues:

# Color Functions

The css-color-5 specification comes with a few niceties when it comes to working with color. It adds two new functions: color-mix(), color-contrast(), and extends existing ones with relative color syntax.


The color-mix() function allows you to mix two colors in a given color space.

.text-primary-dark {
  color: color-mix(var(--theme-primary), black 10%);
.text-primary-darker {
  color: color-mix(var(--theme-primary), black 20%);


The color-contrast() function allows you select the best color from a list of colors that meets or exceeds the contrast criteria when compared to a certain base color.

/* Compares wheat against tan, sienna, and #d2691e */
/* Sienna will be selected as it has a contstast of 4.273 against wheat, which exceeds the threshold of AA-large (3) */
color-contrast(wheat vs tan, sienna, #d2691e to AA-large)


With the relative color syntax you can manipulate and convert any color to any format.

:root {
  --color: #ff0000;

.selector {
  /* change the transparency */
  color: hsl(from var(--color) h s l / .5);
  /* change the hue */
  color: hsl(from var(--color) calc(h + 180deg) s l);
  /* change the saturation */
  color: hsl(from var(--color) h calc(s + 5%) l);

These additions plug functionalities typically provided by CSS Preprocessors. Already supported in WebKit/Safari.

More Info:

Relevant Issues:


# Viewport Units

When working with Viewport Units there’s this longstanding and extremely annoying bug in Safari on iOS where it does not play nice with the vh unit. Setting a container to 100vh will result in an element that’s a wee bit too tall: MobileSafari ignores parts of its UI when calculating 100vh.

Leaving the vh unit as it is, the CSS Working Group introduced several new viewport definitions and accompanying new viewport relative lengths in the css-values-4 specification:

  • svh/svw: 1% of the Small Viewport height/width
  • lvh/lvw: 1% of the Large Viewport height/width
  • dvh/dvw: 1% of the Dynamic Viewport height/width

Also available as logical variants, such as svi/svb

More Info: The Large, Small, and Dynamic Viewports →

Relevant Issues:

The same spec also introduces logs of new mathematical functions to use in calculations. Definitely worth checking out.


# :has()

The CSS :has() relational pseudo-class is part of selectors-4. It allows you to more finely select elements, as an element will only match if any of the extra selectors passed into :has() matches at least one element. It’s often dubbed “the parent selector” but it’s way more than that.

/* Matches <a> elements that contain an <img> child */
a:has(img) { … }

/* Matches <a> elements that directly contain an <img> child */
a:has(> img) { … }

/* Matches <section> elements that don’t contain any heading elements: */
section:not(:has(h1, h2, h3, h4, h5, h6))

/* Matches <h1> elements only if they have a <p> element directly following them */
h1:has(+ p) { … }

More Info: The CSS :has() selector is way more than a “Parent Selector” →

Relevant Issues:


# Overscroll Behaviour

With the CSS overscroll-behavior property you can override the default behavior when “overscrolling” a container. With it, you can prevent a full reload when a pull-to-refresh gesture is performed, disable rubber banding, contain scrolling within one layer, etc.

Long supported in Firefox (version 36) and Chromium (version 63). Safari is — finally! — catching up.

More info: Customizing Pull-to-Refresh and Overflow Effects with CSS overscroll-behavior

Relevant Issues:


# Subgrid