Jerarquía y herencia

publicado en la categoría CSS
Cuando agregamos reglas o propiedades CSS no sólo debemos cuidar que la sintaxis sea correcta ya que hay un orden de prioridades que a veces tiene que ver con el orden real en que se han enumerado pero también con el valor específico del selector que usamos.

Para poder utilizar CSS y sacarle el máximo provecho es indispensable entender cuál es la estructura de un documento HTML. Es bastante común que tratemos de establecer una propiedad, la sintaxis sea correcta y, aún así, no se vea lo que creemos que debería verse.

Podemos imaginarnos que una página web es un conjunto de cajas (bloques) metidas una dentro de la otra, siendo la más grande, la que contiene a todas, el elemento definido con la etiqueta html.

En este tipo de estructura, donde hay elementos contenidos en otros hay una cierta jerarquía, los elementos padre son los contenedores y los elementos hijos los contenidos. El problema de eso es que como las etiquetas pueden anidarse, hay que descubrir cuál está dentro de cuál para conocer el orden de prioridades y eso es lo que se llama herencia.

Como norma general podemos decir que muchas de las propiedades de estilo de los elementos padre son heredadas por los elementos hijo, pero no al revés.

Supongamos que tenemos este texto con cuatro animales para que sea más claro:

<p>
	león 
	<strong>jirafa <em>elefante</em></strong>
	<em>perro</em>
</p>

Sin reglas de estilo definidas, veríamos algo así:

león jirafa elefante perro

Todo tendrá la misma fuente, jirafa se mostrará en negrita, elefante se mostrará en itálica pero también en negrita porque em está dentro de strong.

Decimos entonces que em desciende de strong que es su etiqueta padre (parent) y a su vez, todas descienden de p que sería el abuelo.

Si establecemos una propiedad de color para la etiqueta p, las demás heredarán esa propiedad; por ejemplo, así, todo el texto será rojo:

p {color: red;}

En cambio, si agregamos esta regla:

strong {color: green;}

Tanto jirafa como elefante serán de color verde y el resto será rojo.

Por último, si agregamos:

strong em {color: black;} 

león jirafa elefante perro

Y perro no cambiará de color porque la regla dice que sólo será negro el contenido de una etiqueta em que esté DENTRO de strong. Todos los selectores que estén anidados dentro de otros heredarán los valores de propiedades asignados al selector exterior, salvo que se modifiquen de otra manera.

Este tipo de selector se denomina contextual y consisten en una serie de elementos separados por un espacio. Esto puede tener múltiples opciones y combinaciones:

ul li {font-size: small;}
ul ul li {font-size: x-small;}
div p {font: small sans-serif;}
.ejemplo1 h1 {color: red;}
#ejemplo2 code {background: blue;}
div.ejemplo3 h1 {font-size: large;}
h1 b, h2 b, h1 em, h2 em {color: red;}

Cuando agregamos reglas o propiedades CSS no sólo debemos cuidar que la sintaxis sea correcta. Muchas veces, aunque todo parezca perfecto, nos vamos a encontrar con que ... no parecen funcionar. Por lo general, esto tiene una explicación: en el CSS hay un orden de prioridades que a veces tiene que ver con el orden real (qué está antes y qué está después) pero también con el valor específico del selector que usamos.

Un ejemplo, supongamos que tenemos este código HTML con ciertas definiciones de estilo:

<style>
#rojo {color: red;}
.azul {color: blue;}
</style>

<p class="azul" id="rojo">un texto</p>

A la etiqueta le estamos agregando dos atributos, id y class, en uno le decimos que el párrafo debe ser azul y en el otro que debe ser rojo ¿De que color se verá el texto?

un texto

¿Importa el orden en que está escrito? No, sea como sea que lo escribamos, siempre será rojo porque un atributo id es más importante que un atributo class. Los selectores tienen un orden de prioridades, algo que la www.w3.org dice que podemos calcular con aritmética pero, por lo general, basta saber que esas prioridades existen para aprovecharse de ellas; el orden es más o menos este:

  1. lo que está definido en la etiqueta en el atributo style
  2. lo que está definido con un atributo id
  3. lo que está definido con un atributo class
  4. lo que está definido con un selector genérico (una etiqueta)

Por ejemplo:

<style>
	p {color: red;}
	p.verde {color: green;}
</style>

<p>esto se verá rojo porque TODOS los parrafos son rojos</p>
<p class="verde">pero esto se verá verde</p>
<p style="color: yellow;">este texto se verá de color amarillo</p>

esto se verá rojo porque TODOS los párrafos son rojos

pero esto se verá verde

este texto se verá de color amarillo

De esta manera sobrescribimos la regla inicial ya que si hay varias reglas diferentes que afectan a un mismo elemento, sólo se aplicará una de ellas.

Lo mismo ocurre con definiciones más complejas como las listas; por ejemplo, si queremos resaltar un ítem:

<ul id="milista">
	<li class="resaltado">primer item de una lista</li>
	<li>segundo item de una lista</li>
	<li>tercer item de una lista</li>
	<li>cuarto item de una lista</li>
</ul>

Definirlo así, no funcionará:

ul#milista li {color: blue;}
.resaltado {color: red;}
  • primer item de una lista
  • segundo item de una lista
  • tercer item de una lista
  • cuarto item de una lista

Porque lo que dice ul#demo li es más poderoso que lo que dice la clase .resaltado; ahí es donde funciona bien la aritmética para calcular esas prioridades o el instinto que nos dice que podríamos hacer esto:

ul#demo li {color: blue;}
ul#demo li.resaltado {color: red;}

La herencia y la jerarquía tiene una excepción con la cual podemos forzar las reglas: la posibilidad de usar la palabra !important que podemos agregar al final de una propiedad CSS y que realza cierto valor para, de esta forma, obligar a que se ignore una declaración y forzar un cambio.

Supongamos que tenemos una definición con dos clases donde, el orden en que las escribimos definen cuál es la que se verá; en este caso rojo porque es la última:

<style>
	.claseColorVerde {color: green;}
	.claseColorRojo {color: red;}
</style>

<p class="claseColorVerde claseColorRojo"> ... contenido ... </p>
Sin embargo, podríamos cambiar la primera forzando a que sea verde:

	.claseColorVerde {color: green !important;}
	.claseColorRojo {color: red;}

Usando la palabra !important todas las demás declaraciones posteriores son ignoradas y es por ese motivo que se debe ser muy prudente con su uso y sólo debe ser aplicada cuando sea absolutamente necesario ya que si no, nos veremos en problemas a la hora de corregir algo.

Por último, hay que saber que, como muchas propiedades son heredadas de alguna otra (hasta llegar a la raíz de la página), hay una forma en que podemos indicar eso de modo explícito, utilizando la palabra inherit que establecerá el valor de la propiedad del elemento padre, aunque no sepamos cuál es: