CSS: Pseudo-clases y pseudo-elementos

En esta lección y en la lección CSS Selectores (1) se comentan los diferentes tipos de selectores definidos en la recomendación Selectors Level 3 (2ª edición), publicada en noviembre de 2018.

Los selectores son la parte de las reglas que indican al navegador a qué elementos se van a aplicar las propiedades incluidas en las declaraciones.

En esta lección se comentan únicamente las pseudo-clases y los pseudo-elementos.

Qué son las pseudo-clases y los pseudo-elementos

Las hojas de estilo asocian características de estilo a los elementos basándose en las etiquetas de los elementos y en su posición relativa (en el árbol del documento). Las pseudo-clases y los pseudo-elementos permiten hacer referencia a determinados elementos sin basarse en la información contenida en el árbol del documento.

La diferencia entre pseudo-clases y pseudo-elementos es sutil. En general, los pseudo-elementos suelen hacer referencia a determinadas partes de un elemento, mientras que las pseudo-clases suelen hacer referencia al estado del elemento.

Otra diferencia importante es que un pseudo-elemento sólo puede aparecer al final de un selector, mientras que una pseudo-clase puede aparecer en cualquier elemento del selector.

En CSS 2, la sintaxis de las pseudo-clases y los pseudo-elementos era la misma, etiqueta:pseudo-elemento-o-pseudo-clase (es decir, el nombre de la etiqueta seguido de dos puntos y del nombre del pseudo-elemento o de la pseudo-clase). En 2011, en la recomendación CSS 3 Selectores (cuya segunda versión CSS 3 Selectores se publicó en 2018), se modificó la notación de los pseudo-elementos a etiqueta::pseudo-elemento (es decir, el nombre de la etiqueta seguido dos veces de dos puntos y del nombre del pseudo-elemento) para distinguir unos de otros, pero permitiendo utilizar también la antigua notación.

La pseudo-clase :first-child

La pseudo-clase :first-child hace referencia al primer elemento de un tipo contenido dentro de otro. El ejemplo siguiente muestra cómo identificar al primer párrafo dentro de una división sin necesidad de asignar ninguna clase al párrafo.

div {
  border: black 5px solid;
  margin: 10px;
  padding: 10px;
}

div p:first-child {
  color: red;
}

Enlace externo

Es necesario que el tipo del primer elemento hijo en la página web sea el indicado en la hoja de estilo. En el ejemplo siguiente, el primer elemento dentro de la división no es un <p>, sino un <pre>, así que no se le aplica el estilo indicado en la hoja de estilo.

div {
  border: black 5px solid;
  margin: 10px;
  padding: 10px;
}

div p:first-child {
  color: red;
}
Enlace externo

En el ejemplo siguiente, la pseudo-clase :first-child se aplica al primer elemento dentro de la división, sea cual sea el elemento, ya que en la hoja de estilo no se especifica el elemento.

div {
  border: black 5px solid;
  margin: 10px;
  padding: 10px;
}

div :first-child {
  color: red;
}
Enlace externo

Las pseudo-clases de enlace :link y :visited

La pseudo clase :link (o a:link) permite especificar el aspecto de los enlaces que todavía no han sido visitados.

La pseudo clase :visited (o a:visited) permite especificar el aspecto de los enlaces que sí han sido visitados.


La pseudo-clase :link establece el aspecto de los enlaces no visitados, pero si sólo se incluye en la hoja de estilo la pseudo-clase :link, el aspecto no cambiará al hacer clic en los enlaces:

a:link {
  background-color: lightblue;
}
Enlace externo

Es necesario incluir las dos pseudo-clases :link y :link para que el aspecto del enlace cambie al hacer clic en él.

a:link {
  background-color: lightblue;
}

a:visited {
  background-color: coral;
}
Enlace externo

Los navegadores "recuerdan" los enlaces visitados hasta que se borra el historial en el navegador.

a:link {
  color: green;
}
Enlace externo
a:visited {
  color: red;
}
Enlace externo

En la recomendación CSS 2 se podía utilizar la pseudo clase :visited para modificar cualquier propiedad, pero como una página web maliciosa podía utilizar esta propiedad para saber las páginas que el usuario había visitado, los navegadores han reducido el número de propiedades que se pueden aplicar con esta propiedad. La recomendación CSS 2.1 alerta de ese peligro y permite que los navegadores no permitan modificar ninguna propiedad o sólo admitan algunas propiedades.

