Seudoclases

The CSS Podcast - 015: Pseudo-classes (El podcast de CSS, episodio 15: Seudoclases)

Supongamos que tienes un formulario de registro por correo electrónico y quieres que el campo del formulario de correo electrónico tenga un borde rojo si contiene una dirección de correo electrónico no válida. ¿Cómo puede hacerlo? Puedes usar una seudoclase :invalid de CSS, que es una de las muchas seudoclases proporcionadas por el navegador.

Una seudoclase te permite aplicar estilos según los cambios de estado y los factores externos. Esto significa que tu diseño puede reaccionar a la entrada del usuario, como una dirección de correo electrónico no válida. Estos se tratan en el módulo selectores, y este módulo te guiará por ellos con más detalle.

A diferencia de los seudoelementos, sobre los que puedes obtener más información en el módulo anterior, las seudoclases se vinculan a estados específicos en los que puede estar un elemento, en lugar de aplicar un estilo general a partes de ese elemento.

Estados interactivos

Las siguientes seudoclases se aplican debido a una interacción que un usuario tiene con tu página.

:hover

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 2.

Source

Si un usuario tiene un dispositivo apuntador, como un mouse o un panel táctil, y lo coloca sobre un elemento, puedes engancharte a ese estado con :hover para aplicar estilos. Esta es una forma útil de sugerir que se puede interactuar con un elemento.

:active

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 1.

Source

Este estado se activa cuando se interactúa de forma activa con un elemento, por ejemplo, cuando se hace clic, antes de que se suelte el clic. Si se usa un dispositivo apuntador, como un mouse, este estado se da cuando comienza el clic y aún no se soltó.

:focus, :focus-within y :focus-visible

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 1.

Source

Si un elemento puede recibir el enfoque, como un <button>, puedes reaccionar a ese estado con la seudoclase :focus.

También puedes reaccionar si un elemento secundario de tu elemento recibe el enfoque con :focus-within.

Los elementos enfocables, como los botones, mostrarán un anillo de enfoque cuando estén enfocados, incluso cuando se haga clic en ellos. En este tipo de situación, un desarrollador aplicará el siguiente CSS:

button:focus {
    outline: none;
}

Este CSS quita el anillo de enfoque predeterminado del navegador cuando un elemento recibe el enfoque, lo que presenta un problema de accesibilidad para los usuarios que navegan por una página web con un teclado. Si no hay un estilo de enfoque, no podrán hacer un seguimiento de dónde está el enfoque actualmente cuando usen la tecla de tabulación. Con :focus-visible, puedes presentar un estilo de enfoque cuando un elemento recibe el enfoque con el teclado y, al mismo tiempo, usar la regla outline: none para evitarlo cuando un dispositivo de puntero interactúa con él.

button:focus {
    outline: none;
}

button:focus-visible {
    outline: 1px solid black;
}

:target

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 1.3.

Source

La seudoclase :target selecciona un elemento que tiene un id que coincide con un fragmento de URL. Supongamos que tienes el siguiente código HTML:

<article id="content">
    <!-- ... -->
</article>

Puedes adjuntar estilos a ese elemento cuando la URL contiene #content.

#content:target {
    background: yellow;
}

Esto es útil para destacar áreas a las que se podría haber vinculado específicamente, como el contenido principal de un sitio web, con un vínculo de acceso directo.

Estados históricos

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 1.

Source

La seudoclase :link se puede aplicar a cualquier elemento <a> que tenga un valor href que aún no se haya visitado.

:visited

Puedes aplicar un diseño a un vínculo que el usuario ya visitó con la seudoclase :visited. Este es el estado opuesto a :link, pero tienes menos propiedades CSS para usar por motivos de seguridad. Solo puedes aplicar estilo a color, background-color, border-color, outline-color y el color de los elementos fill y stroke de SVG.

El orden es importante

Si defines un estilo :visited, se puede anular con una seudoclase de vínculo con al menos la misma especificidad. Por este motivo, se recomienda que uses la regla LVHA para aplicar estilo a los vínculos con pseudoclases en un orden específico: :link, :visited, :hover, :active.

