Skip to content

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:

  1. Origen e importancia: estilos del navegador < estilos del autor (tú) < estilos del autor con !important.
  2. Capas (@layer): las capas declaradas después ganan (lo verás abajo).
  3. Especificidad: el selector más específico gana.
  4. 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):

ColumnaQué cuentaEjemplo
AIDs#menu → (1,0,0)
BClases, atributos y pseudo-clases.activo, [type], :hover → (0,1,0)
CElementos y pseudo-elementosp, ::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:

Calculadora de especificidad

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 ​

  1. Calcula la especificidad: a) header nav ul li a, b) .card .card-title, c) #footer p.legal, d) input[type="email"]:focus.
  2. ¿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; }
  1. Escribe un selector para: los enlaces que abren en nueva pestaña (target="_blank"), dentro de un article.
  2. Haz que el primer párrafo después de cada h2 sea más grande, sin añadir clases.
Ver solución
  1. a) (0,0,5) b) (0,2,0) c) (1,1,1) d) (0,2,1) — el atributo y :focus cuentan en la columna B.
  2. Morado. .aviso .texto es (0,2,0); .aviso p y p.texto son (0,1,1); div p es (0,0,2). Gana (0,2,0).
  3. 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 !important e IDs para estilos; usa clases.
  • Las propiedades de texto se heredan; las de caja no.

Siguiente: Colores y unidades.

Academia Web — aprende, copia y construye.