Enlaces relacionados: Privacy and the :visited selector - Plugging the CSS History Leak

Teóricamente, las propiedades que podrían modificarse sin riesgo son las relacionadas con colores. El siguiente ejemplo prueba esas cuatro propiedades. En el ejemplo se establecen antes las propiedades en la etiqueta <a> porque si no Firefox y Chrome no la modifican.

a {
  background-color: white;
  color: blue;
  border: orange 3px solid;
  outline: green 3px solid;
}

a:visited {
  background-color: yellow;
  color: red;
  border-color: black;
  outline-color: red;
}
Enlace externo

Si queremos cambiar el aspecto de un enlace, pero sin distinguir que el enlace se haya visitado o no, tenemos entonces tres opciones:

Las pseudo-clases dinámicas :hover, :active y :focus

La pseudo-clase dinámica :hover

La pseudo-clase :hover permite especificar el aspecto del elemento sobre el que se encuentra el ratón.

p {
  background-color: white;
  color: black;
}

a:hover {
  background-color: black;
  color: white;
}
Enlace externo
p {
  background-color: white;
  color: black;
}

p:hover {
  background-color: black;
  color: white;
}
Enlace externo

La pseudo-clase dinámica :active

La pseudo-clase :active permite especificar el aspecto de un elemento cuando se hace clic sobre él (y mientras se mantiene el botón del ratón apretado).

p {
  background-color: white;
  color: black;
}

a:active {
  background-color: black;
  color: white;
}
Enlace externo
p {
  background-color: white;
  color: black;
}

p:active {
  background-color: black;
  color: white;
}
Enlace externo

La pseudo-clase dinámica :focus

La pseudo-clase :focus permite especificar el aspecto de un elemento cuando este tiene el foco. Los elementos que admiten el foco en una página web son aquellos que reaccionan a entrada por teclado (por ejemplo, los elementos de los formularios o los enlaces). En el ejemplo siguiente, al hacer clic en un campo de texto (o cambiar de campo con el tabulador), el campo seleccionado se resalta con un borde rojo.

input:focus {
  border: red 2px dotted;
  padding: 2px;
}
Enlace externo

En construcciónCuando se utiliza a la vez :link :visited y :hover los navegadores antiguos hacían cada uno una cosa distinta, pero es posible que los modernos no tengan ese problema.

La pseudo-clase de idioma :lang()

La pseudo-clase de idioma :lang() permite especificar el aspecto de los elementos de un idioma determinado. En el ejemplo siguiente se cambia las comillas utilizadas en una cita <q> según el idioma indicado en el atributo lang.

<p>Ambrose Bierce dijo (más o menos) que <q lang="es">una cita es una manera de repetir erróneamente las palabras de otros</q>.</p>

<p>Ambrose Bierce dijo (más o menos) que <q lang="en">a quotation is the act of repeating erroneously the words of another</q>.</p>
q:lang(es) {
  quotes: "«" "»";
}

q:lang(en) {
  quotes: '"' '"';
}
Enlace externo

Los pseudo-elementos ::first-line y ::first-letter

El pseudo-elemento ::first-line

El pseudo-elemento ::first-line permite especificar el aspecto de la primera línea de texto.

Incorrecto en Chrome Correcto en Firefox
p::first-line {
  text-transform: uppercase;
}
Enlace externo Diferencias entre navegadores

En el ejemplo anterior, al hacer zoom o variar el ancho de la ventana se observa únicamente la primera línea de texto está en mayúsculas.

Nota: Aunque Chrome muestra la primera línea de texto en mayúsculas, no lo hace correctamente, como se comenta en la página de diferencias entre navegadores.

El pseudo-elemento ::first-letter

El pseudo-elemento ::first-letter permite especificar el aspecto de la primera letra de texto.

p::first-letter {
  color: red;
}
Enlace externo
p::first-letter {
  background-color: pink;
  color: red;
  float: left;
  font-family: monospace;
  font-size: 400%;
}
Enlace externo

Si hay una imagen al principio del elemento, el aspecto de la primera letra de texto no se modifica.