a:link {}
a:visited {}
a:hover {}
a:active {}

Estados del formulario

Las siguientes pseudoclases pueden seleccionar elementos de formulario en los diversos estados en los que pueden encontrarse durante la interacción con ellos.

:disabled y :enabled

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 3.1.

Source

Si el navegador inhabilita un elemento de formulario, como un <button>, puedes engancharte a ese estado con la seudoclase :disabled. La seudoclase :enabled está disponible para el estado opuesto, aunque los elementos de formulario también son :enabled de forma predeterminada, por lo que es posible que no necesites usar esta seudoclase.

:checked y :indeterminate

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 3.1.

Source

La seudoclase :checked está disponible cuando un elemento de formulario compatible, como una casilla de verificación o un botón de selección, está en estado seleccionado.

El estado :checked es un estado binario (verdadero o falso), pero las casillas de verificación tienen un estado intermedio cuando no están marcadas ni desmarcadas. Esto se conoce como el estado :indeterminate.

Un ejemplo de este estado es cuando tienes un control "Seleccionar todo" que marca todas las casillas de verificación de un grupo. Si el usuario desmarcara una de estas casillas de verificación, la casilla de verificación raíz ya no representaría que "todas" están marcadas, por lo que debería pasar a un estado indeterminado.

El elemento <progress> también tiene un estado indeterminado al que se le puede aplicar un diseño. Un caso de uso común es darle una apariencia rayada para indicar que no se sabe cuánto más se necesita.

:placeholder-shown

Browser Support

  • Chrome: 47.
  • Edge: 79.
  • Firefox: 51.
  • Safari: 9.

Source

Si un campo de formulario tiene un atributo placeholder y no tiene valor, se puede usar la seudoclase :placeholder-shown para adjuntar estilos a ese estado. En cuanto haya contenido en el campo, ya sea que tenga un placeholder o no, este estado dejará de aplicarse.

Estados de validación

Browser Support

  • Chrome: 10.
  • Edge: 12.
  • Firefox: 4.
  • Safari: 5.

Source

Puedes responder a la validación de formularios HTML con pseudoclases como :valid, :invalid y :in-range. Las seudoclases :valid y :invalid son útiles para contextos como un campo de correo electrónico que tiene un pattern que debe coincidir para que sea un campo válido. Este estado de valor válido se puede mostrar al usuario, lo que lo ayuda a comprender que puede avanzar al siguiente campo de forma segura.

La seudoclase :in-range está disponible si una entrada tiene min y max, como una entrada numérica y el valor está dentro de esos límites.

Con los formularios HTML, puedes determinar que un campo es obligatorio con el atributo required. La seudoclase :required estará disponible para los campos obligatorios. Los campos que no son obligatorios se pueden seleccionar con la seudoclase :optional.

Selecciona elementos por su índice, orden y ocurrencia

Hay un grupo de seudoclases que seleccionan elementos según su ubicación en el documento.

:first-child y :last-child

Browser Support

  • Chrome: 4.
  • Edge: 12.
  • Firefox: 3.
  • Safari: 3.1.

Source

Si quieres encontrar el primer o el último elemento, puedes usar :first-child y :last-child. Estas pseudoclases devolverán el primer o el último elemento de un grupo de elementos hermanos.

:only-child

Browser Support

  • Chrome: 2.
  • Edge: 12.
  • Firefox: 1.5.
  • Safari: 3.1.

Source

También puedes seleccionar elementos que no tienen hermanos con la seudoclase :only-child.

:first-of-type y :last-of-type

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 3.5.
  • Safari: 3.1.

Source

Puedes seleccionar :first-of-type y :last-of-type, que, en principio, parecen hacer lo mismo que :first-child y :last-child, pero considera este código HTML:

<div class="my-parent">
    <p>A paragraph</p>
    <div>A div</div>
    <div>Another div</div>
</div>

Y este CSS:

.my-parent div:first-child {
    color: red;
}

