JASoft.org

El blog de José Manuel Alarcón Aguín. Programación web y mucho más...

MENÚ - JASoft: JM Alarcón

Tu estilo gana a mi estilo: Especificidad en reglas CSS

CSSLos selectores CSS nos permiten definir con mucha precisión el aspecto (¡y comportamiento!) que van a tener los elementos HTML en nuestras páginas. Así, utilizamos: estilos embebidos, identificadores, clases, pseudo-clases, etiquetas y atributos para definir exactamente cómo ha de funcionar cada elemento.

Las hojas de estilo .css suelen tener decenas o cientos de estilos que el navegador debe aplicar a cada elemento. Muchos de estos estilos entran en conflicto, por lo que ¿cómo decide el navegador qué estilo o estilos concretos debe aplicar a un determinado elemento de la página?

Pongamos un ejemplo sencillo y consideremos el siguiente fragmento de HTML:

 1: <ul id="menu">
 2:     <li>Menu 001</li>
 3:     <li class="destacado">Menu 002</li>
 4:     <li>Menu 003</li>
 5: </ul>

Al cual se le aplican los siguientes dos estilos:

 1: ul#menu li {
 2:     font-weight:normal;
 3:     font-size:14px;
 4:     color: blue;
 5: }
 6:  
 7: .destacado {
 8:     font-weight:bold;
 9:     color:red;
 10:     text-decoration: underline;
 11: }

Si leemos los selectores vemos que el primero se aplica a los elementos de lista (li) que se encuentran dentro de listas sin ordenar (ul) cuyo identificador es “menu”, es decir afecta a todos los nuestros. En ese caso se les aplica un tamaño de letra de 14px y el color azul para el texto. El segundo selector indica que los elementos que lleven la clase “destacado” aplicada, deberán mostrarse en negrita, con letra de color rojo y con una línea de subrayado.

Según esto, aparentemente, el aspecto que debería mostrar el HTML una vez renderizado en el navegador sería este:

CSSEspecificidad_1

Sin embargo, el verdadero aspecto que muestra es este otro:

CSSEspecificidad_2

Es decir, el selector CSS para la clase “destacado” no se está aplicando en su totalidad, sino que solamente aplica la parte del subrayado, pero no la negrita ni el color rojo para el texto.

¿A qué es debido esto?

La especificidad de los selectores CSS

Como decía, en una página típica hay decenas o cientos de selectores CSS y a un mismo elemento se le pueden aplicar varios de ellos. El navegador debe elegir en cada momento cuál es el apropiado, ya que en muchas ocasiones estos selectores pueden tener valores contradictorios. En el ejemplo anterior, a pesar de su sencillez, ya lo hemos experimentado. Ambos estilos se aplican a nuestro elemento destacado y tienen indicaciones contrarias para el peso del texto y su color, así que ¿cuál debe aplicar el navegador?

Para decidirlo los navegadores utilizan las reglas de la especificidad de los selectores. Es decir, cuanto mas específico es un selector mayor fuerza tiene y es el que prevalece.

Para calcular la especificidad se genera un número que dota de peso diferente a cada elemento, de acuerdo con el siguiente esquema de cálculo:

CSS Especificidad

En este gráfico los elementos situados más a la izquierda se consideran más específicos que los de la derecha, por lo que tendrán más peso a la hora de decidir qué estilos aplicar a un determinado elemento cuando haya conflicto.

Así, los estilos que se especifiquen directamente en la etiqueta HTML siempre tendrán la mayor precedencia y se aplicarán siempre. Si hubiésemos escrito:

 1: <li style="color:red;font-weight:bold;">Menu 002</li>

Da igual lo que indiquen el resto de selectores CSS incluidos en la cabecera o en un .css externo: se aplicará el estilo in-line que hemos indicado.

Para el resto de selectores se deben contar los elementos de cada tipo que haya en dicho selector y colocar el número resultante en cada uno de los recuadros que hay en la figura de arriba. El número resultante será la especificidad del selector, y cuanto mayor sea mayor precedencia tendrá.