p::first-letter {
  color: red;
}
Enlace externo

Si la imagen situada al principio del elemento es una imagen flotante, Firefox no modifica el aspecto de la primera letra de texto, aunque Chrome sí lo hace.

Incorrecto en Chrome Correcto en Firefox
p::first-letter {
  color: red;
}

img {
  float: right;
}
Enlace externo Diferencias entre navegadores
Incorrecto en Chrome Correcto en Firefox
p::first-letter {
  color: red;
}

img {
  float: left;
}
Enlace externo Diferencias entre navegadores

Nota: En realidad no tengo claro si quien lo hace bien es Firefox o Chrome.


Si el primer carácter no es un carácter alfanumérico, el pseudo-elemento se aplica hasta el primer carácter alfanumérico:

p::first-letter {
  color: red;
}
Enlace externo

Los pseudo-elementos ::before y ::after

Contenido generado: content

Los pseudo-elementos ::before y ::after permiten añadir contenido a un elemento desde la hoja de estilo, al principio o al final del elemento.

El contenido generado no puede seleccionarse con el ratón (para copiarlo y pegarlo en otro documento, por ejemplo).

El contenido generado mediante la propiedad content puede incluir texto:

p.cuidado::before {
  content: "Aviso: ";
  font-weight: bold;
  text-decoration: underline;
}
Enlace externo
p.autor-barto::after {
  content: " (escrito por Barto).";
}
Enlace externo

El contenido generado mediante la propiedad content puede incluir una imagen indicando su URI:

p.ff::before {
  content: url("../icono-ff.svg");
}
Enlace externo

No está permitido incluir etiquetas html en la propiedad content. Los navegadores muestran las etiquetas como texto, no como código html.

p.cuidado::before {
  content: "<em>Aviso:</em> ";
}
Enlace externo

Generar contadores: counter, counter-increment y counter-reset

Se pueden generar contadores en los pseudo-elementos ::after y ::before mediante la propiedad content y el valor counter(nombre_de_contador). El contador debe ponerse a cero con la propiedad counter-reset y aumentarse con la propiedad counter-increment.

En los ejemplos siguientes se ha definido un contador que se llama cuenta-parrafos. Este contador se genera al principio de cada párrafo, se pone a cero con el elemento <pre> y se incrementa en cada párrafo.

pre {
  counter-reset: cuenta-parrafos;
}

p::before {
  content: counter(cuenta-parrafos);
  counter-increment: cuenta-parrafos;
}
Enlace externo
pre {
  counter-reset: cuenta-parrafos;
}

p::before {
  content: counter(cuenta-parrafos);
  counter-increment: cuenta-parrafos;
}
Enlace externo

El contador puede incrementarse en cualquier cantidad entera, como muestra el ejemplo siguiente:

pre {
  counter-reset: cuenta-parrafos;
}

p::before {
  content: counter(cuenta-parrafos);
  counter-increment: cuenta-parrafos 10;
}
Enlace externo

Junto con el contador se puede generar texto, como muestra el ejemplo siguiente:

pre {
  counter-reset: cuenta-parrafos;
}

p::before {
  content: counter(cuenta-parrafos)". ";
  counter-increment: cuenta-parrafos;
}
Enlace externo

El contador predeterminado muestra números enteros, pero se puede utilizar cualquiera de los estilos de listas como estilo de contador. El estilo se indica en la propiedad content mediante el valor counter(nombre_de_contador, estilo_de_lista), como muestra el ejemplo siguiente:

pre {
  counter-reset: cuenta-parrafos;
}

p::before {
  content: counter(cuenta-parrafos, upper-roman)". ";
  counter-increment: cuenta-parrafos;
}
Enlace externo

Se pueden utilizar varios contadores simultáneamente, como muestra el ejemplo siguiente:

h1 {
  counter-reset: cuenta-parrafos;
  counter-reset: cuenta-apartados;
}

h2 {
  counter-reset: cuenta-parrafos;
}

h2::before {
  content: counter(cuenta-apartados, upper-alpha)". ";
  counter-increment: cuenta-apartados;
}

p::before {
  content: counter(cuenta-apartados, upper-alpha)"-"counter(cuenta-parrafos)". ";
  counter-increment: cuenta-parrafos;
}
Enlace externo