1. Variables CSS (Custom Properties)

Las variables CSS permiten almacenar valores que se reusan en toda la hoja de estilos. Se declaran con el prefijo -- y se leen con la función var().

Diferencia con variables de preprocesadores (SASS/LESS): las Custom Properties de CSS son en vivo: pueden cambiar con JavaScript, respetan la herencia del DOM y funcionan sin compilación.

Declaración en :root

Al declarar variables en :root quedan disponibles en todo el documento. Es el patrón más común para colores, tipografías y espaciados globales.

:root {
  --color-primario:   #1a3a4a;
  --color-secundario: #2d7d5f;
  --espacio-md:       1rem;
  --fuente-titulos:   'Georgia', serif;
}

/* Uso */
h1 {
  color: var(--color-primario);
  font-family: var(--fuente-titulos);
  margin-bottom: var(--espacio-md);
}

Herencia y sobreescritura local

Las variables CSS se heredan por el árbol DOM. Un descendiente puede redefinir la variable localmente, afectando solo a sí mismo y sus hijos.

/* Variable global en :root */
:root { --color-demo: navy; }

/* Sobreescritura en un elemento específico */
.hijo.verde { --color-demo: green; }
.hijo.ambar { --color-demo: orange; }

/* Los tres hijos leen la misma propiedad: var(--color-demo)
   pero cada uno tiene un valor diferente */
.hijo { background: var(--color-demo); }
var(--color-demo) → hereda del :root (azul marino)
var(--color-demo) → sobreescrito a verde
var(--color-demo) → sobreescrito a ámbar
var(--color-demo) → sobreescrito a lila

Valor de respaldo (fallback)

Si una variable no está definida, var() acepta un segundo argumento como valor de respaldo:

/* Si --color-inexistente no existe, usa el fallback */
background: var(--color-inexistente, red);

