5.1.1. —perdido, buscando el diseño ideal

Aún más sobre especificidad

Más observaciones sobre el calculo de especificidad en selectores de CSS, pseudo clases y pseudo elementos.

Este artículo no es introductorio, sino que contempla diferentes observaciones sobre el cálculo de especificidad en selectores de CSS. Aún así, los enlaces mencionados pueden resultar útiles para introducirse en el tema.

Conflicto

Para entender el tema de la especificidad (o peso) de los selectores hay que tener algo presente: el conflicto entre reglas se da solamente cuando en la hoja de estilos un mismo elemento es referenciado de dos o más formas distintas. Por ejemplo, p#foo puede referenciarse como p, como #foo, como [id]; de darse dos o más reglas que incluyan esos selectores, es cuando se debe calcular la especificidad.

Cálculo

Hace un mes, EstadoBeta publicó Calculando la especificidad en CSS. Aunque el artículo es una buena introducción al tema, hay un detalle sobre la forma de hacerlo que no me convence.

  • p a tiene una especificidad de 2 (2 selectores de elemento, 1 + 1 = 2)
  • .un-link tiene una especificidad de 10 (1 selector de clase)

El problema con esa forma de ver el tema es que permite inferir que 10 selectores de elemento tendrían el mismo peso que un único selector de clase, cuando esto no es así.

Tiempo después, a.css publica Càlcul de l’especificitat y plantea el cálculo como un vector de números separados por coma, que se incrementan al ir contando la cantidad de selectores de cada tipo —Si leen el artículo, lo van a entender mejor. Siguiendo su estilo, diez selectores de elemento se escribiría 0,0,0,10 mientras que un único selector de clase se definiría como 0,0,1,0 —el número 1 en la posición [2] es independiente de los otros, y en caso de conflicto, tendría prioridad sobre cualquier cantidad de selectores de elementos.

El tomar a las clases con un valor de 10 es algo que se repite en CSS3 Selectors: Calculating a selector's specificity, así que a menos que yo esté equivocando, cuídense de las especificaciones.

Combinators

Los combinators son el selector de descendientes (combinar dos selectores), el selector de hijos y el selector de hermanos —en CSS3 Selectors fueron agrupados como combinadores.

Cuando se trata de calcula la especificidad, hay algo que a mí siempre me resultó chocante —no incorrecto, sino sólo no tan obvio. Cualquier forma de combinar selectores no afecta la especificidad, sólo restringe la cantidad de elementos seleccionados. El ejemplo que aún ahora me resulta extraño de dar sería:

html > body {background: red;}
html body {background: green;}

Aunque la primer regla puede sonar más especifica (seleccionar un elemento BODY, descendiente directo del elemento HTML), simplemente restringe la cantidad de elementos BODY que se pueden seleccionar —la segunda regla sería equivalente a un caso como html > foo > body. Tomando en cuenta que ambas reglas del ejemplo se traducen (por cantidad de selectores) a 0,0,0,2, termina ganando la segunda por la regla de cascada.

Las pseudo clases son clases

:link es una conocida pseudo clase usada para seleccionar enlaces no visitados.

Suponiendo un enlace a[href][class="foo"] puede ser referenciado tanto como

  • .foo {color:red}
  • :link {color:green}

Es importante entender una pseudo clase tiene tanto peso como una clase, por lo tanto en el caso anterior, mientras el enlace se mantenga sin visitar, el conflicto se resolvería por cascada.

LoVe & HAte

Suponiendo que conocen LoVe & HAte, sobre el orden en que deben ir las reglas que involucran enlaces. El truco recomienda que primero deben ir las pseudo clases :link y :visited, seguidas de :hover. Esto se recomienda porque cuando se activa :hover, esta pseudo clase no reemplaza a la existente sino que se añade. Pasando a un ejemplo sería:

  • Mientras el puntero está lejos del enlace, <a href="foo" class=":link">
  • Cuando el puntero se encuentra sobre el enlace, <a href="foo" class=":link :hover">

Tomando eso como referencia, si escribiéramos

:hover {background:red;}
:link {background:green;}

cuando el puntero se encuentre sobre el enlace (y se añadiera la pseudo clase :hover), ganaría la regla con :link por la cascada.

Tengan en cuenta esto no se respeta en Internet Explorer 6:hover reemplaza a :link. Ejemplo: /selectores/001.html.

Pseudo elementos

Un pseudo elemento no cuenta en el cálculo de la especificidad pero igualmente quería hacer un rectificación sobre algo que escribí antes. Tomando en cuenta lo que dije al principio sobre cuándo ocurre un conflicto, hay que tener cuidado cuando ocurre uno con pseudo elementos. Todo esto viene a cuenta de un comentario que hice en ie7 y el pseudo elemento :first-letter. El autor puso este ejemplo:

p:first-letter {color:green;}
p a:hover {color:red}

Y yo le respondí que todo el texto debía ser rojo porque :hover tiene más peso que :first-letter, lo cual es cierto si no fuera porque no existe el conflicto. Extendiendo el código del ejemplo sería

<p>
  <a class=":hover">
    <:first-letter>H</:first-letter>
    ola
  </a>
</p>

En este caso, :hover se refiere al elemento A, no al pseudo elemento :first-letter.

Por dar otro ejemplo fijense en <p id="foo">Hola <span>mundo</span></p>. Suponiendo que la hoja de estilos fuera

#foo {color:red}
span {color:green}

la palabra mundo debería ser verde porque no entra en conflicto con la regla anterior —#foo se refiere al elemento P, no al elemento SPAN.

Publicado el 19 de septiembre de 2006 en las categorías CSS

3 comentarios.

Ismael

Excelente Artículo, muy esclarecedor.

20 de septiembre de 2006

Pedro Rogério

Muy bueno, gracias!!!

21 de septiembre de 2006

albertofs

Buen artículo, te lo has currado. Ahora hay que hacer la digestión de él ;-)

25 de septiembre de 2006

© Federico Martín Panicobpm230 (arroba) gmail (punto) com