Ningún elemento se colorearía de rojo porque el primer elemento secundario es un párrafo y no un div. La seudoclase :first-of-type es útil en este contexto.

.my-parent div:first-of-type {
    color: red;
}

Aunque el primer <div> es el segundo hijo, sigue siendo el primero de su tipo dentro del elemento .my-parent, por lo que, con esta regla, se coloreará de rojo.

:nth-child y :nth-of-type

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 3.5.
  • Safari: 3.1.

Source

Tampoco estás limitado a los primeros y últimos elementos secundarios, ni a los tipos. Las seudoclases :nth-child y :nth-of-type te permiten especificar un elemento que se encuentra en un índice determinado. La indexación en los selectores de CSS comienza en 1.

Las seudoclases :nth-last-child() y :nth-last-of-type() cuentan desde el final, en lugar del principio.

También puedes pasar más de un índice a estas seudoclases. Si quisieras seleccionar todos los elementos pares, puedes usar :nth-child(even).

También puedes crear selectores más complejos que encuentren elementos en intervalos regulares con la microsintaxis An+B.

li:nth-child(3n+3) {
    background: yellow;
}

Este selector selecciona cada tercer elemento, comenzando por el elemento 3. El n en esta expresión es el índice, que comienza en cero, y el 3 (3n) es el valor por el que multiplicas ese índice.

Supongamos que tienes 7 elementos <li>. El primer elemento seleccionado es 3 porque 3n+3 se traduce como (3 * 0) + 3. La siguiente iteración elegiría el elemento 6 porque n ahora aumentó a 1, por lo que (3 * 1) + 3). Esta expresión funciona para :nth-child y :nth-of-type.

:nth-child() y :nth-last-child() también admiten una sintaxis "de S" que te permite filtrar las coincidencias con un selector, de forma similar a :nth-of-type(). li:nth-of-type(even) es equivalente a :nth-child(even of li). Mientras que :nth-of-type solo te permite filtrar según el tipo de elemento (como li o p), la sintaxis "de S" te permite filtrar en cualquier selector.

Si tienes una tabla, es posible que desees agregar rayas a cada segunda fila. Si bien puedes segmentar cada segunda fila contr:nth-child(even), esto no funciona si filtras algunas filas. Si implementas el filtrado aplicando el atributo hidden, puedes agregar of :not([hidden]) al selector para filtrar previamente los elementos ocultos antes de seleccionar las filas pares.

tr:nth-child(even of :not([hidden])){
  background: lightgrey;
}

Puedes probar este tipo de selector en este probador de nth-child o en esta herramienta de selector de cantidad.

:only-of-type

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 3.5.
  • Safari: 3.1.

Source

Por último, puedes encontrar el único elemento de un tipo determinado en un grupo de elementos hermanos con :only-of-type. Esto es útil si deseas seleccionar listas con solo un elemento o si quieres encontrar el único elemento en negrita de un párrafo.

Cómo encontrar elementos vacíos

A veces, puede ser útil identificar elementos completamente vacíos, y también hay una seudoclase para eso.

:empty

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 3.1.

Source

Si un elemento no tiene hijos, se le aplica la seudoclase :empty. Sin embargo, los elementos secundarios no son solo elementos HTML o nodos de texto: también pueden ser espacios en blanco, lo que puede ser confuso cuando depuras el siguiente código HTML y te preguntas por qué no funciona con :empty:

<div>
</div>

El motivo es que hay algunos espacios en blanco entre las etiquetas de apertura y cierre de <div>, por lo que :empty no funcionará.

La seudoclase :empty puede ser útil si tienes poco control sobre el código HTML y deseas ocultar elementos vacíos, como un editor de contenido WYSIWYG. Aquí, un editor agregó un párrafo vacío y suelto.

<article class="post">
 <p>Donec ullamcorper nulla non metus auctor fringilla.</p>
 <p></p>
 <p>Curabitur blandit tempus porttitor.</p>
</article>

Con :empty, puedes encontrarlo y ocultarlo.

