What are CSS Variables?
CSS Variables (officially called Custom Properties ) allow you to store values that you can reuse throughout your stylesheet.
Benefits:
Maintainability - Change one value, updates everywhere
Readability - Semantic names like --color-primary instead of #FFE600
Theming - Easy to implement dark mode and themes
Dynamic - Can be changed with JavaScript
Inheritance - Variables cascade and can be scoped
Defining Variables
Syntax
/* Define */
--variable-name: value;
/* Use */
property: var(--variable-name);
Global Variables with :root
:root is a pseudo-class that selects the <html> element - perfect for global variables.
:root {
--color-primary : #FFE600 ;
--spacing-md : 16 px ;
--font-size-base : 1 rem ;
}
body {
font-size : var ( --font-size-base );
}
.button {
background-color : var ( --color-primary );
padding : var ( --spacing-md );
}
Use :root instead of html for global variables - it has higher specificity and is a common convention.
Naming Conventions
Use descriptive, semantic names:
--yellow: #FFE600;
--16: 16px;
--big: 24px;
Common Prefixes
--color- for colors
--font- for typography
--spacing- for spacing
--border- for borders
--shadow- for shadows
--transition- for animations
Real Variables from the Project
Color System
:root {
/* Brand colors - Mercado Libre style */
--color-primary : #FFE600 ; /* Yellow */
--color-primary-dark : #F5D300 ; /* Yellow hover */
--color-secondary : #3483FA ; /* Blue */
--color-secondary-dark : #2968C8 ; /* Blue hover */
/* State colors */
--color-success : #00A650 ; /* Green */
--color-error : #F23D4F ; /* Red */
--color-warning : #FF7733 ; /* Orange */
/* Neutral colors */
--color-white : #FFFFFF ;
--color-black : #333333 ;
--color-gray-100 : #F5F5F5 ; /* Lightest */
--color-gray-200 : #EEEEEE ;
--color-gray-300 : #CCCCCC ;
--color-gray-400 : #999999 ; /* Medium */
--color-gray-500 : #666666 ;
--color-gray-600 : #333333 ; /* Darkest */
}
Use numbered scales (100-600) for colors that have multiple shades. Lower numbers = lighter.
Typography System
:root {
/* Font family */
--font-family-base : -apple-system , BlinkMacSystemFont, 'Segoe UI' ,
Roboto, Oxygen, Ubuntu, sans-serif ;
/* Font sizes (rem units for accessibility) */
--font-size-xs : 0.75 rem ; /* 12px */
--font-size-sm : 0.875 rem ; /* 14px */
--font-size-base : 1 rem ; /* 16px */
--font-size-lg : 1.125 rem ; /* 18px */
--font-size-xl : 1.25 rem ; /* 20px */
--font-size-2xl : 1.5 rem ; /* 24px */
--font-size-3xl : 2 rem ; /* 32px */
}
Spacing Scale
:root {
/* Based on 4px scale for visual rhythm */
--spacing-xs : 0.25 rem ; /* 4px */
--spacing-sm : 0.5 rem ; /* 8px */
--spacing-md : 1 rem ; /* 16px */
--spacing-lg : 1.5 rem ; /* 24px */
--spacing-xl : 2 rem ; /* 32px */
--spacing-2xl : 3 rem ; /* 48px */
}
Using a consistent spacing scale (multiples of 4 or 8) creates visual harmony and makes designs feel more polished.
Border & Radius
:root {
--border-radius-sm : 4 px ;
--border-radius-md : 8 px ;
--border-radius-lg : 16 px ;
--border-radius-full : 9999 px ; /* Perfect circle/pill */
}
Shadows
:root {
/* Box shadow: offset-x offset-y blur spread color */
--shadow-sm : 0 1 px 3 px rgba ( 0 , 0 , 0 , 0.1 );
--shadow-md : 0 4 px 6 px rgba ( 0 , 0 , 0 , 0.1 );
--shadow-lg : 0 10 px 25 px rgba ( 0 , 0 , 0 , 0.15 );
}
Transitions
:root {
--transition-fast : 150 ms ease ;
--transition-base : 300 ms ease ;
--transition-slow : 500 ms ease ;
}
Layout Dimensions
:root {
--container-max-width : 1200 px ;
--header-height : 120 px ;
}
Using Variables
Basic Usage
.button {
background-color : var ( --color-primary );
padding : var ( --spacing-md ) var ( --spacing-lg );
border-radius : var ( --border-radius-sm );
transition : background-color var ( --transition-fast );
}
.button:hover {
background-color : var ( --color-primary-dark );
}
Fallback Values
Provide a fallback if variable isn’t defined:
.element {
color : var ( --color-text , #333 ); /* Uses #333 if --color-text not defined */
}
Nested Variables
Variables can reference other variables:
:root {
--base-size : 16 px ;
--spacing-1x : var ( --base-size ); /* 16px */
--spacing-2x : calc ( var ( --base-size ) * 2 ); /* 32px */
}
Real-World Examples
.header {
background : linear-gradient (
to bottom ,
var ( --color-primary ),
var ( --color-primary-dark )
);
box-shadow : var ( --shadow-sm );
}
.header__container {
max-width : var ( --container-max-width );
padding : var ( --spacing-md ) var ( --spacing-lg );
gap : var ( --spacing-md );
}
.header__logo-text {
font-size : var ( --font-size-2xl );
color : var ( --color-secondary );
}
.header__nav-link {
padding : var ( --spacing-xs ) var ( --spacing-sm );
font-size : var ( --font-size-sm );
color : var ( --color-gray-600 );
border-radius : var ( --border-radius-sm );
transition : background-color var ( --transition-fast );
}
Product Card with Variables
.product-card {
background-color : var ( --color-white );
border-radius : var ( --border-radius-md );
box-shadow : var ( --shadow-sm );
transition : transform var ( --transition-base ),
box-shadow var ( --transition-base );
}
.product-card:hover {
box-shadow : var ( --shadow-lg );
}
.product-card__content {
padding : var ( --spacing-md );
}
.product-card__category {
padding : var ( --spacing-xs ) var ( --spacing-sm );
background-color : var ( --color-gray-100 );
color : var ( --color-gray-500 );
font-size : var ( --font-size-xs );
border-radius : var ( --border-radius-sm );
margin-bottom : var ( --spacing-sm );
}
.product-card__price {
font-size : var ( --font-size-xl );
color : var ( --color-gray-600 );
margin-bottom : var ( --spacing-md );
}
.product-card__shipping {
font-size : var ( --font-size-xs );
color : var ( --color-success );
}
Scoped Variables
Variables can be scoped to specific elements:
:root {
--button-bg : var ( --color-secondary );
}
.button {
background-color : var ( --button-bg );
}
/* Override for danger buttons */
.button--danger {
--button-bg : var ( --color-error );
/* Now this button uses red */
}
/* Override for success buttons */
.button--success {
--button-bg : var ( --color-success );
/* Now this button uses green */
}
Calc() with Variables
Combine variables with calculations:
:root {
--spacing-base : 8 px ;
--spacing-half : calc ( var ( --spacing-base ) / 2 ); /* 4px */
--spacing-double : calc ( var ( --spacing-base ) * 2 ); /* 16px */
--spacing-triple : calc ( var ( --spacing-base ) * 3 ); /* 24px */
}
.element {
margin : var ( --spacing-double );
padding : var ( --spacing-half ) var ( --spacing-base );
}
Dark Mode with Variables
Easily implement dark mode by changing variable values:
:root {
/* Light mode (default) */
--color-bg : #FFFFFF ;
--color-text : #333333 ;
--color-border : #EEEEEE ;
}
/* Dark mode */
@media (prefers-color-scheme: dark) {
:root {
--color-bg : #1a1a1a ;
--color-text : #f0f0f0 ;
--color-border : #333333 ;
}
}
/* Or with class toggle */
.dark-mode {
--color-bg : #1a1a1a ;
--color-text : #f0f0f0 ;
--color-border : #333333 ;
}
/* All components automatically update! */
body {
background-color : var ( --color-bg );
color : var ( --color-text );
}
JavaScript Integration
Change CSS variables with JavaScript:
// Get variable value
const root = document . documentElement ;
const primaryColor = getComputedStyle ( root )
. getPropertyValue ( '--color-primary' );
// Set variable value
root . style . setProperty ( '--color-primary' , '#FF0000' );
// Example: Dynamic theme
function setTheme ( theme ) {
if ( theme === 'dark' ) {
root . style . setProperty ( '--color-bg' , '#1a1a1a' );
root . style . setProperty ( '--color-text' , '#f0f0f0' );
} else {
root . style . setProperty ( '--color-bg' , '#FFFFFF' );
root . style . setProperty ( '--color-text' , '#333333' );
}
}
Variables vs Preprocessor Variables
Feature CSS Variables Sass/Less Variables Browser Support Modern browsers Compile to CSS Dynamic Yes, can change at runtime No, fixed at compile JavaScript Access Yes No Inheritance Yes, cascades No Scope Can be scoped File/block scope Calc() Works with calc() Limited
CSS Variables are native and dynamic. Preprocessor variables (Sass/Less) are compile-time and more powerful for complex logic, but can’t change at runtime.
Common Patterns
Component Variations
.card {
--card-bg : var ( --color-white );
--card-border : var ( --color-gray-200 );
background-color : var ( --card-bg );
border : 1 px solid var ( --card-border );
}
.card--dark {
--card-bg : var ( --color-gray-600 );
--card-border : var ( --color-gray-500 );
}
.card--primary {
--card-bg : var ( --color-primary );
--card-border : var ( --color-primary-dark );
}
Responsive Spacing
:root {
--section-padding : var ( --spacing-xl );
}
@media ( max-width : 768 px ) {
:root {
--section-padding : var ( --spacing-md );
}
}
.section {
padding : var ( --section-padding );
/* Automatically adjusts on mobile */
}
Color Variations
:root {
--primary-h : 52 ; /* Hue */
--primary-s : 100 % ; /* Saturation */
--primary-l : 50 % ; /* Lightness */
--color-primary : hsl ( var ( --primary-h ), var ( --primary-s ), var ( --primary-l ));
--color-primary-light : hsl ( var ( --primary-h ), var ( --primary-s ), 70 % );
--color-primary-dark : hsl ( var ( --primary-h ), var ( --primary-s ), 40 % );
}
Best Practices
Use semantic names that describe purpose, not appearance
Create a consistent scale (colors, spacing, typography)
Define global variables in :root
Use fallback values for critical variables
Group related variables together in comments
Don’t overuse variables - only create them for values you’ll reuse
Avoid deeply nested variable references - can be hard to debug
Organization Tips
:root {
/* ========================================
* COLORS
* ======================================== */
--color-primary : #FFE600 ;
--color-secondary : #3483FA ;
/* ... */
/* ========================================
* TYPOGRAPHY
* ======================================== */
--font-family-base : sans-serif ;
--font-size-base : 1 rem ;
/* ... */
/* ========================================
* SPACING
* ======================================== */
--spacing-xs : 0.25 rem ;
--spacing-sm : 0.5 rem ;
/* ... */
/* ========================================
* LAYOUT
* ======================================== */
--container-max-width : 1200 px ;
--header-height : 120 px ;
/* ... */
}
Browser Support
CSS Variables are supported in all modern browsers:
Chrome 49+
Firefox 31+
Safari 9.1+
Edge 15+
IE11 does not support CSS variables. Use fallbacks or PostCSS if you need IE11 support.
Fallback for Older Browsers
.button {
background-color : #3483FA ; /* Fallback */
background-color : var ( --color-secondary ); /* Modern */
}
Complete Example: Design System
:root {
/* Colors */
--color-primary : #FFE600 ;
--color-primary-dark : #F5D300 ;
--color-secondary : #3483FA ;
--color-secondary-dark : #2968C8 ;
--color-success : #00A650 ;
--color-error : #F23D4F ;
--color-gray-100 : #F5F5F5 ;
--color-gray-600 : #333333 ;
--color-white : #FFFFFF ;
/* Typography */
--font-family-base : -apple-system , BlinkMacSystemFont, sans-serif ;
--font-size-sm : 0.875 rem ;
--font-size-base : 1 rem ;
--font-size-xl : 1.25 rem ;
/* Spacing */
--spacing-xs : 0.25 rem ;
--spacing-sm : 0.5 rem ;
--spacing-md : 1 rem ;
--spacing-lg : 1.5 rem ;
--spacing-xl : 2 rem ;
/* Borders */
--border-radius-sm : 4 px ;
--border-radius-md : 8 px ;
/* Shadows */
--shadow-sm : 0 1 px 3 px rgba ( 0 , 0 , 0 , 0.1 );
--shadow-lg : 0 10 px 25 px rgba ( 0 , 0 , 0 , 0.15 );
/* Transitions */
--transition-fast : 150 ms ease ;
--transition-base : 300 ms ease ;
}
/* Usage throughout the app */
.button {
padding : var ( --spacing-sm ) var ( --spacing-lg );
background-color : var ( --color-secondary );
color : var ( --color-white );
font-family : var ( --font-family-base );
font-size : var ( --font-size-base );
border-radius : var ( --border-radius-sm );
transition : background-color var ( --transition-fast );
}
.button:hover {
background-color : var ( --color-secondary-dark );
}
.card {
background-color : var ( --color-white );
padding : var ( --spacing-lg );
border-radius : var ( --border-radius-md );
box-shadow : var ( --shadow-sm );
}
.card:hover {
box-shadow : var ( --shadow-lg );
}
Next Steps
Animations Use variables in animations
Responsive Design Make variables responsive