W3docs

CSS :invalid Pseudoclase

Aprende cómo CSS :invalid aplica estilos a campos de formulario que no superan las restricciones de validación, con ejemplos, consejos de accesibilidad y soporte de navegadores.

La pseudoclase CSS :invalid coincide con los controles asociados a formularios — como <input>, <select> y <textarea> — cuyo valor actual no supera las restricciones de validación integradas del navegador. Es la mitad visual de la API de validación de restricciones de HTML: el navegador evalúa la validez, y :invalid te permite aplicar estilos al resultado con CSS puro, sin necesidad de JavaScript.

Esta página explica exactamente cuándo coincide :invalid, cómo aplicar estilos sin alarmar a los usuarios antes de que hayan escrito nada, el comportamiento peculiar de los botones de opción, la alternativa moderna :user-invalid y cómo mantener accesible la retroalimentación de errores.

¿Cuándo coincide un elemento con :invalid?

Un control coincide con :invalid cuando tiene al menos una restricción de validación y su valor actual viola esa restricción. Factores desencadenantes habituales:

RestricciónAtributo / tipoFalla cuando…
Requerido pero vacíorequiredel campo no tiene valor
Formato de correo incorrectotype="email"el valor no es un correo electrónico sintácticamente válido
Formato de URL incorrectotype="url"el valor no es una URL absoluta válida
Fuera de rangomin / max en type="number", type="date", etc.el valor está fuera del rango permitido
Paso incorrectostepel valor no se alinea con el intervalo de paso
No coincide con el patrónpatternel valor no coincide con la expresión regular
Demasiado largo / cortominlength / maxlengthla longitud del valor está fuera del rango permitido

Si un control no tiene restricciones en absoluto (un <input type="text"> simple sin atributos adicionales), se considera sin restricciones y ni :valid ni :invalid se le aplican.

Un elemento <fieldset> coincide con :invalid cuando alguno de sus controles de formulario descendientes es inválido.

Para el caso contrario, consulta la pseudoclase :valid, que coincide con controles que superan todas las restricciones. La pseudoclase :required coincide con los campos requeridos independientemente de si tienen un valor.

Sintaxis

:invalid {
  /* declarations applied to all invalid form controls */
}

Limita :invalid a un tipo de elemento específico para mantener los estilos predecibles:

input:invalid,
textarea:invalid {
  border: 2px solid #c00;
  outline: none;
}

Ejemplo básico

El campo de correo electrónico que aparece a continuación está pre-rellenado con una dirección mal formada ("not-an-email"), por lo que coincide con input:invalid al cargar y recibe un borde rojo.

<!DOCTYPE html>
<html>
  <head>
    <title>:invalid example</title>
    <style>
      input:invalid {
        border: 2px solid #c00;
        background-color: #fff0f0;
      }
      input:valid {
        border: 2px solid #090;
        background-color: #f0fff0;
      }
    </style>
  </head>
  <body>
    <h2>:invalid selector example</h2>
    <form>
      <label for="email">Email:</label>
      <input id="email" type="email" value="not-an-email" required />
    </form>
  </body>
</html>

Evitar el "rojo prematuro"

El problema más común con :invalid: un campo required vacío ya es inválido en el momento en que se carga la página, por lo que un formulario nuevo puede mostrarse en rojo antes de que el usuario haya escrito nada. Eso resulta acusatorio.

Opción 1 — solo aplicar estilos mientras el campo está enfocado

Mostrar el borde de error solo mientras el usuario está activamente en el campo:

input:invalid:focus {
  border-color: #c00;
  outline: 2px solid #c00;
  outline-offset: 1px;
}

Esto es sencillo, pero desaparece en el momento en que el usuario avanza con el tabulador, por lo que un campo requerido en blanco vuelve a verse bien.

Opción 2 — ocultar el error mientras el marcador de posición esté visible

:placeholder-shown es verdadero cuando se muestra el texto del marcador de posición (es decir, el campo está vacío). Combinarlo con :not hace que el estilo de :invalid solo se active una vez que el usuario haya escrito algo:

/* Only show the error style when the field has a value that is invalid */
input:invalid:not(:placeholder-shown) {
  border-color: #c00;
}

Esto es eficaz, pero requiere que cada campo tenga un atributo placeholder definido; de lo contrario, :placeholder-shown nunca es verdadero y la protección no hace nada.

Opción 3 — usar :user-invalid (estándar moderno)

La pseudoclase :user-invalid fue diseñada específicamente para resolver este problema. Se comporta como :invalid pero solo coincide después de que el usuario haya interactuado con el control (escrito en él, salido de él o enviado el formulario):

