Ir directamente al contenido de esta página
En la sección sobre selectores y pseudoselectores he indicado los diferentes métodos para aplicar propiedades de estilo a uno o varios elementos. No obstante, el aspecto final que presentará cada elemento no depende sólo de las declaraciones individuales que se han especificado para él, sino que intervienen dos mecanismos de CSS:
Además, hemos de tener en cuenta que son varios los orígenes de las hojas de estilo que se aplican a cualquier documento:
Vamos a ver en detalle todos estos conceptos.
Como ya vimos en la parte del curso dedicada a los selectores avanzados, podemos representar un documento XHTML como un árbol genealógico:
Pues bien, algunas propiedades de CSS se propagan por los descendientes de un elemento. Pensemos, por ejemplo, en la fuente de un documento. Si cada una de las propiedades que tienen que ver con las fuentes de un elemento no fuesen heredables, habría que especificarlas para todos y cada uno de los elementos que empleásemos, lo que supondría crear decenas de reglas con las mismas propiedades. Para un documento tan simple como el esquematizado en la imagen anterior, habría que definir:
h1{font:1em/1.5 Verdana,Helvetica,sans-serif;}
p{font:1em/1.5 Verdana,Helvetica,sans-serif;}
blockquote{font:1em/1.5 Verdana,Helvetica,sans-serif;}
cite{font:1em/1.5 Verdana,Helvetica,sans-serif;}
Y si pensamos que por lo general no vamos a crear documentos tan simples, ni aislados, para todo un sitio deberíamos definir la fuente para cada estado de vínculo, cada encabezado, cada strong
, em
, i
… Decididamente, podría acabar con la paciencia de cualquiera.
Afortunadamente, gracias a la herencia, las regla anteriores —y las hipotéticas para todos y cada uno de los elementos posibles— se pueden resumir así:
body{font:1em/1.5 Verdana,Helvetica,sans-serif;}
Afortunadamente también, hay propiedades que no se heredan. Veamos esta página de ejemplo creada sobre el árbol anterior, y luego ésta, en la que se heredan todas las propiedades. Como se ve, estaríamos en la misma situación que antes: deberíamos restablecer los valores de cualquier propiedad en cualquier descendiente. Ese sería el único argumento de verdad válido para volver a las tablas y a font
.
La moraleja es que hay que saberse de memoria qué propiedades se heredan y cuáles no, y aprovechar las primeras para simplificar nuestras hojas de estilo.
La herencia es un mecanismo básico que hay que tener en mente al trabajar con CSS, pero el más importante es la cascada. La cascada responde a una pregunta crucial: ¿qué ocurre si dos reglas diferentes asignan la misma propiedad al mismo elemento? Supongamos el siguiente estilo:
p{color:lime;}
body p{color:purple;}
Ambas reglas se aplican a los mismos elementos, en la medida en que no puede haber —al menos en un código válido— un párrafo fuera del cuerpo de un documento. ¿Cómo se dirimen sus diferencias? ¿El texto aparecerá en verde lima, o púrpura? Ahí es donde entra la cascada.
Si atendemos a lo que dice la especificación de CSS 2.1 al respecto (inglés), a cada regla aplicada a cualquier elemento se le asigna un «peso», y al final las reglas más pesadas son las que prevalecen.
Tal vez sería más preciso decir que el peso se asigna a cada declaración, puesto que en una regla como
h1{color:#000;border-bottom:1px solid #CCC;}
se asignan pesos descomponiendo previamente la regla en tantas como declaraciones contenga. Además, las propiedades de conjunto también se analizan en sus componentes por separado, por lo que la regla anterior, desde el punto de vista de la cascada, es
h1{color:#000;}
h1{border-bottom-width:1px;}
h1{border-bottom-style:solid;}
h1{border-bottom-color:#CCC;}
Así, el peso se asigna de la siguiente manera:
Y ya está. Ahora sólo hay que saber que saber qué es eso de la importancia, la especificidad y el orden.
Es posible que una declaración sea lo bastante crítica en un estilo como para que no se quiera que deje de aplicarse independientemente de lo que pueda especificar otra hoja de estilo, o la herencia, o cualquier otra regla. Para ello existe !important
, que explicita la importancia de esa declaración, y que se debe incluir antes del punto y coma final para que surta efecto.
Si volvemos a nuestro ejemplo de los párrafos y lo modificamos:
p{color:lime !important;}
body p{color:purple;}
aunque en circunstancias normales el texto de los párrafos sería púrpura, el !important
hará que se vean verde lima, un color que personalmente aborrezco.
Una pequeña nota sobre las hojas de estilo de usuario y agente. En general, las declaraciones de la hoja del autor anulan las del usuario y las del agente, pero el !important
en la hoja del usuario anula el !important
de un autor si entran en conflicto.
La regla de la importancia queda clara, pero ¿qué ocurre si dos declaraciones tienen la misma importancia, bien porque ambas cuenten con !important
, bien porque ambas carezcan de él? Bueno, pues se mira cómo son de específicas.
La especificidad de una declaración se puede representar como cuatro valores separados por comas, que son:
style
en el marcado.id
.class
, un selector de atributo o una pseudoclase.Veamos unos ejemplos:
p{ … } /* 0,0,0,1 */
body p{ … } /* 0,0,0,2 */
.intro{ … } /* 0,0,1,0 */
p.intro{ … } /* 0,0,1,1 */
#contenido{ … } /* 0,1,0,0 */
#contenido p{ … } /* 0,1,0,1 */
div#contenido p{ … } /* 0,1,0,2 */
div#contenido p.intro{ … } /* 0,1,1,2 */
body div#contenido p.intro{ … } /* 0,1,1,3 */
body div#contenido p.intro:hover{ … } /* 0,1,2,3 */
body div#contenido p.intro:first-line{ … } /* 0,1,1,4 */
Cuando se tienen todos estos valores, cualquiera de ellos otorga más peso que los posteriores, es decir, que un solo id
otorga más peso que cualquier número de clases, y una sola clase más peso que cualquier número de elementos. De la misma forma, si se tiene el mismo peso para uno de los valores, son los demás los que determinan el peso total.
Comparemos ahora pares de declaraciones para ver esto más claro.
p{color:lime;} /* 0,0,0,1 */
body p{color:purple;} /* 0,0,0,2 */
Los párrafos serían púrpuras, porque su selector cuenta con más elementos.
p.intro{color:lime;} /* 0,0,1,1 */
body p{color:purple;} /* 0,0,0,2 */
Un párrafo con class="intro"
sería verde lima, porque una sola clase pesa más que dos elementos.
p.intro{color:lime;} /* 0,0,1,1 */
body p.intro{color:purple;} /* 0,0,1,2 */
Ahora el mismo párrafo sería púrpura, porque hay el mismo número de clases pero la segunda regla tiene más elementos.
#resumen{color:lime;} /* 0,1,0,0 */
body div.destacado p.info{color:purple;} /* 0,0,2,3 */
Un párrafo con id="resumen" class="info"
anidado en un div
con class="destacado"
sería lima, porque un solo id
pesa más que cualquier cantidad de clases y elementos.
#info li a[title]:hover{color:lime;} /* 0,1,2,1 */
#info a.v_externo:hover{color:purple;} /* 0,1,2,0 */
En caso de conflicto de estas dos reglas, el vínculo sería verde lima, puesto que a igualdad de identificadores y clases/selectores de atributo/pseudoclases, es el modesto li
el que aporta más peso.
Alguien se preguntará: «¿y el primer número, que siempre es cero en los ejemplos?». Pues ese valor no depende de las declaraciones de la hoja de estilo aplicada al documento, sino del atributo style
que aparezca en su marcado. Si tenemos en nuestro XHTML
<h1 style="color:#FFF;background:#000;">Encabezado</h1>
el encabezado será blanco sobre fondo negro, por muchos identificadores, selectores, clases y elementos que empleemos en una regla, puesto que su especificidad será 1,…,…,…, y tendrá el mayor peso posible.
Por último, si alguien combina las taras de ser desarrollador web y fanático de La Guerra de las Galaxias, le alegrará saber que Andy Clarke creó un gráfico explicativo con personajes del Imperio para ilustrar la especificidad de CSS (inglés).
Con lo dicho hasta ahora es suficiente para comprender la especificidad, pero quiero señalar algunos detalles que suelen plantear dudas cuando se estudia por primera vez este aspecto de CSS:
*
) tiene un valor de 0, por lo que por ejemplo div p
y * div p
tendrían la misma especificidad.div p
como para div>p
.Bien, ya sabemos que la importancia y la especificidad afectan de una manera crítica al peso de una declaración, pero si nos encontramos estas reglas:
body p.destacado{color:lime !important;}
html body .destacado{color:purple !important;}
¿de qué color será el párrafo destacado? Su importancia, como se ve, es la misma, y su especificidad, idéntica —0,0,1,2—. Pues será de color púrpura, porque a igualdad de importancia y especificidad, una regla que aparezca posteriormente en la hoja de estilo gana mayor peso.
El orden no tiene mayor misterio. Con respecto a él, sólo hay que apuntar que si por algún motivo a una página concreta se le añade en la cabecera el elemento style
, es recomendable que se incluya después de cualquier link
a una hoja externa, para asegurarse de que las reglas del documento se aplicarán en caso de que alguna de las incluídas en el archivo .css tenga la misma importancia y la misma especificidad:
<head>
<title>Título del codumento</title>
<link rel="stylesheet" type="text/css"
href="estilo_vinculado.css" />
<style type="text/css">
/*
Las reglas adicionales incluídas en
este bloque contarán con un peso mayor
que las de estilo_vinculado.css, lo
que nos asegurará que se apliquen las
excepciones que queramos incluir
*/
</style>
</head>
Con esto termina esta sección dedicada a la herencia y la cascada.
*{padding:0;margin:0;border:0;}
.