/* Fallback encadenado */
color: var(--color-a, var(--color-b, black));
var(--color-inexistente, #a02020)
usa el fallback
var(--color-secundario)
usa la variable definida
var(--color-local)
variable local al elemento

Comparativa: con y sin variables

✅ Con variables CSS
:root {
  --azul: #1a3a4a;
}

h1 { color: var(--azul); }
nav { background: var(--azul); }
.btn { border: 2px solid var(--azul); }

/* Cambiar un color: una sola línea */
❌ Sin variables CSS
/* Sin variables */

h1 { color: #1a3a4a; }
nav { background: #1a3a4a; }
.btn { border: 2px solid #1a3a4a; }

/* Cambiar: buscar y reemplazar N veces */

Referencia de tipos de valor

Tipo de valor Ejemplo de variable Valor de ejemplo
Color--color-primario#1a3a4a
Longitud--espacio-md1rem
Fuente--fuente-titulos'Georgia', serif
Sombra--sombra-md0 4px 12px rgba(0,0,0,0.1)
Tiempo--duracion-media300ms
Número--z-modal1000

2. Pseudo-clases y Pseudo-elementos

Las pseudo-clases seleccionan un estado del elemento (:hover, :focus) o su posición en el DOM (:nth-child). Los pseudo-elementos seleccionan una parte del elemento o insertan contenido decorativo (::before, ::after).

Pseudo-clases de estado de interacción

Pasa el cursor, haz clic o escribe en el campo para ver los efectos.

:hover

Pasa el cursor
.btn:hover {
  background: green;
  transform: translateY(-3px);
}

:focus

.input:focus {
  border-color: green;
  box-shadow: 0 0 0 3px ...;
}

:active

Mantén presionado
.btn:active {
  transform: translateY(3px);
  box-shadow: 0 1px 0 ...;
}

Pseudo-clases estructurales

:nth-child()

  • Ítem 1 — :first-child
  • Ítem 2 — :nth-child(even)
  • Ítem 3
  • Ítem 4 — :nth-child(even)
  • Ítem 5 — :last-child

:not()

  • Normal
  • Especial ✓
  • Normal
  • Especial ✓
  • Normal
li:not(.especial) {
  opacity: 0.5;
}

Pseudo-clases de formularios

input:focus    { border-color: green; }
input:disabled { opacity: 0.5; cursor: not-allowed; }
input:required { border-left: 3px solid red; }
input:valid    { border-color: green; }
input:invalid  { border-color: red; }

Pseudo-elementos ::before y ::after

Insertan contenido decorativo antes o después del contenido del elemento. Requieren la propiedad content (puede ser vacía: "").

Primera idea importante

Segunda idea importante

Tercera idea importante

p::before {
  content: "→";        /* texto, emoji, o vacío "" */
  position: absolute;
  left: 0;
  color: orange;
}

Cita decorada con ::before y ::after

Las variables CSS y las animaciones son las herramientas más poderosas para crear interfaces expresivas sin JavaScript.
.cita::before {
  content: "\201C";  /* " tipográfico */
  font-size: 3rem;
  color: orange;
}

.cita::after {
  content: "\201D";  /* " tipográfico */
}

::placeholder, ::selection, ::first-letter

Selecciona este texto para ver el efecto ::selection personalizado. La primera letra usa ::first-letter para crear una letra capital decorativa, como en los manuscritos medievales.

Este párrafo tiene su primera línea estilizada con ::first-line: color verde y mayor espaciado entre letras. Este efecto se aplica de forma inteligente según el ancho real del contenedor.

PseudoQué seleccionaCaso de uso
::beforeAntes del contenidoIconos, decoraciones, contadores
::afterDespués del contenidoTooltips, clearfix, decoraciones
::placeholderTexto de ayuda en inputsEstilo del hint de formularios
::selectionTexto seleccionadoBranding en la selección de texto
::first-letterPrimera letraLetra capital en artículos
::first-linePrimera línea visibleÉnfasis tipográfico en párrafos

3. Transiciones

La propiedad transition anima automáticamente el cambio entre dos estados CSS. Solo necesitas definir el estado inicial y el estado final (:hover, :focus, etc.) y el navegador calcula los fotogramas intermedios.

/* Sintaxis completa */
transition: propiedad duración timing-function retraso;

/* Ejemplos */
transition: background 300ms ease;
transition: transform 600ms cubic-bezier(0.34, 1.56, 0.64, 1);
transition: all 200ms ease-in-out;

/* Múltiples propiedades */
transition:
  background 300ms ease,
  transform  400ms cubic-bezier(0.34, 1.56, 0.64, 1),
  box-shadow 300ms ease;

Curvas de tiempo (timing functions)

Pasa el cursor sobre cada caja para comparar las curvas:

ease lento → rápido → lento
ease-in arranca lento
ease-out frena al final
linear velocidad constante
cubic-bezier efecto de rebote
steps(5) pasos discretos

Transición con múltiples propiedades

Cada propiedad puede tener su propia curva y duración:

Múltiples propiedades background + transform + box-shadow + border-radius
.trans-multiple {
  transition:
    background    300ms ease,
    transform     300ms cubic-bezier(0.34, 1.56, 0.64, 1),
    box-shadow    300ms ease,
    border-radius 300ms ease;
}

.trans-multiple:hover {
  background:    green;
  transform:     rotate(-3deg) scale(1.05);
  box-shadow:    0 8px 24px rgba(0,0,0,0.12);
  border-radius: 999px;
}

transition-delay: efecto cascada

Pasa el cursor sobre el grupo para ver el efecto de entrada escalonada:

.item:nth-child(1) { transition-delay: 0ms; }
.item:nth-child(2) { transition-delay: 80ms; }
.item:nth-child(3) { transition-delay: 160ms; }
.item:nth-child(4) { transition-delay: 240ms; }
.item:nth-child(5) { transition-delay: 320ms; }

Regla de oro: usa transition en el estado base del elemento, no en el :hover. Así la animación también ocurre al salir del estado.

4. Animaciones @keyframes

Mientras las transiciones requieren un cambio de estado externo (hover, focus), las animaciones se reproducen de forma autónoma. Se definen con @keyframes y se aplican con la propiedad animation.

/* 1. Definir la animación */
@keyframes nombre {
  from { transform: scale(1); }
  to   { transform: scale(1.1); }
}

/* Con porcentajes para mayor control */
@keyframes rebotar {
  0%, 100% { transform: translateY(0);     }
  50%       { transform: translateY(-30px); }
}

/* 2. Aplicar la animación */
.elemento {
  animation: nombre 1.5s ease-in-out infinite;
  /* nombre | duración | timing | iteración */
}

Propiedades individuales de animation

PropiedadValores comunesDescripción
animation-namenombre del @keyframesQué animación usar
animation-duration1s, 300msDuración total
animation-timing-functionease, linear, cubic-bezierCurva de velocidad
animation-delay0ms, 200msRetraso antes de iniciar
animation-iteration-count1, 3, infiniteNúmero de repeticiones
animation-directionnormal, reverse, alternateDirección de reproducción
animation-fill-modenone, forwards, backwards, bothEstado antes/después
animation-play-staterunning, pausedReproducir o pausar

Demos de animaciones básicas

pulso
ease-in-out infinite
girar
linear infinite
rebotar
ease infinite
parpadeo
ease-in-out infinite
colorCiclico
linear infinite

animation-fill-mode: forwards — entrada escalonada

fill-mode: both aplica los estilos del primer fotograma antes de que inicie y mantiene los del último al terminar. Ideal para animaciones de entrada que se ejecutan una sola vez:

animation-delay: 0ms
animation-delay: 150ms
animation-delay: 300ms
animation-delay: 450ms
@keyframes deslizarDesdeIzq {
  from { opacity: 0; transform: translateX(-30px); }
  to   { opacity: 1; transform: translateX(0); }
}

.item { animation: deslizarDesdeIzq 600ms ease both; }
.item:nth-child(2) { animation-delay: 150ms; }
.item:nth-child(3) { animation-delay: 300ms; }

Animación de texto en onda

CSS   Avanzado
/* Cada letra es un  con animation-delay distinto */
.letra { animation: ondaTexto 1.2s ease-in-out infinite; }
.letra:nth-child(1) { animation-delay: 0ms; }
.letra:nth-child(2) { animation-delay: 80ms; }
/* ... */

animation-play-state: pausa interactiva

Pasa el cursor sobre el spinner para pausarlo:

.contenedor:hover .spinner {
  animation-play-state: paused;
}

Accesibilidad: siempre incluye @media (prefers-reduced-motion: reduce) para respetar la preferencia del sistema operativo del usuario. Las animaciones excesivas pueden causar malestar a personas con trastornos vestibulares.

5. Transform y Filter

transform — sin alterar el flujo

transform mueve, escala, rota o inclina un elemento sin afectar el espacio que ocupa en el layout. El resto de elementos no se mueven. Por eso es ideal para animaciones (y más eficiente que animar top/left).

Pasa el cursor sobre cada caja para ver la transformación:

translate(10px, -10px)
scale(1.5)
rotate(45deg)
skew(20deg, 10deg)
rotate + scale + translateY
transform-origin: bottom left
/* transform-origin cambia el punto de pivote */
.elemento {
  transform-origin: center center; /* por defecto */
  transform-origin: top left;
  transform-origin: bottom right;
  transform-origin: 25% 75%;
}

/* Combinar transformaciones (el orden importa) */
transform: rotate(45deg) scale(1.2) translateX(10px);

Rendimiento: transform y opacity son las dos propiedades CSS más eficientes de animar porque se procesan en la GPU (compositor), no en el hilo principal del navegador.

filter — efectos de imagen en CSS puro

Pasa el cursor sobre cada caja para ver el filtro aplicado:

blur(4px)
brightness(1.6)
contrast(2)
grayscale(100%)
sepia(100%)
hue-rotate(180deg)
saturate(0.2)
invert(100%)
/* Filtros individuales */
filter: blur(4px);
filter: brightness(150%);
filter: grayscale(100%);

/* Filtros combinados */
filter: brightness(1.2) contrast(1.1) saturate(1.3);

/* Truco hover en imágenes */
img { filter: grayscale(80%); transition: filter 300ms ease; }
img:hover { filter: grayscale(0%); }

backdrop-filter — efecto glassmorphism

backdrop-filter aplica filtros al contenido detrás del elemento. Requiere que el elemento tenga fondo semitransparente.

Glassmorphism

backdrop-filter: blur(12px)

.tarjeta-vidrio {
  background: rgba(255, 255, 255, 0.15);  /* semitransparente */
  backdrop-filter: blur(12px) saturate(1.8);
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 16px;
}

6. Proyecto aplicado — Tarjetas interactivas

Este componente combina todos los conceptos de la semana: variables CSS locales por tarjeta, pseudo-elementos para decoración, transiciones suaves, animaciones de entrada y efectos transform.

Conceptos aplicados: variables CSS con --tarjeta-acento sobreescrita por tarjeta · ::before para el borde superior · ::after para el círculo de fondo · animation: aparecer-tarjeta con delay escalonado · transition: transform + box-shadow en hover · :nth-child para colores distintos · :hover en hijos descendientes.

🎨

Variables CSS

Propiedades personalizadas que permiten theming dinámico y mantenimiento centralizado.

:root var() herencia
🎯

Pseudo-selectores

Selección de estados y posiciones sin agregar clases o markup extra al HTML.

:hover ::before :nth-child

Transiciones

Cambios de estado suaves y fluidos con control total sobre la curva de velocidad.

ease cubic-bezier delay

Animaciones

Secuencias de fotogramas clave que se ejecutan de forma autónoma, sin JavaScript.

@keyframes forwards infinite

Código del componente (simplificado)

/* Variable local por tarjeta → sobreescribe la global */
.tarjeta:nth-child(1) { --tarjeta-acento: navy;   }
.tarjeta:nth-child(2) { --tarjeta-acento: green;  }
.tarjeta:nth-child(3) { --tarjeta-acento: orange; }

/* ::before → borde de color superior */
.tarjeta::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0; height: 4px;
  background: var(--tarjeta-acento);
}

/* ::after → círculo decorativo de fondo */
.tarjeta::after {
  content: "";
  position: absolute; bottom: -30px; right: -30px;
  width: 100px; height: 100px;
  background: var(--tarjeta-acento);
  border-radius: 50%;
  opacity: 0.07;
  transition: transform 600ms cubic-bezier(0.34,1.56,0.64,1);
}

/* Hover: eleva la tarjeta y expande el círculo */
.tarjeta:hover { transform: translateY(-6px); }
.tarjeta:hover::after { transform: scale(2.5); opacity: 0.12; }

/* Animación de entrada con delay escalonado */
.tarjeta { animation: aparecer 600ms ease both; }
.tarjeta:nth-child(2) { animation-delay: 100ms; }
.tarjeta:nth-child(3) { animation-delay: 200ms; }
.tarjeta:nth-child(4) { animation-delay: 300ms; }