Selectores CSS


Hasta hace poco no me había dado cuenta de lo importante que es conocer los selectores CSS. Sirven para muchas cosas: creación de pruebas con Selenium/Webdriver, encontrar nodos en un XML o para la creación de páginas web, usándolos con JQuery, YUI o cualquier otra librería JavaScript. Es más, estoy convencido de que aún pueden encontrarse otros usos.

La verdad es que siempre me lío con algunos de ellos. Es por eso que escribo este artículo: para recordarlo y para apuntar aquéllas cosas que me suelen parece más "raras".

No soy un experto, así que agradeceré cualquier corrección y mejora. Sin embargo, he tratado de incluir algunos apartados que podrían llegar a sorprender al más experto.

Cómo probarlos

Desde JavaScript

Lo primero es saber cómo podemos tener un entorno básico que nos permita probar los selectores CSS.

La opción más sencilla es abrir la consola JavaScript de Chrome o Firefox y utilizar las órdenes JavaScript querySelector() o querySelectorAll(), dependiendo si queremos el primer nodo o todos ellos (es muy probable que siempre queramos esta última). Ejemplo:

document.querySelectorAll('*');

Usando CSS

Otra opción es crear una página y utilizar el CSS para marcar en rojo (o en el color favorito del lector) los elementos que coincidan. Ejemplo:

<html>
  <head>
    <style>
      h1 { background-color: red }
    </style>
  </head>
  <body>
    <h1>Hello, world</h1>
    <p>Hello!</p>
  </body>
</html>

Podemos usar Chrome o Firefox para no tener que estar modificando un archivo, editando la CSS al vuelo.

Este método puede ser el más visual pero el menos exacto, ya que en páginas complejas podemos creer que se selecciona algo diferente de lo que se ha seleccionado realmente. Pero para este artículo es el método más sencillo para ofrecer ejemplos autocontenidos :D

Por línea de órdenes

La gente de la W3C tiene un conjunto de utilidades llamadas html-xml-utils. Para los que usáis GNU/Linux, hay paquete Debian para su instalación. Estos programas incluyen hxselect, que nos permite utilizar los selectores CSS:

$ cat file.xml | hxselect 'SELECTOR'

Esto nos permite hacer cosas un poco más avanzadas, como descargarnos una página y parsearla sobre la marcha. Por ejemplo:

wget -O - -q http://example.org  | hxselect 'h1'

Selectores básicos

Selector universal

El selector universal es * y nos permite seleccionarlo todo.

Selector de tag, tipo o etiqueta

Simplemente se utilizará el nombre del tag para la selección: Si queremos todos los "h1", se usará el selector h1.

Selector de clase

Permite seleccionar elementos por alguno de los valores de su atributo class. Para ello, basta indicar el valor del atributo, precedido por un punto. Por ejemplo, para seleccionar todos los elementos que contengan la clase "alert", bastaría con usar .alert.

Selectores de id

Igualmente se pueden seleccionar los elementos por el valor del atributo id. Este atributo debería ser único para cada elemento, por lo que sólo debería seleccionarse un elemento.

Para usarlo, basta preceder el id por el símbolo #. Ejemplo: #alert seleccionaría un elemento del tipo:

<p id="alert">Ey, man!</p>

Selectores avanzados

Selector descendente

Con el fin de buscar elementos dentro de otros elementos, se pueden combinar selectores. De esta manera podemos ir seleccionando elementos de forma descendente, indicando los selectores separados por espacios.

Por ejemplo:

<html>
  <head>
    <style>
      .selectme p { background-color: red }
    </style>
  </head>
  <body>
    <h1>Hello, world</h1>
    <p>Hello!</p>
    <h2>Another title</h2>
    <div class="selectme">
      <p>Wow, man!</p>
    </div>
  </body>
</html>

Es importante entender que se buscarán todos los p que estén por debajo de un elemento con clase selectme, aunque no sea de forma directa. Así, hubiera sido un error buscar en body, ya que hubiera encontrado todos los p.

Selector de hijos

De forma similar, podemos buscar hijos directos mediante el símbolo "mayor que" >.

Por ejemplo:

<html>
  <head>
    <style>
      .search > p { background-color: red }
    </style>
  </head>
  <body>
    <h1>Hello, world</h1>
    <div class=".search">
      <p>Wow, man!</p>
      <div>
        <p>Not me!</p>
      </div>
    </div>
  </body>
</html>

En este ejemplo podemos ver la diferencia entre usar el selector de hijos .search > p y el de descendientes .search p, ya que el selector de hijos sólo seleccionaría el primer elemento p, mientras que el selector de descendientes los seleccionaría todos.

Selector de hermanos

De forma análoga, podemos seleccionar hermanos mediante el símbolo +:

