Wextensible

Selectores CSS Nivel 3 (CSS3)

Selectores CSS3 Los selectores CSS son patrones que realizan una selección de elementos en una página HTML o XML. La especificación en fase REC (estándar) W3C - CSS Selectors Level3 (CSS3) reúne los ya existentes y que también he publicado en este sitio en el tema CSS2.1 selectores así como otros nuevos que expondré en estos temas. Realmente no hay un CSS3 sino niveles de CSS, pues la especificación ya se ha desglosado en módulos evolucionando cada uno de ellos en niveles. El último nivel debe asumir lo especificado en niveles anteriores. A los efectos es como si CSS1 y CSS2 se desglosaran en módulos y pasaran a llamarse módulos del nivel 1 y 2 de CSS. Ahora tenemos el nivel 3 de CSS en todos esos módulos recogiendo y/o mejorando lo especificado en los niveles anteriores. Aunque seguimos conociéndolo como CSS3, tendremos que empezar a cambiar la forma de decir las cosas puesto que habrán algunos módulos que están ya en nivel 4. Un caso es el que nos ocupa sobre selectores W3C CSS Selectors Level 4 actualmente en fase WD, pero que no expondré aquí. El estado actual de las especificaciones CSS puede verlo en W3C CSS Specifications.

El nivel 3 de Selectores CSS ya está consolidado en los navegadores más recientes y conviene conocerlo para sacar el mayor partido a CSS. Empezaremos con una lista de definiciones más ajustada a la nueva especificación y un repaso a la sintaxis. De paso revisaremos la especificación poniendo enlaces a lo que ya tenía publicado sobre CSS2.1 y a lo nuevo en estos temas.

Definiciones y sintaxis CSS

Diferenciar entre los términos nos ayudará a leer documentación sobre CSS. Esta lista de definiciones engloba lo más importante que podemos encontrar en una hoja de estilo CSS:

Hoja de estilo
Una o más reglas y/o reglas arroba
Regla at (regla arroba)
Empieza con @ seguido de una palabra clave, una expresión y punto y coma. O bien un bloque conteniendo reglas. Algo como @charset "utf-8"; o bien @media print { ...reglas... }
Regla
Una regla consiste en un grupo de selectores seguido por un bloque de declaraciones.
Grupo de selectores
Son uno o más selectores separados con coma (,).
Selector
Es una cadena de uno o más selectores simples separados por combinadores. (Estas definiciones se exponen en el siguiente apartado).
Bloque de declaraciones
Una más declaraciones separadas por punto y coma (;) y entre llaves ({ }).
Declaración
Una pareja propiedad y valor separados por dos puntos (:) y finalizado con punto y coma (;).

Un esquema gráfico de una hoja de estilo muy sencilla nos ayudará a entender la sintaxis CSS:

@charset "utf-8";
@media print {
p.clase1 , div#ident {
color: red; font-size: 2em;
}
}
El esquema anterior está realizado con HTML y CSS3. Si por alguna razón no aparece correctamente puede ver una captura de pantalla de este esquema gráfico de la sintaxis CSS3.

Una hoja de estilo es todo el contenido que puede haber dentro de un elemento <style> o vinculado desde un archivo externo con <link rel="stylesheet" href="...ruta al archivo..." />. La regla arroba sin bloque @charset "utf-8" nos permite declarar el conjunto de caracteres del documento. Todo el estilo se incluye dentro de alguna regla con bloque @media clave { ... }, donde clave puede ser all, screen, print entre otros. Por defecto cuando el estilo no se incluye dentro de un bloque @media se supone englobado dentro de un @media all que significa que aplica a todos los medios. Las reglas sin más son el verdadero cuerpo del estilo. Se componen de un grupo de selectores seguido por un bloque de declaraciones. El grupo de selectores se explica en el siguiente apartado. El bloque de declaraciones consta de parejas propiedad y valor separadas por punto y coma.

Definiciones sobre selectores CSS

Las principales definiciones sobres selectores son las siguientes:

Grupo de selectores
Dos o más selectores separados por comas que comparten una misma declaración. Por ejemplo: h1, h2, h3 {color: blue}
Selector
Es una cadena de una o mas secuencias de selectores simples separadas por combinadores. Un pseudo-elemento puede ser añadido a la última secuencia de selectores simples en un selector.
Secuencia de selectores simples
Es una cadena de selectores simples que no se encuentran separados por un combinador. Siempre empieza con un selector de tipo o un selector universal no pudiendo contener más de estos.
Selector simple
Es uno de los siguientes:
  • Selector de tipo de elemento es el nombre de un tipo de elemento HTML, por ejemplo h1.
  • Selector universal se escribe con un asterisco (*) y representa cualquier tipo de elemento HTML. Cuando es seguido por una secuencia de selectores simples o pseudo-elementos se puede omitir. Por ejemplo:
    • *[val=2] es igual que [val=2]
    • *.val es igual que .val
    • *:first-child es igual que :firstchild
    Pero se recomienda no omitirlo para una mejor lectura, pues algo como div *:first-child se podría omitir quedando como div :first-child. Aunque si no nos percatamos del espacio lo podríamos confundir con div:first-child que sería ya otra cosa diferente.
  • Selector de atributo permite seleccionar un elemento atendiendo a algún atributo. Los cuatro primeros E[att], E[att=val], E[att~=val] y E[att|=val] se establecieron en selectores de atributo de CSS2-1. Otros nuevos se incorporan ahora en los selectores por atributos de CSS3.
  • Selector de clase es como E.val seleccionando un elemento E con un atributo class="val". Esta parte no ha variado con respecto a selectores de clase de CSS2-1. En ambas especificaciones se comenta que la selección por clase E.val es equivalente a la selección por atributo E[class~=val]. Por lo tanto un selector de clase nos permite seleccionar un nombre de clase entre una lista de clases separadas por espacios, aspecto que en su día no tuve en cuenta y que conviene conocer.
  • Selector de identificador es como E#ident seleccionando el elemento E con un atributo id="ident". Esto permanece igual que lo visto en selectores por identificadores en CSS2-1.
  • Selector de pseudo-clase nos permite una selección basada en información que se encuentra fuera del árbol del documento o que no puede ser expresada usando los otros selectores simples. Las que ya se encontraban en las pseudo-clases de CSS2-1 eran las de primer hijo, de vínculo, dinámicas para acciones del usuario y de lenguaje. Ahora con las pseudo-clases de CSS3 se incorporan nuevos grupos y es la parte de selectores que más se ha incrementado.
Pseudo-elemento (opcionalmente finaliza un selector)
Permiten aplicar estilo a contenidos que no se podrían marcar de otra forma, creando externamente un nuevo elemento que no existe en el documento. Vea que un pseudo-elemento no es un selector simple, ubicándose al final de un selector (tipo más secuencia más pseudo-elemento opcional). En pseudo-elementos de CSS2-1 teníamos E:first-line, E:first-letter y para contenido generado E:before y E:after. CSS3 no incorpora ningún pseudo-elemento nuevo.
Combinadores
Son el espacio blanco (espacio, tabulador y salto de línea), signo mayor que (>), signo más (+) y tilde (~). Los combinadores permiten aplicar una selección por contexto entre varios selectores simples. En la selección por contexto en CSS2-1 teníamos E F, E>F y E+F. Ahora con los combinadores de CSS3 se incorpora E~F para seleccionar un elemento F precedido por un elemento E pero no necesariamente de forma inmediata.
Sujeto del selector
Son los elementos de un árbol del documento que son representados por un selector. Un selector representa algún elemento que satisface las condiciones que impone el selector.

Un esquema gráfico con un ejemplo de un grupo de selectores nos ayudará a entenderlo:

*.val p.cls:first-child::first-letter,div.val p#id>a:hover+b[att]
El esquema anterior está realizado con HTML y CSS3. Si por alguna razón no aparece correctamente puede ver una captura de pantalla de este esquema gráfico de selectores CSS3.

El selector representado en el esquema visual anterior se aplica al siguiente ejemplo:

Ejemplo:

Un <div class="val"> tiene dos párrafos <p class="cls">. A la primera letra del primer párrafo se le aplica un estilo particular y al pasar el ratón por el segundo vínculo del segundo párrafo se aplica ese mismo estilo a un elemento siguiente al vínculo.