Por ejemplo, para nuestro selector “.destacado” la especificidad es simplemente 0,0,1,0 (o, si lo pasamos a un número decimal normal (aunque no lo sea, OJO), sería simplemente un 10). ¿Por qué? Pues porque tiene simplemente una clase, es decir, un elemento para el tercer recuadro, en el que se deben sumar las clases, pseudo-clases y atributos.

Para el otro selector “ul#menu li”, la especificidad es 0,1,0,2 (o lo que es lo mismo, el número 102), ya que especifica un identificador (@menu) y dos elementos HTML (ul y li).

Dado que 102 es mayor que 10, el primero de los selectores es más específico y por lo tanto cuando haya reglas que entren en conflicto son las de éste las que aplican.

Es por eso que sale el texto con color azul, sin negrita,pero sin embargo sí que se aplica el subrayado también, ya que para esta regla no existe conflicto alguno.

Si abrimos las Developer Tools de Internet Explorer o de Chrome y seleccionamos el elemento destacado, podemos ver los estilos resultantes y comprobaremos que efectivamente se aplican ambos estilos pero uno prevalece sobre el otro (lo he marcado aquí en Chrome):

CSSEspecificidad_Chrome

¿Como haríamos entonces para que se aplique realmente el estilo que deseábamos en nuestro elemento destacado?

Pues siendo más específicos, por ejemplo con este selector:

 1: ul#menu li.destacado {
 2:     font-weight:bold;
 3:     color:red;
 4:     text-decoration: underline;
 5: }

En este caso la especificidad es 0,1,1,2 (1 identificador, 1 clase y dos elementos HTML), es decir, 112, que es mayor que 102 y por lo tanto se aplicaría con mayor prioridad, consiguiendo el resultado que buscábamos.

Algunas cosas a tener en cuenta

La regla es bastante sencilla, pero además debemos tener en cuenta algunas reglas adicionales:

  • A igualdad de especificidad siempre gana el selector que esté definido más tarde en la página. Por ejemplo, si tenemos un elemento al que se le aplican las clases “menu destacado” y tenemos dos selectores “.menu” y “.destacado” (ambos aplican exactamente igual al elemento), con estilos que entran en conflicto, ganará el último de los dos que esté definido en la página.
  • Un elemento de mayor especificidad siempre gana a cualquier número de elementos de menor especificidad. Por ejemplo, imaginemos un selector muy loco que contiene una clase y mete 12 etiquetas HTML en la definición. La clase gana a los elementos HTML aunque si lo convirtiésemos en un número sería 1,12, y en decimal, al pasar de 10, habría que sumarlo a las decenas. Por eso decía que no debe considerarse como un número decimal, sino que se debe ver cuál de los elementos es superior empezando por la izquierda. Lo de convertirlo en un valor decimal sólo sirve como abstracción, para hacerlo más sencillo de comprender, y sirve para casi todos los casos porque realmente es muy raro que haya más de 9 elementos de un tipo especificados. Si los hay seguramente es que la CSS está bastante mal definida.
  • El selector universal (*) no tiene especificidad, o para ser más exactos, su especificidad es 0,0,0,0, por lo que no aporta nada a la especificidad.
  • El modificador “!important” aplicado a un atributo de estilo siempre gana. Lo podemos usar para cuando realmente sea muy importante que un estilo se aplique a un elemento o clase y nos queramos saltar las reglas de especificidad. No deberíamos usarlo más que en casos muy especiales, y desde luego no deberíamos abusar de él.

Calculadoras de especificidad

Aunque el cálculo es bastante fácil y además podemos usar las Developer Tools de los navegadores para cuando haya dudas sobre qué estilos prevalecen, puede ser útil tener a mano una calculadora de especificidad de selectores, que nos saque de dudas en algunas ocasiones.