<html>
  <head>
    <style>
      h2 + p { background-color: red }
    </style>
  </head>
  <body>
    <h1>Hello, world</h1>
    <p>whaaaat?</p>
    <h2>Yeah!</h2>
    <p>hello!</p>
    <p>Not me...</p>
  </body>
</html>

En el ejemplo, sólo el párrafo "Yeah!" se mostrará en rojo, ya que es el único párrafo que es hermano directo de h2.

Selector de atributos

Aquí rizamos el rizo. Podemos buscar por cualquier atributo, no sólo por id o class. Para ello, encerraremos el atributo entre corchetes, teniendo en cuenta, además, que podemos realizar distintos tipos de búsquedas:

  • [atributo] buscará los elementos que contengan el atributo, independientemente de su contenido.
  • [atributo=valor] comprobará que el valor sea exactamente igual al indicado.
  • [atributo~=valor] coincidirá cuando el valor se encuentre entre alguno de los valores del atributo. Asume que el atributo puede contener una lista de valores separados por espacios.
  • [atributo|=valor coincide con los valores que comienzan por valor- (sí, el valor seguido de un guión). Es útil para identificar idiomas, así que sólo suele utilizarse con el tag lang.

En CSS 3 tendremos también los siguientes:

  • [atributo^=valor], que espera que el valor del atributo comience por el valor indicado.
  • [atributo$=valor], para indicar el final del valor.
  • [atributo*=valor], que comprobará si el atributo contiene el valor indicado, en cualquier posición, tratando todo el valor del atributo como una cadena.

pseudo-clases y pseudo-elementos

Existe un conjunto de palabras clave que permiten seleccionar ciertos elementos. Éstas dependen de la versión de CSS y pueden dar muchos dolores de cabeza. Sin embargo, son tan útiles que resulta dificil ignorarlas, ya que pueden evitarnos mucho JavaScript (que nos daría más dolores de cabeza aún).

Estas pseudo-clases comienzan siempre por dos puntos :. Algunas de ellas son:

  • :link, para referirse a los enlaces no visitados
  • :visited, para los enlaces visitados
  • :focus, elemento input con el foco
  • ...

Combinando selectores

También podemos seleccionar los elementos que cumplan varias condiciones si no los separamos con espacios, sino que los unimos:

<html>
  <head>
    <style>
      p.alert { background-color: red }
    </style>
  </head>
  <body>
    <h1>Hello, world</h1>
    <p class="pepito">Hello!</p>
    <h2 class="alert">Another title</h2>
    <p class="alert">Wow, man!</p>
  </body>
</html>

Selectores eficientes

No todos los selectores son igual de eficientes. Éste es el orden, del más rápido al más lento (con ejemplos):

  1. ID: #header
  2. Class: .promo
  3. Type: div
  4. Adjacent sibling: h2 + p
  5. Child: li > ul
  6. Descendant: ul a
  7. Universal: *
  8. Attribute: [type="text"]
  9. Pseudo-classes/-elements: a:hover

Éste es el orden que propone Steve Souders en el libro Even Faster Websites. Para ser sincero, aún no lo he leído, pero he encontrado la lista en el artículo Writing efficient CSS selectors :D

En esta lista hay que tener en cuenta algunas cosas más, como que la diferencia entre usar id y class es inapreciable, mientras que la diferencia con los últimos elementos de la lista puede ser de órdenes de magnitud. Esto se debe a la forma en que los navegadores gestionan el DOM, ya que todos ellos disponen de cachés para los id y los class, pero no para otros atributos.

El selector principal o key

Es muy importante saber que el navegador buscará los elementos en el orden inverso a como se indiquen. Al primer elemento que buscará el navegador se le denomina selector principal o key. Veamos varios ejemplos:

  • div p span: el selector principal es span
  • div p span.myclass: el selector principal es span.myclass (complejo)
  • div p.myclass span: el selector principal es span, nuevamente.

Cuantos más elementos devuelva el selector principal, menos eficiente será nuestro selector. Si queremos hacer un selector totalmente ineficiente, basta con terminarlo siempre con el selector universal *, ya que siempre devolverá todos los elementos.

Referencias

Para crear este artículo he necesitado bastantes referencias, dada mi ignorancia sobre el tema. Conocía lo básico de las CSS, y algo sobre su eficiencia, pero no lo suficiente como para plasmarlo aquí.

Por eso me he remitido a la sapiencia de la W3C, donde podéis consultar la Referencia de selectores CSS en w3schools. También he consultado el artículo Writing efficient CSS selectors, de Harry Roberts, así como los libros web gratuitos Introducción a CSS y CSS avanzado, ambos de Javier Eguiluz.

También puede resultaros útil el artículo The 30 CSS Selectors you Must Memorize, quizá no para memorizarlos pero sí para consultarlos.

Y, por supuesto, el libro que creo que terminaré leyéndome, Even Faster Websites, de Steve Souders.


Comentarios

Comments powered by Disqus