Ir directamente al contenido de esta página

codexexempla.org

Pseudoselectores y selectores avanzados de CSS 2.1 y su impacto en la especificidad de una regla

Tabla de contenidos

  1. Introducción
  2. Pseudoselectores
  3. Selectores avanzados
    1. Selectores basados en parentesco
    2. Selectores de atributos
  4. El selector universal

Introducción

Aunque en el curso que se puede consultar en este sitio expliqué lo que significa la especificidad de una regla de CSS, quisiera ampliar lo dicho tratando un poco más extensamente lo referente a los pseudoselectores y a los selectores avanzados.

Pseudoselectores

Los pseudoselectores se dividen en dos grupos, las pseudoclases:first-child, :link, :visited, :hover, :active, :focus y :lang— y los pseudoelementos:first-line, :first-letter, :before y :after—. Las pseudoclases añaden su especificidad al valor de las clases, y los pseudoelementos al de los elementos1.

Siendo así, veamos el valor de especificidad de algunos selectores de ejemplo con pseudoclases:

Especificidad de algunos selectores de ejemplo (con pseudoclases)
Selector (con y sin pseudoclases)IdentificadoresClasesElementos
  1. Para estos ejemplos presupongo siempre un valor de 0 para los estilos en línea.
  2. No incluyo :lang porque su soporte es algo pobre en los navegadores actuales, y porque tras XHTML 1.1 es ya un atributo obsoleto.
#contenido p101
#contenido p:first-child111
#contenido_adicional a101
#contenido_adicional a:link111
#contenido_adicional a:visited111
#contenido_adicional a:hover111
#contenido_adicional a:active111
#contenido_adicional a.externo111
#contenido_adicional a.externo:hover121
#contacto input101
#contacto input:focus111
a.externo:visited021
a:visited:hover021

Ahora, veamos unos ejemplos de la especificidad de algunos selectores con pseudoelementos:

Especificidad de algunos selectores de ejemplo (con pseudoelementos)
Selectores (con y sin pseudoelementos)IdentificadoresClasesElementos
  1. Sigo presuponinedo un valor de 0 para los estilos en línea.
#contenido p101
#contenido p:first-line102
#contenido p.nota:first-letter112
ul li:before003
a:visited:after012

Como puede verse, la especificidad de los pseudoselectores no ofrece ninguna complicación especial; sólo es necesario recordar cuáles son pseudoclases y cuáles pseudoelementos para saber a qué valor de la especificidad se añaden.

En cuanto al futuro, en el último boceto —hasta ahora— del módulo de selectores de CSS 3 (inglés) se añaden varias pseudoclases nuevas manteniendo su sintaxis. Los pseudoelementos se mantienen, aunque precedidos por dobles dos puntos —::first-letter—. En cuanto a su especificidad, las pseudoclases siguen añadiéndose a las clases, pero los pseudoelementos vuelven a ser ignorados2.

Una nota sobre el soporte de psudoelementos de Internet Explorer: Hay que tener en cuenta unos cuantos datos a la hora de emplear estos cuatro pseudoelementos.

