Tema
Selectores, cascada y especificidad
"¡Puse el color y no se aplica!" es la queja número uno de quien empieza con CSS. Casi siempre la causa está en esta lección. Aprenderás todos los selectores importantes y, sobre todo, las reglas con las que el navegador decide qué estilo gana cuando varios compiten: cascada, especificidad y herencia.
Concepto
Un selector es la "dirección" de los elementos a los que quieres dar estilo. Cuanto más precisa es la dirección, más específico es el selector.
Analogía
"Las personas del edificio" (selector de tipo), "las personas con camiseta roja" (clase), "la persona con pasaporte número X" (ID). Si a todos les dices "siéntense" y a la del pasaporte X "quédate de pie", la instrucción más específica gana.
Selectores básicos
css
/* Universal: todos los elementos */
* { margin: 0; }
/* Tipo (etiqueta) */
p { line-height: 1.6; }
/* Clase: reutilizable, la más usada */
.boton { padding: 12px 24px; }
/* ID: único en la página */
#hero { min-height: 80vh; }
/* Agrupación: misma regla para varios selectores */
h1, h2, h3 { font-family: Georgia, serif; }
/* Encadenado: elemento con ambas condiciones (sin espacio) */
a.boton { text-decoration: none; } /* un <a> con clase boton */
.boton.primario { background: #2563eb; } /* con las dos clases */html
<a href="/contacto" class="boton primario">Contáctanos</a>Un elemento puede tener varias clases separadas por espacios. Esto permite combinar estilos: boton (forma) + primario (color).
Buena práctica
Da estilos con clases, no con IDs. Los IDs tienen especificidad muy alta y no son reutilizables; resérvalos para anclas (#contacto), formularios (label for) y JavaScript.
Combinadores
Seleccionan elementos según su relación con otros:
css
/* Descendiente (espacio): cualquier <a> dentro de nav, a cualquier profundidad */
nav a { color: white; }
/* Hijo directo (>): sólo los <li> que son hijos inmediatos de .menu */
.menu > li { display: inline-block; }
/* Hermano adyacente (+): el <p> inmediatamente después de un h2 */
h2 + p { font-size: 1.2rem; }
/* Hermanos generales (~): todos los <p> después de un h2, con el mismo padre */
h2 ~ p { color: #475569; }html
<ul class="menu">
<li>Inicio</li> <!-- .menu > li ✔ -->
<li>Servicios
<ul>
<li>Diseño</li> <!-- .menu > li ✘ (es nieto) pero .menu li ✔ -->
</ul>
</li>
</ul>Selectores de atributo
css
[disabled] { opacity: .5; } /* tiene el atributo */
[type="email"] { border-color: #0ea5e9; } /* valor exacto */
a[href^="https"] { color: green; } /* empieza con */
a[href$=".pdf"] { color: crimson; } /* termina con */
img[src*="avatar"] { border-radius: 50%; } /* contiene */
[class~="tarjeta"] { padding: 1rem; } /* palabra en lista */
[lang|="es"] { quotes: "«" "»"; } /* es o es-XX */
input[type="text" i] { } /* i = sin distinguir mayúsculas */Caso real: marcar los enlaces externos y los PDF.
css
a[href^="http"]:not([href*="minegocio.com"])::after { content: " ↗"; }
a[href$=".pdf"]::before { content: "📄 "; }Pseudo-clases y pseudo-elementos (adelanto)
css
a:hover { text-decoration: underline; } /* estado: al pasar el mouse */
li:first-child { font-weight: bold; } /* posición */
p::first-line { font-variant: small-caps; } /* parte de un elemento */Los verás a fondo en Pseudo-clases y pseudo-elementos.
La cascada
Cuando varias reglas se aplican al mismo elemento y la misma propiedad, el navegador decide en este orden:
- Origen e importancia: estilos del navegador < estilos del autor (tú) < estilos del autor con
!important. - Capas (
@layer): las capas declaradas después ganan (lo verás abajo). - Especificidad: el selector más específico gana.
- Orden de aparición: a igual especificidad, gana la regla que aparece después.
css
p { color: blue; }
p { color: red; } /* gana: misma especificidad, aparece después */Especificidad
La especificidad se calcula como un trío (A, B, C):
| Columna | Qué cuenta | Ejemplo |
|---|---|---|
| A | IDs | #menu → (1,0,0) |
| B | Clases, atributos y pseudo-clases | .activo, [type], :hover → (0,1,0) |
| C | Elementos y pseudo-elementos | p, ::before → (0,0,1) |
El selector universal * y los combinadores no suman nada. Los estilos inline (style="") le ganan a cualquier selector, y !important le gana a todo lo anterior.
Se compara columna por columna, de izquierda a derecha. Un solo ID (1,0,0) le gana a 50 clases (0,50,0).
css
li /* (0,0,1) */
ul li /* (0,0,2) */
.menu li /* (0,1,1) */
.menu li.activo /* (0,2,1) */
#nav .menu li /* (1,1,1) */
nav ul li.activo > a:hover /* (0,2,4) */Pruébalo con la calculadora:
Ejemplo: ¿de qué color es el enlace?
html
<nav id="principal">
<a href="#" class="enlace">Inicio</a>
</nav>css
#principal a { color: red; } /* (1,0,1) ← GANA */
nav .enlace { color: green; } /* (0,1,1) */
a.enlace { color: blue; } /* (0,1,1) */Rojo, aunque las otras reglas aparezcan después: el ID pesa más.
:is(), :where() y :not()
css
/* :is() toma la especificidad de su argumento más específico */
:is(header, footer) a { color: white; } /* (0,0,2) */
/* :where() SIEMPRE vale 0: perfecto para estilos base fáciles de sobrescribir */
:where(.tarjeta) h2 { margin-bottom: 8px; } /* (0,0,1) */
/* :not() también toma la de su argumento */
button:not(.primario) { background: #e2e8f0; } /* (0,1,1) */!important
css
.oculto { display: none !important; }Fuerza que la declaración gane sobre cualquier otra sin !important. Es un "martillo" que rompe la lógica de la cascada.
Error común
Usar !important para "arreglar" un estilo que no se aplica. Funciona hoy, pero mañana necesitarás otro !important para sobrescribirlo, y así sucesivamente. Mejor revisa en DevTools qué regla está ganando y ajusta la especificidad. Usos legítimos: clases utilitarias (.oculto, .sr-only) o sobrescribir CSS de terceros que no puedes editar.
Herencia
Algunas propiedades se heredan de padres a hijos: principalmente las de texto (color, font-family, font-size, line-height, text-align, visibility, cursor). Las de caja (margin, padding, border, background, width) no se heredan.
css
body {
font-family: system-ui, sans-serif; /* todos los textos la heredan */
color: #1e293b;
}Valores especiales para controlar la herencia:
css
.boton {
color: inherit; /* toma el valor del padre */
font: inherit; /* útil en botones e inputs */
border: initial; /* el valor inicial definido por la especificación */
all: unset; /* quita todos los estilos (heredables se heredan) */
}Un estilo heredado pierde contra cualquier regla directa
Si el body es azul pero existe a { color: purple; } en el navegador, el enlace será morado: un valor heredado tiene la prioridad más baja.
@layer: ordenar la cascada (introducción)
Las capas permiten decidir el orden de prioridad por bloques, independientemente de la especificidad:
css
/* Declara el orden: las últimas tienen más prioridad */
@layer reset, base, componentes, utilidades;
@layer base {
a { color: #2563eb; }
}
@layer componentes {
.menu a { color: white; }
}
@layer utilidades {
.texto-rojo { color: red; } /* gana aunque sea menos específica que #id en "base" */
}Muy útil en proyectos grandes; lo retomarás en Arquitectura CSS.
Casos de uso reales
- "Mi estilo no se aplica": en DevTools aparece tachado → otra regla más específica gana. Solución: igualar o subir la especificidad con una clase, no con
!important. - CSS de un tema de WordPress o Bootstrap que no puedes editar: escribe tu regla con la misma especificidad y cárgala después.
- Estilos base reutilizables con
:where()para que cualquier componente los sobrescriba fácilmente.
Ejercicios
- Calcula la especificidad: a)
header nav ul li a, b).card .card-title, c)#footer p.legal, d)input[type="email"]:focus. - ¿De qué color se ve el párrafo?
html
<div class="aviso"><p id="msg" class="texto">Hola</p></div>css
.aviso p { color: orange; }
p.texto { color: green; }
div p { color: blue; }
.aviso .texto { color: purple; }- Escribe un selector para: los enlaces que abren en nueva pestaña (
target="_blank"), dentro de unarticle. - Haz que el primer párrafo después de cada
h2sea más grande, sin añadir clases.
Ver solución
- a) (0,0,5) b) (0,2,0) c) (1,1,1) d) (0,2,1) — el atributo y
:focuscuentan en la columna B. - Morado.
.aviso .textoes (0,2,0);.aviso pyp.textoson (0,1,1);div pes (0,0,2). Gana (0,2,0). article a[target="_blank"] { ... }
css
h2 + p {
font-size: 1.25rem;
}Resumen
- Selectores principales: tipo, clase, ID, atributo, universal y agrupación.
- Combinadores: descendiente (espacio), hijo (
>), adyacente (+) y hermanos (~). - Cascada: importancia → capas → especificidad → orden de aparición.
- Especificidad (IDs, clases, elementos): se compara columna por columna.
:where()vale 0;:is()y:not()valen lo que su argumento más específico.- Evita
!importante IDs para estilos; usa clases. - Las propiedades de texto se heredan; las de caja no.
Siguiente: Colores y unidades.