.post :empty {
    display: none;
}

Cómo buscar y excluir varios elementos

Algunas pseudoclases te ayudan a escribir CSS más compacto.

:is()

Browser Support

  • Chrome: 88.
  • Edge: 88.
  • Firefox: 78.
  • Safari: 14.

Source

Si deseas encontrar todos los elementos secundarios h2, li y img en un elemento .post, podrías escribir una lista de selectores como la siguiente:

.post h2,
.post li,
.post img {
    
}

Con la seudoclase :is(), puedes escribir una versión más compacta:

.post :is(h2, li, img) {
    /* ... */
}

La seudoclase :is no solo es más compacta que una lista de selectores, sino que también es más tolerante. En la mayoría de los casos, si hay un error o un selector no admitido en una lista de selectores, toda la lista dejará de funcionar. Si hay un error en los selectores pasados en una seudoclase :is, se ignorará el selector no válido, pero se usarán los que sean válidos.

:not()

Browser Support

  • Chrome: 1.
  • Edge: 12.
  • Firefox: 1.
  • Safari: 3.1.

Source

También puedes excluir elementos con la seudoclase :not(). Por ejemplo, puedes usarlo para aplicar un diseño a todos los vínculos que no tengan un atributo class.

a:not([class]) {
    color: blue;
}

Una pseudoclase :not también puede ayudarte a mejorar la accesibilidad. Por ejemplo, un <img> debe tener un alt, incluso si es un valor vacío, por lo que podrías escribir una regla de CSS que agregue un contorno rojo grueso a las imágenes no válidas:

img:not([alt]) {
    outline: 10px red;
}

:has()

¿Qué sucede si quieres aplicar un diseño a los elementos según lo que contienen? Puedes usar la seudoclase :has() para hacerlo. Por ejemplo, es posible que desees aplicar estilos a los botones que incluyen íconos.

 button:has(svg) {
  /* ... */
}

En su configuración más básica, como en el ejemplo anterior, puedes considerar :has() como un selector principal. También puedes usar el selector principal coincidente combinado con otros selectores para segmentar otros elementos.

form:has(input:valid) label {
  font-weight: bold;
}

form:has(input:valid) label::after {
  content: "✅";
}

En este ejemplo, aplicamos estilos al elemento de etiqueta y al seudoelemento label::after cuando la entrada del formulario tiene una seudoclase valid.

La seudoclase :has() no se puede anidar dentro de otra :has(), pero se puede combinar con otras seudoclases.

:is(h1, h2, h3):has(a) {
   /* ... */
}

La lista de selectores es inflexible, por lo que, si alguno de los selectores de la lista no es válido, se ignorarán todas las reglas de estilo.

.my-element:has(img, ::before) {
  /* any styles here will be discarded since pseudo elements can't be included in the :has() selector list */
}

Verifica tus conocimientos

Pon a prueba tus conocimientos sobre las pseudoclases

Las seudoclases actúan como si se hubiera aplicado una clase de forma dinámica a un elemento, mientras que los seudoelementos actúan sobre un elemento en sí.

Verdadero
Presta atención al uso de un solo : o de dos como carácter distintivo clave en el selector.
Falso
Los seudoelementos son para partes, y las seudoclases son para estados.

¿Cuál de las siguientes opciones es una seudoclase funcional?

:is()
🎉
:target
Las seudoclases funcionales tienen un () después de ellas para indicar que aceptan parámetros.
:empty
Las seudoclases funcionales tienen un () después de ellas para indicar que aceptan parámetros.
:not()
🎉

¿Cuáles de las siguientes pseudoclases se deben a una interacción del usuario?

:hover
🎉
:press
Vuelve a intentarlo.
:squeeze
Vuelve a intentarlo.
:target
🎉
:focus-within
🎉

¿Cuáles de las siguientes son seudoclases de estado <form>?

:enabled
🎉
:fresh
Vuelve a intentarlo.
:indeterminate
🎉
:checked
🎉
:in-range
🎉
:loading
Vuelve a intentarlo.
:valid
🎉