Un párrafo <p> sin id con vínculo <a> más <b> sin att más vínculo <a> más <b att>

Un párrafo <p id="id"> con vínculo <a> más <b> sin att más vínculo <a> más <b att>

Un párrafo <p class="cls"> por fuera del <div class="val"> no es afectado por el estilo de la primera letra.

Código completo de este ejemplo

El estilo representado es *.val p.cls:first-child::first-letter, div.val p#id > a:hover + b[att]. Cuando aún no hemos practicado lo suficiente con selectores puede ser duro de entender hasta que vayamos adquiriendo soltura con estas expresiones. En el esquema vemos un grupo de selectores formados por dos selectores. El primero tiene dos secuencias de selectores simples separados por el combinador espacio y finalizado con un pseudo-elemento. Una secuencia es una cadena de selectores simples, siempre empezando con una selector simple tipo o universal, luego puede tener cero o más selectores simples que no sean de tipo o universal. Las partes de la secuencia no pueden llevar ningún espacio entre ellas. El pseudo-elemento, que siempre estará al final del selector, se separa con doble dos puntos (::) en CSS3 pero en CSS2-1 se separa con dos puntos (:). Esto se hizo para diferenciar los pseudo-elementos de las pseudo-clases, aunque aún siguen funcionando los pseudo-elementos con sólo dos puntos (:) para los ya existentes en CSS2-1 (:first-line, :first-letter, :before, :after).

Con este otro ejemplo podemos interactuar con la hoja de estilo para modificar el estilo de los elementos:

Ejemplo:

Esto es texto dentro de un contenedor <div class="mi-clase">. El texto no es un elemento a considerar en las pseudo-clases first-child por lo que el párrafo a continuación tiene la condición de primer hijo.

Párrafo primer hijo.

Otro párrafo hijo

Párrafo último hijo

Otro párrafo por fuera del <div> anterior.

Modificar regla del selector para cambiar el color azul y fondo naranja:
 

Código completo de este ejemplo

Para probar como se ejecuta el encadenamiento de selectores hemos puesto cuatro casillas de verificación para observar este proceso. El ejemplo se ejecuta con JavaScript modificando la regla en la hoja de estilo, tal como se explica en el apartado siguiente. Inicialmente aparecen todas las casillas desactivadas. Puede activarlas en cualquier orden, pero para el orden dado se exponen las siguientes observaciones:

  1. Con div.miclase seleccionamos todos los elementos de la página que sean class="miclase". Sólo hay un <div class="miclase"> y lo verá con color azul y fondo naranja.
  2. Si agregamos ahora div.miclase p.miparrafo seleccionamos todos los elementos párrafo <p class="parrafo"> que estén dentro de <div class="miclase">. Por fuera hay otro que no será seleccionado.
  3. Al aplicar la pseudo-clase div.miclase p.miparrafo:first-child partimos de la selección anterior (los tres párrafos) y elegimos el que tenga la condición de primer hijo del <div class="val">. Es el primero de los tres pues no hay otro elemento que sea primer hijo del <div>, dado que el texto que hay antes del primer párrafo no contiene HTML y los nodos texto no se consideran elementos a efectos de aplicar selectores CSS.
  4. Por último sobre esa selección (el primer hijo) aplicamos el pseudo-elemento div.miclase p.miparrafo:first-child::first-letter generándose un nuevo elemento con la primera letra del primer párrafo para dotarle del estilo. Usamos (:) en lugar de (::) para que sea compatible con navegadores que no soporten CSS3.

Algunas otras combinaciones entre las anteriores darán distinto resultado. Marcando p.miparrafo::first-letter aplicará estilo a la primera letra de todos los <p class="miparrafo"> de la página. Marcando sólo ::first-letter resaltará la primera letra de todos los elementos de bloque de la página. En este caso al no haber un selector de tipo por defecto se supone que es todos los elementos, es decir, equivale a *::first-letter.

Las hojas de estilo stylesheet

