Selectores CSS avanzados

Al margen de la selección «básica» de elementos a través de CSS, que suele realizarse mediante clases e IDs, existe un amplio abanico de métodos para seleccionar elementos dependiendo de la estructura del documento HTML denominados combinadores CSS:

Nombre Símbolo Ejemplo Significado
Agrupación de selectores , p, a, div { } Se aplican estilos a varios elementos.
Selector descendiente #page div { } Se aplican estilos a elementos dentro de otros.
Selector hijo > #page > div { } Se aplican estilos a elementos hijos directos.
Selector hermano adyacente + div + div { } Se aplican estilos a elementos que siguen a otros.
Selector hermano general ~ div ~ div { } Se aplican estilos a elementos al mismo nivel.
Selector universal * #page * { } Se aplican estilos a todos los elementos.

En los siguientes apartados, veremos varios ejemplos gráficos sobre un supuesto ejemplo de documento HTML, dibujado en forma de árbol esquemático. Así sabremos que elementos están dentro de otros y nos será más fácil entender cada uno de los combinadores CSS.

Agrupación de selectores

En muchas ocasiones nos ocurrirá que tenemos varios bloques CSS con selectores diferentes pero con los mismos estilos exactamente, algo que generalmente no es apropiado. Si esto ocurre a menudo, el tamaño del documento CSS ocupará más y tardará más en descargarse:

.container-logo {
  border-color: red;
  background: white;
}

.container-alert {
  border-color: red;
  background: white;
}

.container-warning {
  border-color: red;
  background: white;
}

Una buena práctica es ahorrar texto y simplificar nuestro documento CSS lo máximo posible, por lo que podemos hacer uso de la agrupación CSS utilizando la , (coma).

De esta forma, podemos pasar de tener el ejemplo anterior, a tener el siguiente ejemplo (que es totalmente equivalente), donde hemos utilizado la agrupación para decirle al navegador que aplique dichos estilos las diferentes clases:

.container-logo, .container-alert, .container-warning {
  border-color: white;
  background: red;
}

Al margen de esto, dos buenas prácticas que podríamos aplicar en esta situación serían las siguientes:

  • Simplifica por responsabilidades: .container-alert y .container-warning parecen tener un concepto muy similar: alertas o mensajes de advertencia. Es posible que estos selectores tengan la misma funcionalidad y sean sinónimos. Si es así, lo ideal sería refactorizar y simplificarlos a uno: .container-warning, haciendo desaparecer el otro.

  • Legibilidad por delante: CSS por si sólo puede ser dificil de leer y mantener. Aunque a priori puede parecer que es mejor poner la lista de selectores uno detrás de otro, la experiencia nos dicta que deberíamos separarlos en una línea diferente cada selector. Esto lo hace tremendamente más legible a la hora de revisar código CSS.

.container-logo,
.container-warning {
  border-color: white;
  background: red;
}

Consejo: Esto puede parecer poco importante a priori, pero a medida que avanzamos con nuestro diseño, los documentos CSS se hacen tremendamente grandes y difíciles de mantener, por lo que cuanto más sencillos sean, mejor.

Selector descendiente

En CSS podemos utilizar lo que se llama el selector descendiente, que no es más que una forma de seleccionar ciertos elementos que están dentro de otros elementos. Esto puede parecer sencillo, pero cuidado, ya que puede ser una fuente de problemas si no se entiende bien.

Su sintaxis se basa en colocar los elementos uno a continuación de otro, separado por un espacio:

div#pagina div {
  background-color: blue;
}

En el ejemplo anterior, aplicamos los estilos CSS (color azul de fondo) a todos los elementos <div> que estén dentro de un <div> con ID pagina. De esta forma, si existe un elemento <div> fuera del <div> con id pagina, no se aplicarán los estilos indicados:

Selector descendiente

Repasemos varios detalles importantes respecto a este combinador CSS:

  • Se están seleccionando todos los elementos <div> que están dentro de <div> con ID pagina.
  • Observa que se seleccionan independientemente del nivel al que estén (hijos, abuelos, ...)
  • En este caso, el div de div#pagina es innecesario, ya que habíamos dicho que los IDs no se pueden repetir. Si ya existe un elemento con ID pagina, no hace falta diferenciarlo también por etiqueta. Si se tratase de una clase, si podría usarse.

