Skip to content

Intermediate · CSS layout and responsive design · topic 28 of 64 · 35 min

Modern CSS: variables, clamp, container queries and more

Explanation

Modern CSS has powerful features that work in all current browsers. Custom properties (CSS variables) store colours and sizes in one place, clamp() makes text grow smoothly, container queries adapt a component to its own space, and :has() and nesting make selectors simpler.

Custom properties (CSS variables)

A custom property is a name that starts with two hyphens and holds a value. You read it with var(). Define them on :root (the html element) to use them everywhere.

css
:root {
  --brand: #ea580c;
  --text: #1f2937;
  --bg: #ffffff;
  --radius: 12px;
}
.btn {
  background: var(--brand);
  border-radius: var(--radius);
}
@media (prefers-color-scheme: dark) {
  :root { --text: #f3f4f6; --bg: #111827; }
}
body { color: var(--text); background: var(--bg); }
One place for brand values, and a dark theme by changing only the variables
Think of it like this: Think of a recipe that says "add 1 cup of the house spice mix" instead of listing ten spices each time. Change the house mix once, and every dish that uses it changes. CSS variables are your house spice mix.

calc(), min(), max() and clamp()

css
.sidebar { width: calc(100% - 2rem); }
.container { width: min(100% - 2rem, 960px); }   /* the smaller of the two */
h1 { font-size: clamp(1.75rem, 1.2rem + 2.5vw, 3rem); }
clamp(minimum, preferred, maximum)

clamp() keeps a value between a minimum and a maximum while letting it grow with the screen in between. It gives fluid headings that never get too small on phones or too big on monitors, without media queries.

Container queries

Media queries look at the whole screen. Container queries look at the space a component actually has. A product card can switch to a side-by-side layout when its container is wide, whether it sits in a narrow sidebar or a wide main area.

css
.card-list { container-type: inline-size; }

@container (min-width: 400px) {
  .card { display: grid; grid-template-columns: 120px 1fr; }
}
The card changes layout based on its container, not the screen

:has(), nesting and friends

FeatureExampleWhat it does
:has().field:has(input:invalid) { color: #b91c1c; }Styles a parent based on what it contains
Nesting.card { & h3 { margin: 0; } }Write child rules inside the parent rule
Logical propertiesmargin-inline: auto; padding-block: 1rem;Work for left-to-right and right-to-left languages (like Urdu)
aspect-ratioimg { aspect-ratio: 16 / 9; }Keep a shape without padding hacks
Tip: Before using a brand-new feature, check its support on MDN or caniuse.com. Everything in this topic works in all major browsers released in the last few years.
Careful: Variable names are case-sensitive and must start with --. A typo like var(--Brand) silently gives nothing. Add a fallback when unsure: var(--brand, orange).

Watch the lesson

Modern CSS: variables, clamp, container queries and more · 1/6

:root { --brand: #ea580c; }
.btn { background: var(--brand); }

Modern CSS saves a lot of work. Let us start with custom properties, also called CSS variables.

Prefer a video by a teacher? Find free videos on “modern css custom properties clamp container queries has selector” on YouTube ↗

In real life: A festival theme switch

A clothing brand runs Diwali, Eid and Christmas themes. All colours live in custom properties on :root. For each festival, a small class on <html> overrides five variables and the whole site changes colour. Headings use clamp() so they look great on both phones and laptops, and the product card uses a container query so it fits in the sidebar and the main grid alike.

Practice (0/2 done)

Task 1 · Code · HTML

Create a CSS variable --brand with the value #ea580c on :root, and use it as the background-color of .btn with var(--brand).

Task 2 · Code · Javascript

Write a function clampValue(min, preferred, max) that works like CSS clamp() for numbers: it returns preferred, but never less than min and never more than max.

Quick quiz

Question 1

1.How do you read a custom property called --gap?

Question 2

2.What does clamp(1rem, 4vw, 2rem) do?

Question 3

3.A container query responds to...

Question 4

4.Which selector styles a .field that contains an invalid input?

Question 5

5.Why use margin-inline instead of margin-left and margin-right?

Read more (free)

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

← Previous: Responsive design and media queries