Es gehört zu den eisernen Regeln in der Software-Entwicklung: Daten, die von außen kommen, müssen überprüft werden. Nur weil eine Komponente beispielsweise erwartet, dass ein bestimmter Parameter eine Zeichenkette ist, ist das noch lange keine Garantie, dass sie auch jedes Mal eine Zeichenkette übergeben bekommt. Nur weil eine Klasse erwartet, dass ein bestimmter Parameter eine existierende Benutzer-ID ist, heißt das noch nicht, dass das auch bei jedem Aufruf der Fall ist. Und nur weil ein Formular auf einer Website erwartet, dass in einem bestimmten Feld eine positive Zahl eingegeben wird, muss das nicht jeder Benutzer auch tatsächlich machen. Als Entwickler muss man zumindest einkalkulieren, dass jemand aus Versehen “-3 Paar” Socken bestellt, oder in das Feld für die Postleitzahl seinen Nachnamen eingibt.

Für solche und viele andere Fälle müssen die übergebenen Daten validiert werden. Dazu gehört auch, dem “Überbringer” (zum Beispiel dem Benutzer an der Tastatur) eine Rückmeldung zu geben, dass und warum die Eingabe ungültig war. Dafür gibt es in HTML und CSS verschiedene Möglichkeiten.

Beispielsweise kann man in input-Tags die gültigen Eingaben beschränken. Ein input, das Zahlen zwischen 3 und 7 erwartet, kann etwa so aussehen:

<input type="number" min="3" max="7" required>

Das alleine hindert den Benutzer nicht daran, auch andere Werte einzugeben (dafür sind dann JavaScript auf der Client-Seite sowie serverseitige Checks zuständig). Aber das Eingabefeld wird bei ungültigen Werten als “invalid” markiert, und man kann mit CSS darauf reagieren:

.myform input {
  border: solid 1px black;
}

.myform input:valid {
  border: solid 1px green;
}

.myform input:invalid {
  border: solid 1px red;
}

Damit bekommt ein Feld zunächst mal einen schwarzen Rahmen. Ist die Eingabe im Feld als gültig erkannt, wird der Rahmen grün. Ist die Eingabe ungültig, wird der Rahmen rot.

Das klingt doch schon mal gut. Ein Problem ist aber, dass die Pseudoklassen :valid und :invalid unmittelbar angewendet werden, im Zweifel direkt beim Laden des Formulars. Das heißt, wenn ein Eingabefeld nicht mit einem gültigen Wert vorbelegt ist, wird das Feld als “ungültig” markiert, bevor der Benutzer überhaupt irgendwas eingegeben hat.

Für dieses Problem gibt es mittlerweile eine Lösung, nämlich die Pseudoklassen :user-valid und :user-invalid. Die bewirken beinahe das gleiche wie :valid und :invalid. Sie werden aber erst aktiv, wenn der Benutzer mit dem jeweiligen HTML-Element (zum Beispiel einem Eingabefeld) interagiert hat. Im obigen Beispiel sieht das dann so aus:

.myform input {
  border: solid 1px black;
}

.myform input:user-valid {
  border: solid 1px green;
}

.myform input:user-invalid {
  border: solid 1px red;
}

:valid und :invalid werden von den meisten Browsern seit mehreren Jahren unterstützt. Seit 2023 unterstützen die meisten Browser auch :user-valid und :user-invalid. Mozilla Firefox war hier sogar ein gutes Stück früher dran: Bereits ab Version 4, veröffentlicht im Jahr 2011, bot der Browser eine analoge Funktion, allerdings zunächst unter den Nicht-Standard-Bezeichnern :-moz-ui-valid und :-moz-ui-invalid. Laut CanIUse stehen :user-valid und :user-invalid heute für knapp 91% aller Benutzer global zur Verfügung.