El estilo lo podemos incorporar en un archivo externo, en un elemento <style> en el <head> del documento o en línea dentro de un atributo style del elemento. Los dos primeros son las llamadas hojas de estilo o style sheet. Lo óptimo es incluirlo en un archivo externo si ese estilo es de frecuente uso en múltiples documentos del sitio. En otro caso si sólo afecta a un documento o es de pequeño tamaño es mejor ubicarlo en el <head> del documento pues así evitamos peticiones adicionales al servidor de un archivo externo. Hay que ubicar todo el estilo lo más arriba que podamos en el documento, pues el navegador cargará esos estilos y los tendrá disponibles cuanto antes para comenzar a renderizar la página.

Pero para hacer una página como esta con ejemplos CSS y dotarla de mayor utilidad he creido conveniente incorporar el estilo con JavaScript. Así la acción del usuario puede modificar el estilo de un elemento y observar con detenimiento como se aplica el mismo. Para evitar tener que incorporar el estilo en línea con JavaScript hemos de buscar la forma de incorporarlo a las hojas de estilo. La especificación W3C DOM Level 2: Style Sheets trata de establecer un estándar para que todos los navegadores manejen de igual forma las hojas de estilo. Está página W3C Dynamic style - manipulating CSS with JavaScript también nos ayudará sobre el tema. El siguiente ejemplo busca todas las hojas de estilo de este documento y hace cambios en una de ellas (ejecute el botón "BUSCAR HOJAS"):

Ejemplo:

Para ejecutar este ejemplo antes debe usar este botón para de estilo de este documento.
Lista de hojas de estilo de este documento:
Podemos  una regla que ponga color rojo a esta palabra. Y también podemos  esa regla.

Código completo de este ejemplo

En la lista de hojas de estilo de este documento aparecen las vinculadas externamente en los archivos cabeza-pie.css, interior.css y formatos.css. Luego hay dos con href = null correspondiente a dos elementos <style> ubicados en la cabecera del HTML de esta página. A la primera segunda le he puesto un id = hoja-estilo-head que aparece resaltado en azul y es sobre la que se ejecuta el ejemplo de este apartado. La otra hoja (hoja-estilo-head2) nos sirve para ejecutar un ejemplo en el apartado anterior.

En enero 2014 he implementado CSS-FOLD eliminando estilos en archivos externos y cargando todo el estilo en línea en el documento, es decir, en elementos <style> en la página. Las hojas de estilo con id="css-before" y id="css-after" contienen el estilo que antes estaba en los archivos que vinculaba externamente. Por lo tanto todas las hojas de estilo de esta página tendrán href=null pues están en elementos <style>.

Se pueden observar los métodos insertRule() y deleteRule(). Estos son los estándar para insertar y eliminar una regla en la hoja de estilo. Chrome 23.0 también incorpora addRule() y removeRule() que son métodos equiparables a los de IE8, navegador que no soporta los métodos estándar. Sin embargo para IE8 y cualquier navegador que no soporte estos métodos yo se los agrego con este código:

El código para el ejemplo anterior tiene las funciones insertarRegla() y eliminarRegla(). Al cargarse la página se ejecuta el listado de hojas de estilo que se encuentran en document.styleSheets. Iteramos por las hojas de estilo y extraemos el atributo href y el id. Cuando identificamos id = hoja-estilo-head guardamos una referencia a esta hoja que es el estilo del elemento <style> que hay en la cabecera de esta página. Ahí insertaremos o eliminaremos una regla para dotar de color rojo al elemento de prueba.

El elemento <span id="palabra2"> no tiene inicialmente un color declarado y toma el color verde heredado del contenedor padre, como se observa en la primera imagen de estas capturas de pantalla. Vea como Matched CSS Rules son las reglas CSS encontradas para ese elemento, mientras que inherited from... es lo heredado del padre.

Insertar y eliminar reglas CSS
Insertar y eliminar reglas CSSImagen no disponible

Tras ejecutar la inserción de la regla vemos el color rojo en una regla separada. El color verde del padre aparece tachado significando que ese estilo ha sido sobrescrito. Al eliminar la regla volvemos a la situación inicial, tomando de nuevo el color verde.

Las acciones del ejemplo anterior podíamos haberlas hecho con estilo directo, es decir, con algo como elemento.style.color = "red". Pero a efectos de hacer ejemplos sobre selectores CSS y que sean a la vez interactivos usando JavaScript hay que aprender a insertar y eliminar reglas en una hoja de estilo.