IE6 soporta :first-letter y :first-line, pero con un pequeño error en la implementación de su sintaxis, que hace necesario que incluir un espacio en blanco detrás del selector. Así, estas reglas no se aplicarían:


    p:first-line{background-color:#FF0;}
    p:first-line,.siglos{font-variant:small-caps;}
                

pero estas sí:


    p:first-line {background-color:#FF0;}
    p:first-line ,.siglos{font-variant:small-caps;}
                

En cuanto a :before y :after, no los soporta.

Por su parte, IE7 corrige el error de sintaxis para :first-letter y :first-line, aunque sigue sin soportar :before y :after.

Por último, IE8 Beta 2 sí parece dar un soporte completo.

Selectores avanzados

Selectores basados en parentesco

CSS 2.1 permite seleccionar algunos elementos según las relaciones de parentesco que establecen con otros. La selección de descendientes sigue las reglas generales de la especificidad, pero hay que tener en mente lo que puede suponer que los combinadores para selección de hijos y de hermanos no añaden especificidad a una regla.

Primero, la tabla de ejemplos:

Especificidad de algunos selectores de ejemplo (con combinadores de parentesco)
Selectores (con y sin parentesco)IdentificadoresClasesElementos
  1. Sigo presuponiendo un valor de 0 para los estilos en línea.
#contenido>p101
#contenido p101
#contenido p+p102
#contenido div p102

Revisemos los dos primeros selectores de ejemplo. Supongamos el siguiente código:


    <div id="contenido">
        <p>Lorem ipsum…</p>
        <div>
            <p>Ut enim ad minim…</p>
        </div>
    </div>
            

Apliquemos un estilo siguiendo el orden que he mostrado en la tabla:


    #contenido>p{background-color:#FF0;}
    #contenido p{background-color:#DDD;}
            

Literalmente estamos diciendo «aplica un fondo amarillo a los párrafos que sean hijos directos de contenido y gris para cualquier párrafo dentro de ese mismo elemento». Desde el punto de vista lógico, parece que con la primera regla estamos apuntando a unos elementos más específicos que con la segunda; sin embargo, desde la definición de CSS no, por lo que el resultado es el que muestra la imagen, con ambos párrafos luciendo un suave fondo gris:

Ejemplo 1: Los párrafos con fondo gris

Así pues, si queremos lograr el efecto correcto, tenemos que aplicar las reglas no según su especificidad, sino basándonos en el orden de la cascada:


    #contenido p{background-color:#DDD;}
    #contenido>p{background-color:#FF0;}
            

Ahora sí, como se ve en la siguiente ilustración el efecto es el deseado:

Ejemplo 2: El efecto deseado

Con el combinador para seleccionar hermanos ocurre lo mismo. Sobre el siguiente marcado:


    <div id="contenido">
        <p>Lorem ipsum…</p>
        <p>Ut enim ad minim…</p>
        <div>
            <p>Lorem ipsum…</p>
            <p>Ut enim ad minim…</p>
        </div>
    </div>
            

aplico las reglas siguientes esperando que todo párrafo precedido por otro tenga el fondo amarillo, pero que además los párrafos dentro de un div adicional que no cumplan la condición presenten un fondo gris:


    #contenido p+p{background-color:#FF0;}
    #contenido div p{background-color:#DDD;}
            

Como la primera regla no tiene más especificidad que la segunda, todos los párrafos dentro del segundo div presentan el fondo gris:

Ejemplo 3: Sólo el segundo párrafo tiene el fondo amarillo

Al igual que para el ejemplo de selector de hijos, invirtiendo el orden de las declaraciones…


    #contenido div p{background-color:#DDD;}
    #contenido p+p{background-color:#FF0;}
            

…los estilos se aplican como se pretendía:

Ejemplo 4: Ahora cualquier párrafo con otro anterior tiene el fondo amarillo

Selectores de atributos

Los selectores de atributos se consideran clases en el cálculo de la especificidad de una regla, independientemente de que se indique o no un valor para el atributo:

Especificidad de algunos selectores de ejemplo (con selectores de atributos)
Selectores (con y sin atributos)IdentificadoresClasesElementos
  1. Sigo presuponiendo un valor de 0 para los estilos en línea.
abbr001
abbr.destacar011
abbr[title]011
abbr[title].destacar021
a.externo011
a[class="externo"]011
a[class~="externo"]011
a[hreflang]011
a[hreflang="es"]011
a[href|="es"]011

Como se ve, tampoco tiene mayor misterio. Sólo un pequeño detalle, y es que el valor de clase se aplica a cualquier atributo, incluido id. Esto significa que aplicadas las siguientes reglas:


    #contenido{color:black;}
    div[id="contenido"]{color:orange;}
            

el color del texto del contenido será negro, puesto que la especificidad de la primera regla es 1,0,0, y la de la segunda 0,1,1. Véalo.

El selector universal

Por último, un poco de información adicional para los obsesos del conocimiento: ¿cuál es el valor de especificidad del selector universal? En principio, su valor es cero:

Especificidad de algunos selectores de ejemplo (con selectores de atributos)
Selectores (con y sin *)IdentificadoresClasesElementos
  1. Sigo presuponiendo un valor de 0 para los estilos en línea.
*000
.error010
*.error010
div001
div *001

Podríamos terminar aquí, si no fuese porque hace poco leí un libro de Eric Meyer donde se planteaba la siguiente pregunta: ¿tiene el mismo valor una especifidad de cero, que ningún valor de especificidad?3 La pregunta puede parecer propia de una discusión meramente académica, pero tiene algunos efectos prácticos que hay que conocer a la hora de depurar hojas de estilo.

Como se sabe, las propiedades heredadas por un elemento no tienen valor alguno en el cómputo de la especificidad de una regla que se le aplique. Así, si tenemos:


    <p>Un párrafo con un elemento <em>enfatizado</em>.</p>
            

y una regla:


    p{color:#000;}
            

el color negro del texto que hereda em como tal no tiene especificidad alguna. ¿Pero que ocurre si nuestra CSS es como la que sigue?:


    *{color:#5072BF;}
    p{color:#000;}
            

A primera vista podría parece que el texto enfatizado debería ser de color negro, puesto que es el que heredaría de la declaración aplicada al párrafo que lo contiene. Sin embargo:

Ejemplo 5: El texto enfatizado aparece de color azul

¿A qué de debe? A que em también es un objetivo del valor de color del selector universal —que es 0,0,0—, que es suficiente para superar el valor de la «negritud» heredada de p —que es ninguno—. En conclusión, 0 > ∅.

Notas

  1. En la especificación de CSS 2 se indicaba expresamente que los pseudoelementos no añadían valor alguno a la especificidad (inglés), pero en la de CSS 2.1 se corrige este punto (inglés). Volver
  2. El problema es que para la versión 3 se está empleando como referencia la última especificación de CSS que es Recomendación, que es la 2 —la 2.1 aún es Candidata a Recomendación—. Es de suponer que en la versión definitiva, cuando la Revisión 2.1 sea un documento estable, se restablecerá su valor. Volver
  3. CSS: The Definitive Guide, Eric A. Meyer, pp. 69-70. Volver

Contacto

En virtud de la Ley Orgánica 15/1999 de Protección de Datos de Carácter Personal le informo de que los datos que proporcione no serán empleados para otro fin que el de responder a su mensaje. En especial, me comprometo a no cederlos a terceros ni a emplearlos para enviar información no solicitada.

Del blog de Digital Icon