/* Supported in all modern browsers as of 2024 */
input:user-invalid {
  border-color: #c00;
}

/* Fallback for older browsers */
@supports not selector(:user-invalid) {
  input:invalid:not(:placeholder-shown) {
    border-color: #c00;
  }
}

:user-invalid es la solución más limpia cuando puedes depender de ella. Firefox la ha soportado como :-moz-ui-invalid durante años; el estándar :user-invalid está ahora en todos los navegadores modernos.

Enfoque de estilos

Un borde rojo completo de 2 px es legible pero chocante. Considera combinar un cambio de borde con una sutil box-shadow para un aspecto más suave:

input:invalid:not(:placeholder-shown) {
  border-color: #c00;
  box-shadow: 0 0 0 3px rgba(204, 0, 0, 0.15);
}

Evita depender únicamente del color; consulta la sección de Accesibilidad más abajo.

Peculiaridades

Botones de opción

Cuando un grupo de botones de opción tiene required en una de sus entradas, cada botón del grupo coincide con :invalid mientras ninguno esté seleccionado. Aplicar estilos a pequeños círculos de radio no es práctico; en su lugar, aplica estilos al <fieldset> o <label> que los rodea:

/* Style the fieldset, not the radio buttons themselves */
fieldset:invalid {
  border: 2px solid #c00;
  border-radius: 4px;
  padding: 8px 12px;
}

Todos los botones de opción de un grupo comparten el mismo atributo name — eso es lo que los convierte en un grupo dentro del modelo de validez del navegador.

Campos opcionales vacíos

Un <input type="text"> simple sin required, sin pattern y sin restricciones de longitud siempre es :valid aunque esté vacío. :invalid solo se activa cuando existe una restricción y se viola.

select y textarea

<select> coincide con :invalid si es required y su value actual es una cadena vacía (un patrón común es una <option value=""> de marcador de posición "-- elegir --" al inicio). <textarea> sigue las mismas reglas que <input> para required, minlength y maxlength.

Firefox y :-moz-ui-invalid

Firefox ha aplicado durante mucho tiempo estilos mediante :-moz-ui-invalid, que solo se activa después de la interacción del usuario, lo que efectivamente incorpora el comportamiento de :user-invalid. Si añades tus propias reglas :invalid y las pruebas en Firefox, el campo puede verse bien (porque la protección de interacción del usuario predeterminada del navegador está activada), y luego comportarse de manera diferente en Chrome (donde la protección predeterminada está desactivada). Define reglas explícitas y usa :user-invalid con un respaldo para obtener un comportamiento coherente.

Accesibilidad

El color solo nunca es suficiente para comunicar un error: los usuarios con deficiencias en la visión del color pueden no percibir un borde rojo. Combina el estilo de :invalid con:

  • Un mensaje de texto visible que explique qué salió mal y cómo solucionarlo.
  • Un icono o símbolo junto al cambio de color (por ejemplo, una ✕ o un icono de advertencia).
  • aria-invalid="true" en el control para que los lectores de pantalla lo anuncien como inválido.
  • aria-describedby apuntando al elemento de mensaje de error para que la descripción se lea automáticamente.
<label for="email">Email address</label>
<input
  id="email"
  type="email"
  aria-invalid="true"
  aria-describedby="email-error"
  required
/>
<span id="email-error" role="alert">
  Please enter a valid email address.
</span>

El role="alert" en el span de error hace que los lectores de pantalla anuncien el mensaje en cuanto aparece en el DOM, incluso sin enfoque.

Pseudoclases relacionadas

PseudoclaseCoincide cuando…
:validel control supera todas sus restricciones
:requiredel control tiene el atributo required
:optionalel control no tiene required
:out-of-rangeel valor de una entrada numérica/de fecha supera min/max
:in-rangeel valor de una entrada numérica/de fecha está dentro de min/max
:placeholderel texto del marcador de posición de una entrada
:focusel control tiene actualmente el foco de teclado

Compatibilidad con navegadores

:invalid es parte de Selectors Level 4 y ha sido compatible con todos los principales navegadores durante muchos años. :user-invalid (la variante que tiene en cuenta la interacción) llegó en Chrome 119, Firefox 88 (como :-moz-ui-invalid mucho antes) y Safari 16.5.

Para más información sobre los atributos de restricción nativos de HTML, consulta <input> y HTML Forms.

Práctica

Práctica
¿Cuál es la función de la pseudoclase ':invalid' en CSS?
¿Cuál es la función de la pseudoclase ':invalid' en CSS?
Was this page helpful?