What's new in CSS?

Who am I?

What is the CSS Working Group (CSSWG)?

  • Part of W3C
  • Chartered to develop CSS
  • Everyone can get involved (discussions happening on GitHub)
  • Issues get discussed and resolved on
  • Separate CSS specification modules

New Features

Features with browser support

Container Queries

Styling based on container element

.container {
  container-type: inline-size;
}

@container (width => 600px) {
  .card {
    display: flex;
  }
}

Container length units

Container queries also bring new units:
cqw, cqh, cqi, cqb, cqmin, cqmax

@container (width => 600px) {
  .card {
    display: flex;
    font-size: 2cqi;
  }
}

@container style()

Styling based on container element's style

@container style(--theme: dark) {
  .card {
    background-color: #202020;
    color: #f0f0f0;
  }
}

:has()

Parent selector and much more

ul + .message {
  display: none;
}

/* If the list has no items, display the message */
ul:not(:has(> li)) + .message {
  display: block;
}

Cascade Layers

Generate different layers of specificity

@layer reset, defaults, components, utilities, overrides;
@import url('framework.css') layer(components.framework);

@layer utilities {
  [data-color='brand'] { color: var(--brand, rebeccapurple); }
}

@layer defaults {
  a:any-link { color: maroon; }
}

a { color: mediumvioletred; }

Nesting

Style and at-rules can be nested like in preprocessors

.card {
  background-color: #fff;

  &:hover {
    background-color: #eee;
  }

  @media (width >= 600px) {
    border: 1px solid #aaa;
  }
}

Subgrid

Nested grids controlled by a parent grid

.outer-grid {
  display: grid;
  grid-template-rows: repeat(4, minmax(100px, auto));
  background-color: #333;
}

.inner-grid {
  display: grid;
  grid-row: 2 / 4;
  grid-template-rows: subgrid;
  background-color: #666;
}

@supports selector()

Checks support for specific selectors

@supports selector(:nth-child(1 of .foo)) {
  :nth-child(1 of .foo) { font-size: 1.2rem; }
}

@supports selector(:has(+ a)) {
  :has(+ a) { color: green; }
}

@supports font-format() + @supports font-tech()

Checks support for specific font formats or technologies

@supports (font-format(woff2)) {
  .font-format-supported { display: block; }
}

@supports (font-tech(palettes)) {
  .font-tech-supported { display: block; }
}

aspect-ratio

Defines a preferred aspect ratio

.image {
  width: 100%;
  aspect-ratio: 16 / 9;
}

conic-gradient() + repeating-conic-gradient()

Circular color transitions around a center point

