Modern CSS features
Modern CSS brings powerful new capabilities: CSS properties (custom properties/variables), has() selector for parent selection, CSS subgrid for nested grids, cascade layers for managing specificity, and container queries for component-based responsiveness. These features enable more flexible, maintainable, and powerful stylesheets.
CSS custom properties (variables)
CSS
/* Define custom properties */
:root {
--primary-color: #0066cc;
--secondary-color: #ff6600;
--spacing: 16px;
--radius: 8px;
}
/* Use custom properties */
button {
background: var(--primary-color);
padding: var(--spacing);
border-radius: var(--radius);
color: white;
}
/* Fallback values */
.theme-dark {
color: var(--text-color, #ffffff);
/* Uses --text-color if defined, otherwise #ffffff -->
}
/* Scope variables to elements */
.light-theme {
--text-color: #000000;
--bg-color: #ffffff;
}
.dark-theme {
--text-color: #ffffff;
--bg-color: #1a1a1a;
}
/* Variables in calc() */
.spacing {
margin: calc(var(--spacing) * 2);
padding: calc(var(--spacing) / 2);
}
/* Dynamic variables with JavaScript */
document.documentElement.style.setProperty('--primary-color', '#ff0000');
/* CSS */
button {
background: var(--primary-color); /* updates when JS changes var -->
}has() selector - parent selection
The :has() selector lets you style elements based on their children or siblings, enabling "parent" selection which was impossible before.
CSS
/* Style form if input is invalid */
form:has(input:invalid) {
border: 2px solid red;
}
/* Style card if it contains a featured label */
.card:has(.featured-badge) {
border: 3px solid gold;
box-shadow: 0 0 20px rgba(255, 215, 0, 0.3);
}
/* Style parent based on child hover */
.parent:has(.child:hover) {
background: rgba(0, 0, 0, 0.05);
}
/* Complex selectors with has() */
article:has(> h2.featured) {
padding: 20px;
background: #f9f9f9;
border-left: 4px solid #0066cc;
}
/* has() with :is() */
section:has(h2, h3) {
margin-bottom: 30px;
border-bottom: 1px solid #eeeeee;
}CSS subgrid
Subgrid lets nested grid items align with the parent grid, creating sophisticated multi-level layouts.
CSS
/* Parent grid */
.gallery {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: auto auto auto;
gap: 20px;
}
/* Child uses subgrid */
.gallery-item {
display: grid;
grid-template-columns: subgrid; /* inherit parent's columns -->
grid-template-rows: subgrid; /* inherit parent's rows -->
gap: inherit;
}
.gallery-item-image {
grid-column: 1;
grid-row: 1;
}
.gallery-item-title {
grid-column: 1;
grid-row: 2;
}
.gallery-item-description {
grid-column: 1;
grid-row: 3;
}
<!-- All items align with parent grid columns and rows -->
/* Practical example: form layout -->
.form {
display: grid;
grid-template-columns: 150px 1fr;
gap: 20px;
}
.form-group {
display: grid;
grid-template-columns: subgrid; /* labels and inputs align -->
gap: inherit;
}
.form-group label {
grid-column: 1;
}
.form-group input {
grid-column: 2;
}Cascade layers
CSS
/* Define layer order */
@layer reset, base, theme, utilities;
/* Reset layer - low specificity baseline -->
@layer reset {
* { margin: 0; padding: 0; }
body { font-size: 16px; }
}
/* Base layer - component styles -->
@layer base {
button {
padding: 10px 20px;
border: 1px solid #ccc;
background: white;
}
}
/* Theme layer - specific overrides -->
@layer theme {
button {
background: #0066cc;
color: white;
}
}
/* Utilities layer - override everything -->
@layer utilities {
.btn-danger {
background: #ff0000 !important;
}
}
/* Later layer wins over earlier, ignores specificity -->
/* Utilities override theme, which overrides base, which overrides reset -->
/* Nested layers -->
@layer framework {
@layer reset { /* reset styles */ }
@layer components { /* component styles */ }
}
@layer my-styles {
@layer overrides { /* custom overrides --> }Advanced color functions
CSS
/* color-mix() - mix two colours -->
.tint {
background: color-mix(in srgb, #0066cc 80%, white);
/* 80% blue, 20% white -->
}
/* Relative colour syntax - modify existing colour -->
:root {
--primary: oklch(0.55 0.2 264);
}
.lighter {
background: oklch(from var(--primary) calc(l + 0.2) c h);
/* Same colour but lighter -->
}
.desaturated {
background: oklch(from var(--primary) l calc(c * 0.5) h);
/* Same colour but less saturated -->
}
/* hwb() - hue, whiteness, blackness -->
.color {
color: hwb(194 0% 0%); /* pure cyan -->
color: hwb(194 60% 0%); /* tinted cyan -->
color: hwb(194 0% 40%); /* shaded cyan -->
}@supports for feature detection
CSS
/* Check if browser supports feature -->
@supports (display: grid) {
.layout {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
}
/* Fallback for older browsers -->
@supports not (display: grid) {
.layout {
display: flex;
flex-wrap: wrap;
}
}
/* Check for specific property values -->
@supports (background: color-mix(in srgb, red, blue)) {
.mixed {
background: color-mix(in srgb, red 50%, blue 50%);
}
}
@supports not (background: color-mix(in srgb, red, blue)) {
.mixed {
background: purple; /* fallback -->
}
}
/* Logical combinations -->
@supports (display: flex) and (display: grid) {
.modern { /* both supported */ }
}
@supports (display: grid) or (display: -webkit-grid) {
.grid { /* grid supported, including webkit prefix --> }
}Container queries (component responsiveness)
CSS
/* Container query: element responds to container size -->
.card-container {
container-type: inline-size;
container-name: card;
}
/* Query container -->
@container card (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
}
}
@container card (max-width: 399px) {
.card {
display: flex;
flex-direction: column;
}
}
<!-- Card layout changes based on card container, not viewport -->
/* Container query with max-width -->
@container (min-width: 200px) and (max-width: 500px) {
.item { font-size: 14px; }
}
@container (min-width: 501px) {
.item { font-size: 16px; }
}Note
Modern CSS features enable more maintainable, flexible stylesheets. Custom properties let you create design systems, has() enables new layout possibilities, subgrid simplifies complex layouts, and cascade layers help manage specificity.
Next
Styling form elements and UI components: [forms & UI](/css/forms-ui).