CSS New Features That Are Absolutely Stunning
CSS functions
CSS now supports powerful built-in functions that make previously JavaScript-only transformations possible directly in stylesheets.
min(),max(),clamp()— Responsive sizing without media queriesround(),mod(),rem()— Mathematical operations on valuessin(),cos(),tan()— Trigonometric functions for complex layoutsabs(),sign()— Absolute value and sign of a number
/* Fluid typography that clamps between 1rem and 2rem */
h1 {
font-size: clamp(1rem, 2.5vw + 0.5rem, 2rem);
}
/* Responsive container width without breakpoints */
.card {
width: min(400px, 90vw);
}
/* Circular motion using trig functions */
.orbit {
--angle: 45deg;
transform: translate(
calc(cos(var(--angle)) * 100px),
calc(sin(var(--angle)) * 100px)
);
}
View Transitions
The View Transitions API lets you create smooth, animated transitions between page states — or even between full pages in an MPA — with minimal CSS.
/* Enable the default cross-fade for a specific element */
.hero-image {
view-transition-name: hero;
}
/* Customize the animation */
::view-transition-old(hero) {
animation: 300ms ease-out fade-and-slide-out;
}
::view-transition-new(hero) {
animation: 300ms ease-in fade-and-slide-in;
}
@keyframes fade-and-slide-out {
from {
opacity: 1;
transform: translateY(0);
}
to {
opacity: 0;
transform: translateY(-20px);
}
}
@keyframes fade-and-slide-in {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
Trigger a transition in JavaScript:
// SPA navigation with animated transitions
document.startViewTransition(async () => {
// Update the DOM inside this callback
await updatePageContent(newUrl);
});
For multi-page apps (MPA), opt-in in CSS:
@view-transition {
navigation: auto; /* Enables cross-document view transitions */
}
CSS If
- The
@ifat-rule allows you to apply styles conditionally based on certain criteria, similar to conditional statements in programming languages. This feature is particularly useful for creating themes or responsive designs without relying heavily on media queries.
@layer utilities {
@if (prefers-color-scheme: dark) {
body {
background-color: #121212;
color: #ffffff;
}
} @else {
body {
background-color: #ffffff;
color: #000000;
}
}
}
In this example, the styles inside the @if block will be applied if the user prefers a dark color scheme, while the styles inside the @else block will be applied otherwise.
.box {
width: 300px;
height: 300px;
background-color: if(
media(width > 100px): blue; media (width > 500px): red; else: green;
);
}
CSS Layers
- CSS Layers allow you to organize your styles into different layers, which can help manage specificity and maintainability in large stylesheets. Layers can be defined using the
@layerat-rule.
@layer base, components, utilities;
@layer utilities {
.text-center {
text-align: center;
}
}
@layer base {
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
}
@layer components {
.button {
background-color: blue;
color: white;
padding: 10px 20px;
border-radius: 5px;
}
}
CSS attr()
- The
attr()function in CSS allows you to retrieve the value of an HTML attribute and use it within your CSS styles. This feature enhances the dynamic styling capabilities of CSS by enabling styles to adapt based on the attributes of elements.
<div class="tooltip" data-tooltip="This is a tooltip!" data-width="100">
Hover over me
</div>
.tooltip::after {
content: attr(data-tooltip type<string>, "Default tooltip text");
width: attr(data-width px, 150px);
}
Container Queries
Respond to the size of their container rather than the viewport, allowing for more modular and adaptable designs.
Container queries enable components to adjust their styles based on the size of their parent element, making it easier to create responsive designs that work well in various layouts.
Setting up a container query is quite straightforward. You can define a container using the container-type property and then apply styles based on the container’s size.
.card {
container-type: inline-size;
}
/* Syntax */
@container style(<style-feature>),
not style(<style-feature>),
style(<style-feature>) and style(<style-feature>),
style(<style-feature>) or style(<style-feature>) {
/* <stylesheet> */
}
@container (min-width: 300px) {
.card {
background-color: lightblue;
}
}
This code snippet sets up a container query that changes the background color of the .card element when its width exceeds 300 pixels.
container-type: This property defines the type of container. it accepts normal, size, inline-size, scroll-state.
normal: The element does not establish a container.
size: The element establishes a size container, which tracks both width and height.
inline-size: The element establishes an inline size container, which tracks only the inline size (width in horizontal writing modes).
scroll-state: The element establishes a scroll state container, which tracks the scroll position of the element.
container-name: This property allows you to name a container, which can be useful when you have multiple containers on a page.
.container {
container-name: my-container;
container-type: size;
}
@container my-container (min-width: 400px) {
.item {
font-size: 1.5rem;
}
}
container: This shorthand property allows you to set both the container-name and container-type in one declaration.
.container {
container: my-container inline-size;
}
Container units
cqw: Container Query Width - 1% of the container’s width.cqh: Container Query Height - 1% of the container’s height.cqi: Container Query Inline Size - 1% of the container’s inline size.cqb: Container Query Block Size - 1% of the container’s block size.cqmin: Container Query Minimum - The smaller value between width and height of the container.cqmax: Container Query Maximum - The larger value between width and height of the container.
@supports
The @supports rule allows you to apply CSS only if the browser supports a specific feature. This is particularly useful for progressive enhancement and ensuring compatibility across different browsers.
@supports (display: grid) {
.layout {
display: grid;
grid-template-columns: 1fr 1fr;
}
}
In this example, the styles inside the @supports block will only be applied if the browser supports CSS Grid.
Corner Shape
The corner-shape property allows you to create complex shapes for the corners of elements, going beyond simple rounded corners. It supports various values like bevel, notch, square, scoop, round and squrecircle.
.box {
width: 200px;
height: 200px;
background-color: lightcoral;
corner-shape: bevel;
}
- You can use superellipse() function to create squircle shapes for corners.
CSS Nesting
CSS Nesting allows you to nest CSS rules inside one another, making it easier to read and maintain styles, especially for complex components.
/* Without nesting — repetitive selectors */
.card {
background: white;
border-radius: 8px;
}
.card .title {
font-size: 1.25rem;
font-weight: bold;
}
.card .body {
font-size: 1rem;
color: #555;
}
.card:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.card:hover .title {
color: blue;
}
/* With CSS Nesting — clean and co-located */
.card {
background: white;
border-radius: 8px;
.title {
font-size: 1.25rem;
font-weight: bold;
}
.body {
font-size: 1rem;
color: #555;
}
&:hover {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
.title {
color: blue;
}
}
}
The & selector refers to the parent rule. You can also nest media queries:
.sidebar {
width: 250px;
@media (max-width: 768px) {
width: 100%;
position: static;
}
.nav-item {
padding: 8px 16px;
&:hover {
background: #f0f0f0;
}
&.active {
font-weight: bold;
color: var(--primary);
}
}
}
CSS Nesting is now supported in all modern browsers (Chrome 112+, Firefox 117+, Safari 17+) and is a game-changer for component-based styling without preprocessors.
CSS Colors
Named Colors: CSS Supports a wide range of named colors likerebeccapurple,lightseagreen, andmediumslateblue.Color Functions: New color functions likecolor-mix()andcolor-contrast()allow you to programmatically blend and select accessible colors.
/* color-mix(): blend two colors */
.muted-button {
/* Mix 30% blue into red */
background: color-mix(in srgb, blue 30%, red);
}
/* color-contrast(): automatically pick the most readable color */
.auto-text {
/* Picks whichever of black or white has higher contrast against the background */
color: color-contrast(var(--bg-color) vs black, white);
}
HexaDecimal Colors: CSS now supports 8-digit and 4-digit hexadecimal color codes, allowing you to specify colors with alpha transparency directly in the hex format.
/* 8-digit hex (RRGGBBAA) */
.transparent-blue {
background-color: #0000ff80; /* Blue with 50% opacity */
}
/* 4-digit hex (RGBA) */
.semi-transparent-red {
background-color: #f00a; /* Red with 66% opacity */
}
RGBA: CSS supports RGBA color values, allowing you to define colors in terms of red, green, blue, and alpha (opacity).
.semi-transparent-green {
background-color: rgba(0, 255, 0, 0.5);
}
HSL and HSLA: CSS supports HSL (Hue, Saturation, Lightness) and HSLA (Hue, Saturation, Lightness, Alpha) color values.
.soft-purple {
background-color: hsl(270, 60%, 70%);
}
.transparent-yellow {
background-color: hsla(60, 100%, 50%, 0.5);
}
HWB: CSS supports HWB (Hue, Whiteness, Blackness) color values.
.muted-cyan {
background-color: hwb(180, 20%, 10%);
}
LAB: CSS supports LAB color values, which are based on human vision and provide a more perceptually uniform color space.
.vibrant-red {
background-color: lab(53.24% 80.09 67.2);
}
LCH: CSS supports LCH (Lightness, Chroma, Hue) color values.
.bright-green {
background-color: lch(75% 100 120);
}
oklab: CSS supports oklab color values, which are designed to be perceptually uniform.
.deep-blue {
background-color: oklab(0.14 0.05 -0.1);
}
oklch: CSS supports oklch color values, which are based on the oklab color space.
.vivid-orange {
background-color: oklch(0.6 0.4 50);
}
CSS Relative Color Syntax
CSS Relative Color Syntax allows you to define colors in relation to other colors, making it easier to create color schemes that adapt to different themes or contexts.
:root {
--base-color: hsl(210, 50%, 50%);
--card-bg: hsl(from var(--base-color) h s calc(l+10));
--card-text: color-mod(var(--base-color) lightness(-20%) saturation(+15%));
}
.button {
background-color: color-mod(var(--base-color) lightness(+10%));
color: color-mod(var(--base-color) lightness(-50%));
}
is Function
The :is() pseudo-class function allows you to group multiple selectors into one, reducing redundancy and improving readability.
/* Without :is() */
.button-primary,
.button-secondary,
.button-tertiary {
padding: 10px 20px;
border-radius: 5px;
}
/* With :is() */
:is(.button-primary, .button-secondary, .button-tertiary) {
padding: 10px 20px;
border-radius: 5px;
}
In this example, the :is() function groups the three button classes, allowing you to apply the same styles to all of them in a single rule.