Pseudo-clases en CSS
Aprende a utilizar las pseudo-clases en CSS para aplicar estilos a elementos en estados específicos y mejorar la interactividad de tus sitios web.
Cristian Escalante
Última actualización: 10 de abril de 2025
Pseudo-clases en CSS
Las pseudo-clases son selectores especiales que permiten aplicar estilos a elementos HTML basados en su estado o posición en el documento, sin necesidad de añadir clases o IDs adicionales. Son herramientas poderosas para crear interfaces interactivas y dinámicas.
¿Qué son las pseudo-clases?
Las pseudo-clases se añaden a los selectores CSS y se identifican por comenzar con dos puntos (:
). Permiten seleccionar elementos en estados específicos o en posiciones particulares dentro del documento.
selector:pseudo-clase {
propiedad: valor;
}
Pseudo-clases de interacción del usuario
Estas pseudo-clases se activan cuando el usuario interactúa con un elemento.
Se aplica cuando el puntero del mouse está sobre el elemento.
button:hover {
background-color: #0056b3;
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
}
.enlace:hover {
text-decoration: underline;
color: #ff6600;
}
Se aplica cuando el elemento está siendo activado por el usuario (por ejemplo, cuando se hace clic en un botón).
button:active {
transform: translateY(1px);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}
a:active {
color: #ff0000;
}
Se aplica cuando el elemento tiene el foco (por ejemplo, un campo de formulario seleccionado).
input:focus {
border-color: #4d90fe;
outline: none;
box-shadow: 0 0 0 2px rgba(77, 144, 254, 0.3);
}
.nav-link:focus {
background-color: rgba(0, 0, 0, 0.1);
}
Similar a :focus
, pero solo se aplica cuando el foco es visible para el usuario (generalmente mediante teclado).
button:focus-visible {
outline: 2px solid #4d90fe;
outline-offset: 2px;
}
Se aplica a un elemento que tiene o contiene un elemento enfocado.
form:focus-within {
background-color: #f8f9fa;
}
Pseudo-clases de estado de elementos
y
Seleccionan elementos de formulario deshabilitados o habilitados.
input:disabled {
background-color: #f2f2f2;
cursor: not-allowed;
opacity: 0.7;
}
button:enabled:hover {
background-color: #0056b3;
}
, y
Para elementos de formulario como checkboxes y radio buttons.
input[type="checkbox"]:checked + label {
font-weight: bold;
color: #0066cc;
}
input[type="checkbox"]:indeterminate + label {
font-style: italic;
color: #666666;
}
input:default + label {
text-decoration: underline;
}
, , ,
Para validación de formularios.
input:valid {
border-color: #28a745;
}
input:invalid {
border-color: #dc3545;
}
input:required {
border-left: 4px solid #0066cc;
}
input:optional {
border-left: 4px solid #cccccc;
}
y
Para campos que son o no editables.
input:read-only {
background-color: #f8f9fa;
cursor: default;
}
input:read-write:focus {
background-color: #ffffff;
}
Pseudo-clases estructurales
Estas pseudo-clases seleccionan elementos basados en su posición en el documento.
, ,
Seleccionan el primer, último o único hijo de un elemento.
li:first-child {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
li:last-child {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom: none;
}
.item:only-child {
width: 100%;
}
() y ()
Seleccionan elementos basados en una fórmula.
/* Selecciona elementos pares */
tr:nth-child(even) {
background-color: #f2f2f2;
}
/* Selecciona elementos impares */
tr:nth-child(odd) {
background-color: #ffffff;
}
/* Fórmula: an+b */
li:nth-child(3n+1) {
font-weight: bold;
}
/* Desde el final */
li:nth-last-child(2) {
color: #ff6600;
}
, ,
Similar a las anteriores, pero consideran el tipo de elemento.
p:first-of-type {
font-size: 1.2em;
font-weight: bold;
}
h2:last-of-type {
margin-bottom: 2em;
}
section img:only-of-type {
display: block;
margin: 0 auto;
}
() y ()
img:nth-of-type(3n+1) {
clear: left;
}
p:nth-of-type(odd) {
background-color: #f8f9fa;
}
Selecciona el elemento raíz del documento (generalmente <html>
).
:root {
--color-primary: #0066cc;
--color-secondary: #6c757d;
--font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
Selecciona elementos que no tienen hijos.
.card:empty {
display: none;
}
Pseudo-clases de negación y coincidencia
()
Selecciona elementos que no coinciden con el selector dado.
/* Todos los inputs excepto los de tipo submit */
input:not([type="submit"]) {
border: 1px solid #ccc;
}
/* Todos los elementos excepto el primero */
li:not(:first-child) {
border-top: 1px solid #eee;
}
() y ()
Agrupan selectores (con diferencias en la especificidad).
/* Equivalente a header p, main p, footer p */
:is(header, main, footer) p {
margin-bottom: 1em;
}
/* Similar a :is() pero con especificidad 0 */
:where(header, main, footer) p {
line-height: 1.6;
}
Pseudo-clases de enlaces
y
Para enlaces no visitados y visitados.
a:link {
color: #0066cc;
}
a:visited {
color: #551a8b;
}
Pseudo-clases de idioma y dirección
()
Selecciona elementos basados en el idioma.
:lang(es) q {
quotes: "«" "»";
}
:lang(en) q {
quotes: """ """;
}
()
Selecciona elementos basados en la dirección del texto.
:dir(rtl) {
text-align: right;
}
:dir(ltr) {
text-align: left;
}
Combinando pseudo-clases
Las pseudo-clases pueden combinarse para crear selectores más específicos.
/* Primer elemento hijo que también es un párrafo */
p:first-child {
font-weight: bold;
}
/* Input requerido que está enfocado */
input:required:focus {
border-color: #ff6600;
}
/* Botón deshabilitado al pasar el mouse */
button:disabled:hover {
cursor: not-allowed;
}
Ejemplos prácticos
Navegación con estados
<nav>
<ul class="menu">
<li><a href="#" class="active">Inicio</a></li>
<li><a href="#">Productos</a></li>
<li><a href="#">Servicios</a></li>
<li><a href="#">Contacto</a></li>
</ul>
</nav>
.menu a {
display: block;
padding: 10px 15px;
color: #333;
text-decoration: none;
transition: all 0.3s ease;
}
.menu a:hover {
background-color: #f0f0f0;
color: #0066cc;
}
.menu a:active {
background-color: #e0e0e0;
}
.menu a.active {
background-color: #0066cc;
color: white;
}
.menu a.active:hover {
background-color: #0056b3;
}
Formulario con validación visual
<form class="contact-form">
<div class="form-group">
<label for="name">Nombre *</label>
<input type="text" id="name" required>
</div>
<div class="form-group">
<label for="email">Email *</label>
<input type="email" id="email" required>
</div>
<div class="form-group">
<label for="message">Mensaje</label>
<textarea id="message"></textarea>
</div>
<button type="submit">Enviar</button>
</form>
.form-group {
margin-bottom: 15px;
}
.contact-form input,
.contact-form textarea {
width: 100%;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
transition: all 0.3s ease;
}
.contact-form input:focus,
.contact-form textarea:focus {
border-color: #0066cc;
box-shadow: 0 0 0 2px rgba(0, 102, 204, 0.2);
outline: none;
}
.contact-form input:required,
.contact-form textarea:required {
border-left: 3px solid #0066cc;
}
.contact-form input:invalid {
border-color: #dc3545;
}
.contact-form input:valid {
border-color: #28a745;
}
.contact-form button {
padding: 10px 15px;
background-color: #0066cc;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.contact-form button:hover {
background-color: #0056b3;
}
.contact-form button:active {
transform: translateY(1px);
}
Tabla con filas alternadas
<table class="data-table">
<thead>
<tr>
<th>ID</th>
<th>Nombre</th>
<th>Precio</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Producto A</td>
<td>$10.00</td>
</tr>
<tr>
<td>2</td>
<td>Producto B</td>
<td>$15.00</td>
</tr>
<tr>
<td>3</td>
<td>Producto C</td>
<td>$20.00</td>
</tr>
</tbody>
</table>
.data-table {
width: 100%;
border-collapse: collapse;
}
.data-table th,
.data-table td {
padding: 10px;
text-align: left;
border-bottom: 1px solid #ddd;
}
.data-table thead tr {
background-color: #f2f2f2;
}
.data-table tbody tr:nth-child(odd) {
background-color: #f9f9f9;
}
.data-table tbody tr:hover {
background-color: #f0f0f0;
}
.data-table tbody tr:first-child {
border-top: 2px solid #ddd;
}
Consideraciones de rendimiento
- Las pseudo-clases estructurales como
:nth-child()
pueden afectar al rendimiento en documentos grandes. :not()
con selectores complejos puede ser costoso en términos de rendimiento.- Evita anidar demasiadas pseudo-clases para mantener el código eficiente.
Compatibilidad con navegadores
La mayoría de las pseudo-clases básicas tienen buen soporte en navegadores modernos. Sin embargo, algunas de las más recientes como :is()
, :where()
o :focus-visible
pueden requerir comprobación de compatibilidad.
/* Alternativa para navegadores que no soportan :focus-visible */
button:focus {
outline: 2px solid #4d90fe;
}
button:focus:not(:focus-visible) {
outline: none;
}
Conclusión
Las pseudo-clases son herramientas poderosas que permiten crear interfaces más dinámicas e interactivas sin necesidad de JavaScript o clases adicionales. Dominarlas te permitirá escribir CSS más limpio, semántico y eficiente.