¿Cansado de cambiar colores y valores en 50 lugares diferentes cada vez que quieres modificar tu diseño? Las CSS Variables (Custom Properties) son la solución moderna para crear diseños dinámicos, themes cambiables y componentes reutilizables sin tocar una línea de JavaScript.
En este tutorial aprenderás a dominar las CSS Variables desde cero hasta casos de uso avanzados, con proyectos prácticos que podrás aplicar inmediatamente en tus proyectos.
🎯 ¿Qué vas a aprender?
- Qué son las CSS Variables y cómo funcionan
- Diferencia entre CSS Variables y variables de Sass/SCSS
- Crear un theme switcher completo (claro/oscuro)
- Responsive design avanzado con variables
- Animaciones dinámicas usando solo CSS
🤔 El Problema que Resuelven
Imagina que tienes una web con un color principal azul (#3498db) usado en 50 lugares diferentes: botones, enlaces, borders, backgrounds...
Un día el cliente dice: "Quiero cambiar todo a verde".
/* Tienes que cambiar en 50 lugares diferentes */
.button {
background: #3498db; /* Cambiar aquí */
}
.link {
color: #3498db; /* Y aquí */
}
.border {
border-color: #3498db; /* Y aquí también... */
}
/* ...47 más lugares 😱 */
Con CSS Variables, cambias una sola línea y automáticamente se actualiza en todos lados.
🔍 ¿Qué son las CSS Variables?
Las CSS Custom Properties (conocidas como CSS Variables) son una funcionalidad nativa de CSS que te permite:
- Definir valores reutilizables en un lugar
- Cambiarlos dinámicamente con JavaScript (si quieres)
- Heredarlos a través del DOM
- Usarlos en cálculos con calc()
/* 1. Definir la variable */
:root {
--color-primary: #3498db;
--spacing-large: 2rem;
--font-size-h1: 2.5rem;
}
/* 2. Usar la variable con var() */
.button {
background: var(--color-primary);
padding: var(--spacing-large);
}
💡 Nomenclatura: ¿Por qué dos guiones?
Los nombres de CSS Variables siempre empiezan con --. Esto les dice al navegador "esto es una custom property". Puedes usar cualquier nombre después: --mi-color, --main-bg, --button-hover-color, etc.
⚡ CSS Variables vs Variables de Sass
Si has usado Sass o SCSS, ya conoces las variables. Pero las CSS Variables tienen superpoderes que Sass no tiene:
Se pueden cambiar en runtime
Solo en tiempo de compilación
Respetan la cascada de CSS
No entienden de herencia
Perfectas para themes dinámicos
JavaScript no puede tocarlas
No necesitas compiladores
Sass/SCSS → CSS
/* Sass Variables */
$primary-color: #3498db;
.button {
background: $primary-color; // Se convierte a #3498db
}
/* CSS Variables */
:root {
--primary-color: #3498db;
}
.button {
background: var(--primary-color); /* Permanece como variable */
}
🎨 Casos de Uso Básicos
1. Sistema de Colores
El uso más común: definir una paleta de colores consistente.
:root {
/* Colores principales */
--color-primary: #3498db;
--color-secondary: #2ecc71;
--color-accent: #e74c3c;
/* Grises */
--color-text-dark: #2c3e50;
--color-text-light: #7f8c8d;
--color-bg-light: #ecf0f1;
/* Estados */
--color-success: #27ae60;
--color-warning: #f39c12;
--color-danger: #e74c3c;
}
/* Uso en componentes */
.btn-primary {
background: var(--color-primary);
color: white;
}
.alert-success {
background: var(--color-success);
border: 2px solid var(--color-success);
}
2. Sistema de Espaciado
Mantén consistencia en márgenes, paddings y gaps.
:root {
/* Sistema de espaciado (escala 8pt) */
--spacing-xs: 0.25rem; /* 4px */
--spacing-sm: 0.5rem; /* 8px */
--spacing-md: 1rem; /* 16px */
--spacing-lg: 1.5rem; /* 24px */
--spacing-xl: 2rem; /* 32px */
--spacing-xxl: 3rem; /* 48px */
}
.card {
padding: var(--spacing-lg);
margin-bottom: var(--spacing-md);
}
.button {
padding: var(--spacing-sm) var(--spacing-md);
}
3. Tipografía
:root {
/* Fuentes */
--font-primary: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
--font-mono: 'Fira Code', 'Courier New', monospace;
/* Tamaños */
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--font-size-lg: 1.125rem;
--font-size-xl: 1.25rem;
--font-size-h1: 2.5rem;
/* Pesos */
--font-weight-normal: 400;
--font-weight-medium: 500;
--font-weight-bold: 700;
}
🔄 Herencia y Cascada
Una de las características más potentes de las CSS Variables es que respetan la herencia CSS. Esto significa que puedes definir diferentes valores para diferentes partes de tu HTML.
/* Variables globales */
:root {
--button-color: #3498db;
}
/* Variables específicas para la sidebar */
.sidebar {
--button-color: #2c3e50;
}
/* Variables para alertas de éxito */
.alert-success {
--button-color: #27ae60;
}
/* El botón usa siempre la misma regla */
.button {
background: var(--button-color);
}
<!-- Botón azul (usa :root) -->
<button class="button">Botón Normal</button>
<!-- Botón gris oscuro (hereda de .sidebar) -->
<div class="sidebar">
<button class="button">Botón Sidebar</button>
</div>
<!-- Botón verde (hereda de .alert-success) -->
<div class="alert-success">
<button class="button">¡Éxito!</button>
</div>
🤓 ¿Por qué es esto genial?
Con clases tradicionales necesitarías: .button, .button-sidebar,
.button-success... Con variables, un solo componente .button
se adapta automáticamente al contexto.
🎨 Proyecto Práctico: Theme Switcher
Vamos a crear un sistema completo de themes claro/oscuro usando solo CSS Variables. Cero JavaScript necesario para los estilos (solo para el botón de cambio).
Paso 1: Definir las Variables del Theme
:root {
/* Theme claro (por defecto) */
--bg-primary: #ffffff;
--bg-secondary: #f8f9fa;
--text-primary: #212529;
--text-secondary: #6c757d;
--border-color: #dee2e6;
--shadow-color: rgba(0, 0, 0, 0.1);
/* Colores de acento (no cambian) */
--color-primary: #007bff;
--color-success: #28a745;
--color-danger: #dc3545;
}
/* Theme oscuro */
[data-theme="dark"] {
--bg-primary: #1a1a1a;
--bg-secondary: #2d2d2d;
--text-primary: #ffffff;
--text-secondary: #b0b0b0;
--border-color: #404040;
--shadow-color: rgba(0, 0, 0, 0.3);
}
Paso 2: Aplicar las Variables
body {
background-color: var(--bg-primary);
color: var(--text-primary);
transition: background-color 0.3s ease, color 0.3s ease;
}
.card {
background: var(--bg-secondary);
border: 1px solid var(--border-color);
box-shadow: 0 2px 10px var(--shadow-color);
transition: all 0.3s ease;
}
.text-muted {
color: var(--text-secondary);
}
input, textarea {
background: var(--bg-primary);
color: var(--text-primary);
border: 1px solid var(--border-color);
}
Paso 3: El Botón Toggle (Solo JavaScript necesario)
// JavaScript mínimo para cambiar theme
function toggleDemoTheme() {
const demo = document.querySelector('.theme-demo');
const currentTheme = demo.getAttribute('data-theme');
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
demo.setAttribute('data-theme', newTheme);
const button = demo.querySelector('.theme-toggle');
button.textContent = newTheme === 'dark' ? '☀️ Cambiar Theme' : '🌙 Cambiar Theme';
}
🎭 Demo del Theme Switcher
Card de ejemplo
Texto secundario que cambia automáticamente
📱 Responsive Design con Variables
Las CSS Variables revolucionan el responsive design. **En lugar de redefinir cada propiedad en cada breakpoint**, cambias solo las variables y todos tus componentes se adaptan automáticamente.
🚀 El superpoder del responsive con variables
**Método tradicional:** Redefinir `.card { padding: 2rem; }` en cada media query.
**Con variables:** Cambiar solo `--card-padding: 2rem` y **automáticamente** todos los
cards, modales, forms que usen esa variable se adaptan. ¡Un cambio, 50 componentes actualizados!
:root {
/* Mobile first */
--container-padding: 1rem;
--grid-gap: 1rem;
--font-size-h1: 1.8rem;
--card-padding: 1rem;
}
/* Tablet */
@media (min-width: 768px) {
:root {
--container-padding: 2rem;
--grid-gap: 1.5rem;
--font-size-h1: 2.2rem;
--card-padding: 1.5rem;
}
}
/* Desktop */
@media (min-width: 1024px) {
:root {
--container-padding: 3rem;
--grid-gap: 2rem;
--font-size-h1: 2.8rem;
--card-padding: 2rem;
}
}
/* Los componentes nunca cambian */
.container {
padding: var(--container-padding);
}
.grid {
gap: var(--grid-gap);
}
h1 {
font-size: var(--font-size-h1);
}
.card {
padding: var(--card-padding);
}
🤯 ¿Te das cuenta del poder?
Cambias 4 variables en 3 breakpoints y automáticamente todos tus componentes se adaptan. Sin duplicar código, sin clases responsive adicionales.
✨ Animaciones Dinámicas
Las CSS Variables pueden animarse, y esto abre un mundo de posibilidades para crear animaciones que se adaptan dinámicamente.
Progreso Dinámico con CSS Variables
Las CSS Variables brillan en barras de progreso porque puedes controlarlas de 3 formas diferentes. Vamos a ver todos los enfoques:
/* Variables necesarias */
:root {
--demo-secondary: #2ecc71;
--demo-spacing-md: 1rem;
}
.progress-bar {
--progress: 0%;
width: 100%;
max-width: 400px;
height: 24px;
background: #e0e0e0;
border-radius: 12px;
overflow: hidden;
position: relative;
margin: 0 auto var(--demo-spacing-md);
}
.progress-bar::before {
content: '';
position: absolute;
top: 0;
left: 0;
height: 100%;
width: var(--progress); /* ¡La magia! */
background: linear-gradient(90deg, var(--demo-secondary), #27ae60);
transition: width 0.5s ease;
border-radius: 12px;
}
/* Estados de progreso */
.progress-25 { --progress: 25%; }
.progress-50 { --progress: 50%; }
.progress-75 { --progress: 75%; }
.progress-100 { --progress: 100%; }
🎯 Enfoque 1: Estados Fijos (Para UI componentes)
Cuándo usar: Cuando tienes estados predefinidos o trabajas con frameworks como React/Vue.
/* Estados predefinidos */
.progress-25 { --progress: 25%; }
.progress-50 { --progress: 50%; }
.progress-75 { --progress: 75%; }
/* Uso en HTML */
<div class="progress-bar progress-50"></div>
⚡ Enfoque 2: JavaScript Dinámico (Para datos reales)
Cuándo usar: Con APIs, formularios, uploads. Cualquier valor entre 0-100%.
// Cambio directo del valor
function updateProgress(element, percentage) {
element.style.setProperty('--progress', percentage + '%');
}
// Ejemplo práctico
const progressBar = document.querySelector('.progress-bar');
updateProgress(progressBar, 67); // 67%
✨ Enfoque 3: Animación CSS Automática (Para efectos visuales)
Cuándo usar: Loading screens, demos, efectos visuales, onboarding.
/* ¡Aquí está la verdadera MAGIA! */
@keyframes progress-fill {
from { --progress: 0%; }
to { --progress: 100%; }
}
.progress-animated {
animation: progress-fill 3s ease-in-out infinite;
}
.progress-animated-once {
animation: progress-fill 2s ease-out forwards;
}
<!-- CSS completo -->
<style>
:root {
--demo-secondary: #2ecc71;
--demo-spacing-md: 1rem;
}
.progress-bar {
--progress: 0%;
width: 100%; max-width: 400px; height: 24px;
background: #e0e0e0; border-radius: 12px;
overflow: hidden; position: relative;
margin: 0 auto var(--demo-spacing-md);
}
.progress-bar::before {
content: ''; position: absolute; top: 0; left: 0; height: 100%;
width: var(--progress);
background: linear-gradient(90deg, var(--demo-secondary), #27ae60);
transition: width 0.5s ease; border-radius: 12px;
}
.progress-25 { --progress: 25%; }
.progress-50 { --progress: 50%; }
@keyframes progress-fill { from { --progress: 0%; } to { --progress: 100%; } }
.progress-animated { animation: progress-fill 3s infinite; }
</style>
<!-- HTML -->
<div class="progress-bar progress-25"></div>
<div class="progress-bar progress-50"></div>
<div class="progress-bar" id="dynamic"></div>
<button onclick="document.getElementById('dynamic').style.setProperty('--progress','67%')">67%</button>
<div class="progress-bar progress-animated"></div>
🎯 Demo - Los 3 Enfoques en Acción
📌 1. Estados Fijos (CSS):
Valores predefinidos con clases CSS
🎮 2. Control JavaScript:
Cualquier valor dinámico 0-100%
✨ 3. Animación Automática:
¡Aquí está la magia visual que esperabas!
Arriba: Se anima una vez | Abajo: Loop infinito
Hover Effects Dinámicos
Los efectos hover son perfectos para mostrar el poder de las CSS Variables. En lugar de definir hover para cada variante de botón, **defines las variables una vez y ellas se encargan de todo**.
🤓 ¿Por qué es genial este enfoque?
**Sin variables:** Necesitarías .btn-primary:hover, .btn-success:hover,
.btn-danger:hover... **Con variables:** Un solo .dynamic-button:hover
funciona para todos, pero cada uno cambia a su color específico.
.dynamic-button {
/* Variables por defecto */
--btn-bg: var(--demo-primary);
--btn-hover-bg: #2980b9;
--btn-scale: 1;
--btn-shadow: 0 2px 5px rgba(0,0,0,0.2);
background: var(--btn-bg);
transform: scale(var(--btn-scale));
box-shadow: var(--btn-shadow);
transition: all 0.3s ease;
border: none;
padding: 12px 24px;
color: white;
cursor: pointer;
border-radius: 6px;
}
.dynamic-button:hover {
--btn-bg: var(--btn-hover-bg);
--btn-scale: 1.05;
--btn-shadow: 0 4px 15px rgba(0,0,0,0.3);
}
/* Variantes del botón */
.btn-success {
--btn-bg: var(--demo-secondary);
}
.btn-danger {
--btn-bg: var(--demo-danger);
}
/* Hovers específicos para mayor especificidad */
.dynamic-button.btn-success:hover {
--btn-bg: #1e7e34;
}
.dynamic-button.btn-danger:hover {
--btn-bg: #a71e2a;
}
✨ Demo de Animaciones
🚀 Casos de Uso Avanzados
1. Componentes Context-Aware
Componentes que cambian según su contexto sin clases adicionales.
/* El botón base */
.smart-button {
background: var(--context-color, #666);
border: 2px solid var(--context-color, #666);
}
/* Contextos diferentes */
.header {
--context-color: #fff;
}
.sidebar {
--context-color: #2c3e50;
}
.alert-warning {
--context-color: #f39c12;
}
.card-pricing {
--context-color: #8e44ad;
}
2. Matemáticas con calc()
Combina variables en cálculos complejos.
:root {
--base-size: 16px;
--scale-ratio: 1.25;
--sidebar-width: 250px;
--header-height: 60px;
}
/* Tipografía escalada */
h1 {
font-size: calc(var(--base-size) * var(--scale-ratio) * var(--scale-ratio));
}
h2 {
font-size: calc(var(--base-size) * var(--scale-ratio));
}
/* Layout calculado */
.main-content {
width: calc(100vw - var(--sidebar-width));
height: calc(100vh - var(--header-height));
}
3. Variables Fallback
Valores por defecto cuando una variable no está definida.
.component {
/* Si --primary-color no existe, usa #007bff */
color: var(--primary-color, #007bff);
/* Fallback en cadena */
font-family: var(--font-custom, var(--font-system, system-ui));
/* Cálculos con fallback */
padding: calc(var(--spacing-unit, 8px) * 2);
}
✅ Mejores Prácticas
Nomenclatura Consistente
/* ✅ Bueno */
--color-primary
--color-secondary
--spacing-sm
--spacing-lg
--font-size-h1
/* ❌ Malo */
--primary
--blueColor
--small-space
--titleSize
Organización por Categorías
:root {
/* === COLORES === */
--color-primary: #007bff;
--color-secondary: #6c757d;
/* === TIPOGRAFÍA === */
--font-primary: 'Inter', sans-serif;
--font-size-base: 1rem;
/* === ESPACIADO === */
--spacing-xs: 0.25rem;
--spacing-sm: 0.5rem;
/* === LAYOUT === */
--container-max-width: 1200px;
--sidebar-width: 250px;
}
Performance: Limita las Variables
No defines variables para todo. Solo para valores que:
- Se reutilizan en múltiples lugares
- Pueden cambiar dinámicamente
- Forman parte de un sistema (colores, espaciado)
- Necesitan cálculos matemáticos
Usa Fallbacks Siempre
/* ✅ Siempre con fallback */
.component {
color: var(--text-color, #333);
padding: var(--padding, 1rem);
}
/* ❌ Sin fallback = riesgo */
.component {
color: var(--text-color);
}
🌐 Compatibilidad y Soporte
✅ Soporte Excelente
- Chrome: 49+ (2016)
- Firefox: 31+ (2014)
- Safari: 9.1+ (2016)
- Edge: 16+ (2017)
🛡️ Estrategia de Fallback
/* Para navegadores muy antiguos */
.button {
background: #007bff; /* Fallback */
background: var(--primary-color); /* Variable */
}
📊 En resumen: ¿Vale la pena?
¡Absolutamente sí! Con más del 95% de soporte global, las CSS Variables son la herramienta más potente para crear diseños mantenibles y dinámicos. Si estás desarrollando para web moderna, no hay excusa para no usarlas.
🏗️ Proyecto Final: Dashboard Completo
Vamos a crear un mini-dashboard que combine todo lo aprendido: themes dinámicos, responsive design y animaciones.
.dashboard-demo {
/* === THEME SYSTEM === */
--dash-bg-primary: #ffffff;
--dash-bg-secondary: #f8f9fa;
--dash-text-primary: #212529;
--dash-text-secondary: #6c757d;
--dash-border: #dee2e6;
--dash-shadow: rgba(0, 0, 0, 0.1);
/* === RESPONSIVE === */
--dash-sidebar-width: 200px;
--dash-card-padding: var(--demo-spacing-lg);
--dash-grid-gap: var(--demo-spacing-md);
/* Layout */
display: grid;
grid-template-columns: var(--dash-sidebar-width) 1fr;
background: var(--dash-bg-primary);
}
/* Dark Theme */
.dashboard-demo[data-theme="dark"] {
--dash-bg-primary: #1a1a1a;
--dash-bg-secondary: #2d2d2d;
--dash-text-primary: #ffffff;
--dash-text-secondary: #b0b0b0;
--dash-border: #404040;
--dash-shadow: rgba(0, 0, 0, 0.3);
}
/* Responsive Layout (sin variables adicionales) */
@media (max-width: 768px) {
.dashboard-demo {
grid-template-columns: 1fr;
--dash-sidebar-width: auto;
}
.dashboard-sidebar {
border-right: none;
border-bottom: 1px solid var(--dash-border);
}
}
🎯 Dashboard Demo
Dashboard
Usuarios
Ventas
Pedidos
🎯 Resumen y Próximos Pasos
✅ Lo que has aprendido
- Sintaxis y conceptos básicos de CSS Variables
- Diferencias con variables de preprocesadores
- Sistema de themes dinámicos
- Responsive design con variables
- Animaciones y transiciones dinámicas
- Mejores prácticas y organización
🚀 Próximos pasos
- Implementa un theme switcher en tu proyecto actual
- Refactoriza tu CSS usando variables para colores y espaciado
- Experimenta con animaciones usando variables
- Crea un design system completo
- Explora CSS Grid + Variables para layouts avanzados
💡 El takeaway más importante
Las CSS Variables no son solo una "feature nueva" - son un cambio de paradigma. Te permiten pensar en CSS de forma más dinámica y sistemática. Una vez que las domines, no podrás volver a CSS estático.
🚀 ¿Te ha gustado este tutorial?
Las CSS Variables son solo el comienzo. Únete a StudyCode Pro para más tutoriales como este, roadmaps completos y una comunidad que te ayudará a conseguir tu primer trabajo como Frontend Developer.
📬 Únete Gratis