Ir al contenido
wannacode

Selectores y la cascada

En resumen: Un selector CSS elige los elementos a los que se aplica una regla, y la cascada decide qué regla gana en un conflicto: origen, especificidad y orden.

Problema

El precio no se pone rojo

La tienda empieza una oferta: el precio del pan debe ser rojo. Un compañero añade una regla para .price al final de style.css. El precio se hace más grande y en negrita, pero sigue gris oscuro.

HTML, CSS, JS

La consola está vacía: CSS no da errores. La regla es la última del archivo y sí alcanza el precio, porque el tamaño y la negrita llegan. Solo el color no. Otra regla quiere otro color para el mismo párrafo, y el navegador eligió esa.

La idea

Regla y selector

CSS dice cómo se ve cada elemento del árbol. Lo dice con reglas:

.price {
color: #c0392b;
font-size: 20px;
}
  • .price es el selector: a qué elementos se aplica la regla.
  • Entre las llaves están las declaraciones: propiedad, dos puntos, valor y punto y coma.

Los selectores buscan en el árbol, así que son como preguntas que se le hacen:

  • p (tipo): todos los <p>.
  • .price (clase): todos los elementos con class="price". Un elemento puede tener varias clases: class="price sale".
  • #product (id): el elemento con id="product".
  • [type="email"] (atributo): los elementos con ese atributo y ese valor, por ejemplo input[type="email"].
  • article p (descendiente, con espacio): un <p> en cualquier lugar dentro de un <article>, a cualquier profundidad.
  • nav > a (hijo): un <a> que es hijo directo de <nav>.
  • .price.sale (sin espacio): un elemento con las dos clases.
  • h1, h2 (lista): la regla vale para ambos.

Los estilos se escriben sobre todo con clases. Un tipo alcanza a todos los párrafos del sitio, y un id es para un solo elemento. Una clase va justo donde la necesitas y no depende de cómo esté organizado el árbol.

Pruébalo

Alcanza justo estos

Quita el subrayado solo de los enlaces del menú (el enlace de abajo se queda subrayado) y pon los dos precios en negrita sin poner en negrita las descripciones. Las propiedades son text-decoration: none y font-weight: 700.

HTML, CSS, JS

La idea

La cascada

Al precio del principio lo alcanzan dos reglas, y las dos fijan color. El navegador tiene que elegir una. Esta regla de elección se llama cascada. Compara en tres niveles y se detiene en el primero que decide:

  1. Origen. El navegador tiene estilos propios: por eso <h1> es grande y un enlace es azul y subrayado. Tu CSS los gana.
  2. Especificidad. Cuán preciso es el selector. Son tres números: cuántos ids, cuántas clases, cuántos tipos. p es 0,0,1, .price es 0,1,0, #product p es 1,0,1. Los atributos ([type="email"]) y los estados (:hover) cuentan como clases. Los números se comparan columna por columna desde la izquierda. En cuanto una columna difiere, está decidido: 1,0,1 gana a 0,1,0.
  3. Orden. Cuando la especificidad es igual, gana la regla que va más tarde en el código.

La cascada decide cada propiedad por separado. Por eso font-size y font-weight de .price llegan: nada más compite por ellas. Por color sí compite algo, y es más fuerte.

Existe también !important: color: #c0392b !important gana a toda declaración normal, sea cual sea la especificidad. Funciona, pero después cada cambio del color necesita un nuevo !important. Así que es señal de que en algún sitio un selector es demasiado fuerte, no una solución.

Míralo

Mira cómo elige el navegador

Cuatro reglas y un elemento. Observa cómo el navegador decide color y font-size por separado.