Las dos más conocidas son:

  • Specificity Calculator de Keegan Street: permite comparar de manera muy visual y atractiva dos selectores cualesquiera.
  • CSS Specificity Calculator de Nicholas Bannister-Andrews: es mucho más espartana que la anterior, pero tiene la ventaja de que nos permite calcular la especificidad de muchos selectores de un solo golpe, por lo que es muy rápido si necesitamos muchos cálculos.

Ambos explican los resultados de sus cálculos para ayudarnos a entenderlos.

Este post está basado en material extraído de mi curso online de HTML(5) y CSS(3) de campusMVP. Si quieres aprender de verdad sobre este tema y tenerme como tutor para contestar tus dudas empieza hoy mismo.

Fácil, ¿no?. Pues la especificidad es tal vez el concepto más importante que debes conocer y tener claro sobre CSS. Te evitará muchas sorpresas y te ayudará a saber porqué fallan los estilos de tus páginas.

¡Espero que te sea útil!

José Manuel Alarcón José Manuel Alarcón
Fundador y director de campusMVP.es, el proyecto de referencia en formación on-line para programadores en lengua española. Autor de varios libros y cientos de artículos. Galardonado como MVP de Microsoft desde 2004. Gallego de Vigo, amante de la ciencia y la tecnología, la música y la lectura. Ayudando a la gente en Internet desde 1996.
Descarga GRATIS mi último libro (no técnico): "Tres Monos, Diez Minutos".
Banner

Comentarios (4) -

Spain Sergio León

Hola José Manuel:
Excelente post! Lo he twitteado y retwitteado.
Sólo una cosa, cuando dices "Ganan los estilos definidos en la página sobre los que están en archivos .css externos" yo creo que no es correcto. En su día escribí algún post sobre ello panicoenlaxbox.blogspot.com.es/.../...dad-css.html y he vuelto a hacer la prueba hoy y yo creo que sólo importa el orden. Es decir, a CSS le da igual que sea una hoja de estilos externa (<link>) o estilos en la propia página (<style>), al final en caso de ambigüedad gana lo más cercano (lo dicho en último lugar).
Yo creo que lo típico es hacer algo así:

<link...
<style...

pero si haces esto otro:

<style...
<link...

verás que hay diferencia, ahora <style> ya no gana, gana <link>

Felicidades por tu blog, por CampusMVP y por todo ;-)

Responder

Spain José Manuel Alarcón

Hola Sergio,

La verdad es que tienes razón.
En CSS 2 no era así: los estilos definidos en el propio documento están más próximos a los elementos que las externas, por lo que tenían precedencia sobre las externas:

http://www.w3.org/TR/CSS21/cascade.html#cascade

Sin embargo parece que esto ha cambiado.
A mi personalmente me parece que era más lógico lo anterior, puesto que los estilos embebidos tienen mayor precedencia precisamente por estar más "pegados" al elemento, al igual que las del documento.

No obstante en general no debería influirte pues las buenas prácticas aconsejan que los estilos internos se introduzcan al final, tras cualuier declaración externa. El motivo es que éstos sólo deberían usarse precisamente para sobrescribir o redefinir (totalmente o en parte) en la página actual estilos generales que no se apliquen a este caso en particular. Poniéndolas siempre al final te aseguras de que van a actuar como esperabas, incluso sin que se cumpla esa regla que puse en mi post.

Gracias por el comentario. Lo cambiaré ahora mismo.

Saludos!

Responder

Hola José:

Pues completamente de acuerdo, ni pongo ni quito una coma. Además me ha gustado mucha tu forma de defender los estilos en el propio documento: "sobrescribir o redefinir", esto intentaré recordarlo cuando tengo que explicarlo y no encuentro muchos motivos por los que meter este tipo de estilos. Y sí... la verdad es que tener que meter <style> antes que <link> parece algo bastante improbable

Te felicito por "tus blogs" (ambos dos) que sigo siempre y no me pierdo una entrada :-)

Gracias por contestar.

Responder

Muy buen artículo. Gracias!

Responder

Agregar comentario