Learn how to use CSS custom properties (variables) within media queries to create responsive design tokens that adapt seamlessly across different screen sizes.
What it is
CSS variables, also known as custom properties, allow you to store values in a reusable token. When combined with media queries, these tokens can change their value based on the viewport size or other conditions. This creates a "responsive token" system where a single variable name (like --pad) holds different values for mobile and desktop contexts without needing to rewrite specific rules for every element.
The mental model is treating your design system like a set of switches. You define the default state in :root, then flip the switch inside a media query block to update the value globally.
Why it matters
- Maintainability: Change padding, colors, or font sizes for all breakpoints by editing one line per breakpoint instead of hunting through multiple selectors.
- Consistency: Ensures that spacing scales proportionally across the entire layout when the breakpoint triggers.
- Reduced Code Duplication: Eliminates the need to repeat media query blocks for individual components if they share the same responsive logic.
- Dynamic Theming: Allows complex themes to shift entirely by updating a few root-level variables.
Syntax or steps
- Define your base variable in the
:rootselector. - Create a media query block targeting the desired condition (e.g.,
@media (min-width: 700px)). - Inside the media query, redefine the same variable name under
:rootwith the new value. - Use the variable via
var(--name)in your component styles.
Example
/* 1. Define base tokens */
:root {
--spacing-unit: 1rem;
--font-size-base: 16px;
}
/* 2. Override tokens at larger screens */
@media (min-width: 700px) {
:root {
--spacing-unit: 2rem;
--font-size-base: 18px;
}
}
/* 3. Use tokens in components */
.card {
padding: var(--spacing-unit);
font-size: var(--font-size-base);
}
In this example, the .card element automatically receives 1rem padding on small screens and 2rem padding on screens wider than 700px. The browser recalculates the variable value whenever the media query condition changes.
Common mistakes
- Using variables directly in media queries: You cannot write
@media (min-width: var(--breakpoint)). Media queries are evaluated before variables are resolved. Always hardcode the breakpoint values in the query itself. - Forgetting the fallback: If a variable is undefined,
var()returns nothing. Always define defaults in:root. - Over-scoping: Defining variables inside a specific class rather than
:rootprevents them from cascading correctly to child elements unless explicitly inherited. - Performance concerns: While generally negligible, excessive re-declaration of many variables in numerous media queries can increase CSS file size. Group related tokens together.
When to use it
| Approach | Best For | Trade-off |
|---|---|---|
| Responsive Variables | Global design tokens (spacing, typography scale, theme colors) that change uniformly across breakpoints. | Requires careful management of breakpoint definitions since they cannot be dynamic. |
| Component-Level Queries | Unique layouts where only one specific component needs to change behavior independently of the global theme. | Can lead to fragmented code and inconsistent scaling across the site. |
Practice
Guided Exercise: Create a button style that uses --btn-height. Set the default height to 40px. Inside a media query for min-width: 500px, change --btn-height to 50px. Apply this variable to a .button class.
Challenge: Add a second breakpoint at min-width: 1000px that increases --btn-height to 60px and introduces a new variable --btn-radius that goes from 4px to 8px to 12px across the three stages.
Quick check
Question: Can you use a CSS variable inside the condition of a media query, such as @media (max-width: var(--mobile-limit))?
Answer: No. Media queries are processed statically during parsing, while variables are resolved dynamically during rendering. Breakpoints must be hardcoded values.
Summary
Using CSS variables in media queries allows you to centralize responsive logic into design tokens, making your stylesheet easier to maintain and scale. Remember that while the variable values can change responsively, the media query conditions themselves must remain static.