/* <article id="product">
<p class="price sale">1,80 €</p>
</article> */
p { color: #555; font-size: 16px; }
.price { color: #c0392b; font-size: 20px; }
#product p { color: #222; }
.sale { font-size: 24px; }
Paso a paso, en palabras
  1. Un elemento: un <p> con las clases price y sale, dentro de <article id="product">. Los cuatro selectores lo alcanzan. Dos de las reglas quieren fijar color y tres quieren font-size.
  2. La especificidad de un selector son tres números: cuántos ids, cuántas clases, cuántos tipos. #product p tiene un id y un tipo: 1,0,1.
  3. color: lo fijan tres reglas. El navegador compara la primera columna: 1 gana a 0, y no mira más. Gana #product p, aunque .price viene después.
  4. font-size: otra vez tres reglas. La columna de id es igual (0). En la columna de clases, p queda fuera con 0. .price y .sale son iguales en las tres columnas.
  5. Con la misma especificidad gana la regla que está más tarde en el código. .sale está en la línea 7, después de .price, por eso font-size es 24px.
  6. Cada propiedad tiene su propio ganador: color de #product p, font-size de .sale. La regla .price alcanza el elemento y aun así pierde en las dos.

Aquí está el mismo código en el navegador. El precio es gris oscuro y de 24px, como en la escena. Prueba a intercambiar .price y .sale: el tamaño cambia y el color no. Abre las herramientas de desarrollo (F12), selecciona el precio y mira el panel Estilos: las declaraciones que pierden aparecen tachadas.

HTML, CSS, JS

La idea

Herencia

Algunas propiedades pasan del padre a los hijos. Si un elemento no tiene una regla propia para ellas, toma el valor de su padre. Esto es la herencia.

  • Las propiedades del texto se heredan: color, font-family, font-size, font-weight, line-height, text-align.
  • Las de la caja no: border, padding, margin, background, width. Un borde alrededor de la tarjeta no significa un borde alrededor de cada párrafo de dentro.

Un valor heredado es el más débil. Cualquier regla que alcance el elemento directamente lo gana, incluso p con 0,0,1. Los botones y los campos reciben del navegador su propia fuente y su propio color, por eso no heredan. inherit pide la herencia de forma explícita: button { font-family: inherit; }.

HTML, CSS, JS

El texto de la tarjeta es verde y en Georgia, pero el borde está solo alrededor de la tarjeta. El botón tomó la fuente por inherit, y su color se quedó negro: no hay una regla así para color.

Pruébalo

Arregla el precio

Pon el precio en rojo (#c0392b) sin !important. La descripción debe seguir en gris oscuro (#222).

HTML, CSS, JS

Pruébalo

Encuentra el error

El precio tiene las clases price y sale, pero no es rojo. ¿Por qué?

Elige la línea con el error.

Pruébalo

Completa

El menú tiene enlaces y una lista anidada con más enlaces. Solo los enlaces que son hijos directos de <nav> deben quedar sin subrayado.

nav  a {
  text-decoration: none;
}
Más precisamente, para curiosos

Origen. Hay tres fuentes: el navegador, el usuario (ajustes y extensiones) y el autor, que eres tú. En las declaraciones normales el autor gana al usuario, y el usuario gana al navegador. Con !important el orden se invierte: el !important del usuario gana al tuyo. Así una persona con poca vista puede imponer una fuente mayor en cualquier sitio.

style="…". Un estilo en el atributo del elemento gana a cualquier selector del archivo. Así que también es una trampa, como !important.

Las columnas no se desbordan. 0,11,0 no es 1,1,0. Once clases no ganan a un id: la comparación termina en la primera columna.

Lo que no cuenta. * es 0,0,0. Los combinadores (espacio, >, +, ~) no suman nada. Los pseudoelementos (::before) cuentan como tipos.

:is(), :not() y :where(). :is() y :not() toman la especificidad de su argumento más fuerte. :where() es siempre 0,0,0: práctico para estilos por defecto que cualquier regla sobrescribe.

Capas. @layer ordena grupos enteros de reglas, y la capa decide antes que la especificidad. Las grandes bibliotecas de estilos lo usan para no pelearse con tu CSS.

Las palabras clave. inherit toma el valor del padre. initial es el valor inicial de la propiedad según el estándar (para display es inline). unset es inherit en las propiedades heredadas e initial en las demás. revert devuelve el estilo del navegador.

Ejercicio

La oferta en el catálogo

El catálogo tiene tres productos, y la leche está en oferta (la clase sale en su tarjeta). Todo el texto del catálogo es #222, y los precios van en negrita. El precio del producto en oferta es rojo (#c0392b), y el precio antiguo de dentro es gris (#777). La etiqueta −20% tiene texto blanco (#fff) sobre fondo rojo (#c0392b). Los demás precios se quedan en #222. No uses !important.

HTML, CSS, JS

Test

Ponte a prueba

1. ¿Qué especificidad tiene #cart .item a?
2. Primero va article p { color: gray; } y después .price { color: red; }. ¿De qué color es <p class="price"> dentro de un <article>?
3. .card { color: green; border: 1px solid; }. ¿Qué recibe un <p> dentro de la tarjeta, si ninguna otra regla lo alcanza?
4. ¿Por qué !important es mala señal en el código?
5. ¿Por qué los estilos se escriben sobre todo con clases y no con ids?

Creado por Ivo Gergov como parte de la campaña de Evo Tech por una educación accesible en programación ·