Se pueden construir selectores muy complejos con tantos elementos como se quiera, pero una buena práctica es mantenerlos simples. Cuántos más elementos descendientes existan en un selector, más complejo será el procesamiento de dicha regla por los navegadores. Lo recomendable es ser despierto y utilizar sólo los necesarios.

  <div class="menu">
    <div class="options">
      <ul>
        <li><a href="/one">Option 1</a></li>
        <li><a href="/two">Option 2</a></li>
        <li><a href="/three">Option 3</a></li>
      </ul>
    </div>
  </div>

Observando el fragmento de código HTML anterior, veamos las siguientes 2 formas de aplicar estilos CSS a los enlaces <a>:

/* Forma 1 */
.menu .options ul li a {
  color: orange;
}

/* Forma 2 */
.menu a {
  color: orange;
}

Mientras que la primera es mucho más específica, es una muy buena práctica en CSS mantener los selectores lo menos específicos posibles para evitar problemas de Especificidad (a.k.a. CSS Peter Griffin):

GIF de Peter Griffin usando CSS

Selector hijo

Aunque el selector descendiente es bastante interesante, nos puede interesar hacer la misma operación, pero en lugar de seleccionar todos los elementos descendientes, seleccionar sólo los descendientes directos del elemento con el símbolo >, descartando así nietos y sucesivos.

#pagina > div {
  background-color: blue;
}

Veamos los elementos seleccionados en el documento de ejemplo para afianzar conceptos:

Selector hijo

Al contrario que en el caso anterior, no se seleccionan todos los elementos <div> descendientes, sino solo aquellos que son hijos directos del primer elemento especificado.

Selector hermano adyacente

Es posible también hacer referencia a los elementos hermanos, es decir, aquellos elementos que están directamente a continuación del elemento especificado. Mediante el símbolo + del selector hermano adyacente, se pueden seleccionar aquellos elementos hermanos que están seguidos el uno de otro (en el mismo nivel):

div.articulo span + span {
  color: blue;
}

Cómo se podrá ver en este nuevo ejemplo, este combinador CSS hará que se seleccionen los elementos span que estén a continuación de un div.articulo span:

Selector hermano adyacente

Obsérvese que el primer elemento <span> no es seleccionado, puesto que es el que estamos tomando de base. Una buena forma para entenderlo es leerlo de la siguiente forma: «todo elemento <span> que esté inmediatamente precedido de un <span>».

Selector hermano general

Si pensamos otras opciones en el ejemplo anterior, es posible que necesitemos ser menos específicos y en lugar de querer seleccionar los elementos hermanos que sean adyacentes, queramos seleccionar todos los hermanos en general, sin necesidad de que sean adyacentes. Esto se puede conseguir con el selector hermano general, simbolizado con el carácter ~:

Selector hermano general

Como se ve en el ejemplo, no es necesario que el elemento strong se encuentre adyacente al primero, sino que basta con que sean hermanos en el mismo nivel.

Selector universal

Por último, el selector universal se simboliza con un asterisco * y es la forma de aplicar ciertos estilos en TODOS Y CADA UNO de los elementos HTML correspondientes.

Selector universal

Este ejemplo selecciona todos los elementos dentro de div#menu. Es importante recalcar la diferencia de seleccionar #menu, a seleccionar todos los elementos dentro de #menu, que es lo que estamos haciendo en este caso.

El selector universal puede ser muy útil en algunos casos para resetear ciertas propiedades de todo un documento, como en el siguiente ejemplo, donde se eliminan los márgenes de todos los elementos del documento HTML, puesto que algunos navegadores ponen márgenes diferentes y esto puede producir ciertas inconsistencias en los diseños:

/* Elimina márgenes y rellenos de todos los elementos de un documento HTML */
* {
  margin: 0;
  padding: 0;
}
Manz
Publicado por Manz

Docente, divulgador informático y freelance. Autor de Emezeta.com, es profesor en la Universidad de La Laguna y dirige el curso de Programación web FullStack y Diseño web FrontEnd de EOI en Tenerife (Canarias). En sus ratos libres, busca GIF de gatos en Internet.