.checkerboard {
  background-image: repeating-conic-gradient(#000 0% 25%, #fff 0% 50%);
  background-size: 60px 60px;
}

:is() + :where()

Simplifies selecting multiple elements

article > :is(h1, h2, h3, h4, h5, h6) {
  font-family: "soleil", Helvetica, Arial, sans-serif;
}

Extended :not()

:not() now supports complex selectors

/* All <p>s outside an <article> */
p:not(article *) {
  background-color: rgb(0 0 0 / 0.2);
}

scale, rotate and translate

Separate transformation properties

.img:hover {
  scale: 1.2;
}

a.open .arrow {
  rotate: 90deg;
}

.img {
  translate: 40px;
}

@property

Defines custom properties that can be used like built-in properties

@property --my-color {
  syntax: "<color>";
  inherits: false;
  initial-value: #c0ffee;
}

a { color: var(--my-color); }

Range syntax in media queries

Mathematical expressions in media queries

@media (600px <= width) { … }

@media (width < 80em) { … }

@media (400px < width <= 1000px) { … }

New viewport units

Viewport units based on large, small and dynamic viewport lengths

.box {
  width: 80lvw;
  height: 50dvh;
  padding: 1svh 1svw;
}

New color functions and spaces

Color functions supporting different color spaces
lch(), lab(), oklch(), oklch() and color()

.box {
  background-color: hwb(0 100% 0% / 50%);
  color: #0008;
  border-color: #FFFFFFA0;
  text-decoration-color: color(display-p3 -0.6112 1.0079 -0.2192);
  background-color: lch(29.2345% 44.2 27);
  color: lab(62.2345% -34.9638 47.7721);
  border-color: oklab(40.101% 0.1147 0.0453);
  text-decoration-color: oklch(0.66016 0.15546 134.231);
}

color-mix()

Mixes two colors using a color space to create a new color

.box {
  background-color: color-mix(in srgb, #34c9eb 10%, white);
}

Relative color syntax

Allows defining new colors based on another color

.relative-colors {
  --accent: darkblue;
  color: rgb(from var(--accent) r g b / 0.5 );
  background-color: lch(from var(--accent) l c calc(h + 180));
}

New media features

Media features to check different device aspects and user preferences


@media (prefers-color-scheme: dark) { … }
@media (prefers-contrast: more) { … }
@media (prefers-reduced-motion) { … }
@media (prefers-reduced-data: reduce) { … }
@media (dynamic-range: high) { … }
@media (update: slow) { … }
@media (forced-colors: active) { … }
					

:modal

Selector to target elements displayed modally

:modal {
  border: 5px solid red;
  background-color: yellow;
  box-shadow: 3px 3px 10px rgb(0 0 0 / 0.5);
}

:focus-visible + :focus-within

Select elements when the focus ring is visible or when the focus is placed somewhere inside an element

input:focus-visible {
  box-shadow: 0 0 4px skyblue;
}

fieldset:focus-within {
  background-color: rgb(0 0 0 / 0.1);
}

:user-valid + :user-invalid

Selects (in-)valid form elements when the user interacted with them

input:user-invalid {
  background-color: rgb(255 0 0 / 0.6);
}

:placeholder-shown

Selects inputs where the placeholder is showns

input:placeholder-shown {
  background-color: #f0f0f0;
  color: #080808;
}

:autofill

Selects form fields that are filled by selecting a predefined option

input:autofill {
  background-color: rgb(0 0 0 / 0.2);
}

::file-selector-button

Targets the button within <input type="file"> elements

::file-selector-button {
  appearance: none;
  background-color: navy;
  color: white;
}

backdrop-filter

Filters the backdrop of an element

dialog {
  background-color: rgb(255 255 255 / 0.5);
  backdrop-filter: blur(10px);
}

linear()

.box {
  animation-timing-function: linear(0, 0.25 75%, 1);
}

overflow: clip

.box {
  overflow: clip;
}
  • 90
  • 16
  • 81
  • 90
  • 76

appearance

input, button, select, textarea {
  appearance: none;
  border: 2px solid gray;
}

text-decoration-thickness + text-underline-offset

a {
  text-decoration-thickness: 0.1em;
  text-underline-offset: 0.1em;
}

::target-text

::target-text {
  background-color: rebeccapurple;
  color: white;
}

View Transitions

Transition between different DOM states

figcaption {
  view-transition-name: figure-caption;
}

::view-transition-old(figure-caption),
::view-transition-new(figure-caption) {
  animation-duration: 0.5s;
}

Typed Object Model

Advanced CSS value manipulation

el.attributeStyleMap.set('padding', CSS.px(42));
const padding = el.attributeStyleMap.get('padding');
console.log(padding.value, padding.unit); // 42, 'px'

accent-color

Provides an accent color for form elements

form {
  accent-color: seagreen;
}
  • 93
  • 15.4
  • 92
  • 93
  • 79

color-scheme

Forces a color scheme onto elements

:root {
  color-scheme: dark;
}
  • 81
  • 13
  • 96
  • 81
  • 68

content-visibility

Controls whether the contents of an element are visible

section {
  content-visibility: auto;
}

touch-action

.box {
  touch-action: pan-right pinch-zoom;
}

clip-path: path()

.box {
  clip-path: path("M 20 240 C 20 0 300 0 300 240 Z");
}

Scrollbar styling

Basic styling of scrollbars

.container {
  scrollbar-gutter: stable;
  scrollbar-width: thin;
  scrollbar-color: firebrick;
}

Font Palettes

Defines and applies custom color palettes for COLRv1 fonts

@font-palette-values --Grays {
  font-family: Rocher;
  base-palette: 9;
  override-colors: 2 rgb(90, 290, 210);
}

.grays {
  font-family: "Rocher";
  font-palette: --Grays;
}

Trigonometric functions and units

Math functions and units related to trigonometry

.box {
  width: calc(pow(2% / 4));
  height: calc(tan(60deg) * 100%;
}

Exponential and other math functions

Mathematical functions related to exponential functionality
pow(), exp(), hypot(), log(), rem(), sqrt(), abs(), round(), sign()

.box {
  width: calc(10px * pow(5, 2));
  height: calc(10px * exp(1));
}

scroll-behavior

Defines whether the scroll behavior is smooth or immediate

article {
  scroll-behavior: smooth;
}

overscroll-behavior

Controls the effect when overscrolling a scroll container

.box {
  overflow-behavior: contain;
}

scroll-margin + scroll-padding

Defines the distance of elements to their scroll container

article {
  scroll-padding: 150px;
}

p {
  scroll-margin: 150px;
}

margin-trim

Controls trimming of margins

article > p {
  margin-trim: block;
}

text-wrap

Influences text wrapping e.g. to balance it out

article > p {
  text-wrap: balance;
}

New font related units

cap, ic, lh, rex, rch, ric, rlh

p {
  font-size: 1.5cap;
}

input {
  height: 2lh;
}

:nth-child(an + b of S)

Matches elements based on their position in a group of siblings matching a selector

p:nth-child(2n + 1 of .special) {
  color: red;
}

:picture-in-picture

Matches elements that are displayed in a picture-in-picture context

video:picture-in-picture {
  border: 2px solid blue;
  border-radius: 4px;
}

:fullscreen

Matches elements that are displayed in fullscreen mode

video:fullscreen {
  border: 2px solid blue;
}

hyphenate-limit-chars

Defines the minimum number of characters in a hyphenated word

p {
  hyphenate-limit-chars: 3;
}

scroll-snap-stop

Defines whether a scroll container should stop on snap points

.gallery {
  scroll-snap-stop: always;
}

Custom Highlight API

Allows to define custom highlights

CSS.highlights.set('my-custom-highlight', highlight);
::highlight(my-custom-highlight) {
  background-color: yellow;
  color: black;
}

Upcoming Features

Features soon to be implemented

Scroll-driven animations

Animating elements based on scroll position

@keyframes --stretch {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

body {
	scroll-timeline: --scroll-indicator;
}

#scroll-indicator {
  position: fixed;
  top: 0;
  background-color: firebrick;
  width: 100%;
  height: 8px;
  animation: --stretch 1s linear;
  animation-timeline: --scroll-indicator;
}

Anchor Positioning

Positions elements relative to other elements with fallbacks

.anchor {
  anchor-name: --my-anchor;
}

.tooltip {
  position: absolute;
  bottom: anchor(--my-anchor auto);
  top: auto;
}

@scope

Scopes styles to a DOM subtree

@scope (.card) {
p {
  background-color: lime;
}

View Transitions for MPA

Transitions between two elements in multi-page applications

@keyframes --slide-to-left {
  from { transform: translateX(100vw); }
  to { transform: translateX(0); }
}

::view-transition-old(root) {
  animation: none;
}

::view-transition-new(root) {
  animation: --slide-to-left 0.3s;
}

@starting-style

Defines initial styles for elements being added

div {
  width: 100px;
  height: 100px;
  transition: background-color 0.5s;
  background-color: transparent;

  @starting-style {
    background-color: yellow;
  }
}

Masonry layout

Pinterest-like layout

.container {
  display: grid;
  gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
  grid-template-rows: masonry;
}

Color spaces for gradients

Defines the color space to use for transitioning colors in a gradient

.card {
  background-image: linear-gradient(in lch, yellow, blue);
}

contrast-color()

Selects a fitting contrast color for a given color

.card {
  background-color: #000;
  color: contrast-color(#000 vs green, blue, yellow);
}

toggle()

Toggles between different values

ul {
  list-style-type: toggle(disc; circle; square; box);
}

box-shadow-* longhand properties

Different box-shadow-* properties for the different parts of box shadows

.container {
  box-shadow-offset: 4px 6px;
  box-shadow-color: rgb(0 0 0 / 0.4);
  box-shadow-blur: 5px;
  box-shadow-spread: 0;
  box-shadow-position: inset;
}

stripes()

Defines a 1d image that can be used in different contexts like multi-color borders

.container {
  border: 10px solid stripes(red 1px, green 2fr, blue 2px);
}

border-*-radius longhand properties

Border properties that allow to set the two radii for one side

.container {
  border-top-radius: 10px;
}

.container {
  border-inline-end-radius: 10px;
}

Sources

Links

Request

Please take the State of CSS 2023 survey!

https://stateofcss.com/en-us/

Thank you!