Benutzerdefinierte Formulareingaben mit modernen CSS-Funktionen gestalten

Avatar of Aaron Iker
Aaron Iker am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Heutzutage ist es durchaus möglich, benutzerdefinierte Checkboxen, Radiobuttons und Toggle-Switches zu erstellen und dabei semantisch und barrierefrei zu bleiben. Wir brauchen nicht einmal eine einzige Zeile JavaScript oder zusätzliche HTML-Elemente! Es ist tatsächlich in letzter Zeit einfacher geworden als früher. Schauen wir es uns an.

Hier werden wir landen

Die Dinge sind wirklich einfacher geworden als früher!

Der Grund dafür ist, dass wir endlich die Pseudo-Elemente ::before und ::after des <input>-Tags selbst gestalten können. Das bedeutet, wir können ein <input> behalten und gestalten, ohne zusätzliche Elemente zu benötigen. Früher mussten wir uns auf zusätzliche <div>s oder <span>s verlassen, um ein benutzerdefiniertes Design zu realisieren.

Schauen wir uns das HTML an

Hier gibt es nichts Besonderes. Mit diesem HTML können wir unsere Eingaben gestalten

<!-- Checkbox -->
<input type="checkbox">

<!-- Radio -->
<input type="radio">

<!-- Switch -->
<input type="checkbox" class="switch">

Das war's für den HTML-Teil, aber natürlich wird empfohlen, `name`- und `id`-Attribute sowie ein passendes <label>-Element zu haben.

<!-- Checkbox -->
<input type="checkbox" name="c1" id="c1">
<label for="c1">Checkbox</label>

<!-- Radio -->
<input type="radio" name="r1" id="r1">
<label for="r1">Radio</label>

<!-- Switch -->
<input type="checkbox" class="switch" name="s1" id="s1">
<label for="s1">Switch</label>

Zur Gestaltung

Zunächst prüfen wir die Unterstützung für appearance: none;, einschließlich der mit Präfixen versehenen Varianten. Die Eigenschaft appearance ist entscheidend, da sie dazu dient, das Standard-Styling eines Browsers von einem Element zu entfernen. Wenn die Eigenschaft nicht unterstützt wird, werden die Stile nicht angewendet und die Standard-Input-Stile angezeigt. Das ist völlig in Ordnung und ein gutes Beispiel für progressive Enhancement.

@supports(-webkit-appearance: none) or (-moz-appearance: none) {
  input[type='checkbox'],
  input[type='radio'] {
    -webkit-appearance: none;
    -moz-appearance: none;
  }
}

Derzeit ist `appearance` ein Arbeitsentwurf, aber hier ist die Unterstützung:

Diese Browser-Supportdaten stammen von Caniuse, wo es detailliertere Informationen gibt. Eine Zahl gibt an, dass der Browser die Funktion ab dieser Version unterstützt.

Desktop

ChromeFirefoxIEEdgeSafari
83*80Nein83*15.4

Mobil / Tablet

Android ChromeAndroid FirefoxAndroidiOS Safari
12712712715.4

Wie bei Links müssen wir verschiedene interaktive Zustände bei Formularelementen berücksichtigen. Wir werden diese bei der Gestaltung unserer Elemente berücksichtigen.

  • :checked
  • :hover
  • :focus
  • :disabled

Zum Beispiel, wie wir unseren Toggle-Input gestalten, den "Knopf" erstellen und den Zustand :checked berücksichtigen können.

/* The toggle container */
.switch {
  width: 38px;
  border-radius: 11px;
}

/* The toggle knob */
.switch::after {
  left: 2px;
  top: 2px;
  border-radius: 50%;
  width: 15px;
  height: 15px;
  background: var(--ab, var(--border));
  transform: translateX(var(--x, 0));
}

/* Change color and position when checked */
.switch:checked {
  --ab: var(--active-inner);
  --x: 17px;
}

/* Drop the opacity of the toggle knob when the input is disabled */
.switch:disabled:not(:checked)::after {
  opacity: .6;
}

Wir verwenden das <input>-Element als Container. Der Knopf im Input wird mit dem Pseudo-Element ::after erstellt. Wiederum kein Bedarf an zusätzlichem Markup!

Wenn Sie sich die Stile in der Demo genauer ansehen, werden Sie feststellen, dass wir einige CSS-Custom-Properties definieren, da dies zu einer guten Methode geworden ist, wiederverwendbare Werte in einem Stylesheet zu verwalten.

@supports(-webkit-appearance: none) or (-moz-appearance: none) {
  input[type='checkbox'],
  input[type='radio'] {
    --active: #275EFE;
    --active-inner: #fff;
    --focus: 2px rgba(39, 94, 254, .25);
    --border: #BBC1E1;
    --border-hover: #275EFE;
    --background: #fff;
    --disabled: #F6F8FF;
    --disabled-inner: #E1E6F9;
  }
}

Aber es gibt noch einen weiteren Grund, warum wir Custom Properties verwenden – sie eignen sich gut zum Aktualisieren von Werten basierend auf dem Zustand des Elements! Wir werden hier nicht ins Detail gehen, aber hier ist ein Beispiel, wie wir Custom Properties für verschiedene Zustände verwenden können.

/* Default */
input[type='checkbox'],
input[type='radio'] {
  --active: #275EFE;
  --border: #BBC1E1;
  border: 1px solid var(--bc, var(--border));
}

/* Override defaults */
input[type='checkbox']:checked,
input[type='radio']:checked {
  --b: var(--active);
  --bc: var(--active);
}
  
/* Apply another border color on hover if not checked & not disabled */
input[type='checkbox']:not(:checked):not(:disabled):hover,
input[type='radio']:not(:checked):not(:disabled):hover {
  --bc: var(--border-hover);
}

Aus Gründen der Barrierefreiheit sollten wir einen benutzerdefinierten Fokusstil hinzufügen. Wir entfernen die Standard-Outline, da sie nicht so abgerundet werden kann wie die anderen Elemente, die wir gestalten. Ein `border-radius` zusammen mit einem `box-shadow` kann jedoch einen abgerundeten Stil ergeben, der wie eine Outline funktioniert.

input[type='checkbox'],
input[type='radio'] {
  --focus: 2px rgba(39, 94, 254, .25);
  outline: none;
  transition: box-shadow .2s;
}

input[type='checkbox']:focus,
input[type='radio']:focus {
  box-shadow: 0 0 0 var(--focus);
}

Es ist auch möglich, das <label>-Element, das dem <input>-Element im HTML direkt folgt, auszurichten und zu gestalten.

<input type="checkbox" name="c1" id="c1">
<label for="c1">Checkbox</label>
input[type='checkbox'] + label,
input[type='radio'] + label {
  display: inline-block;
  vertical-align: top;
  /* Additional styling */
}

input[type='checkbox']:disabled + label,
input[type='radio']:disabled + label {
    cursor: not-allowed;
}

Hier ist die Demo noch einmal.

Hoffentlich sehen Sie, wie schön es ist, heutzutage benutzerdefinierte Formularstile zu erstellen. Es erfordert weniger Markup, dank Pseudo-Elementen, die direkt auf Formulareingaben angewendet werden können. Es erfordert weniger ausgefeilte Stilwechsel, dank Custom Properties. Und es hat eine ziemlich gute Browserunterstützung, dank @supports.

Alles in allem ist das eine viel angenehmere Entwicklererfahrung, als wir sie früher hatten!