Individuelle Checkbox & Radio Inputs – CSS3 Adventskalender Tag 13

CSS Checkbox Update 2016

Da der Artikel nun 5 Jahre alt ist und sich CSS & Design weiterentwickelt haben, hab ich mal ein Update gemalt. Custom Radio-Button und Checkboxen mit pure™ CSS, barrierefrei & überhaupt:

See the Pen CSS3 Custom Checkbox, Radio Input and Select by Sven Wolfermann (@maddesigns) on CodePen.

— ab hier der alte Artikel von 2011 —
Um es vorweg zu nehmen, beim Stylen von Input-Feldern muss man aus Usability-Gesichtspunkten Vorsicht walten lassen. Der normale User ist an das Aussehen der Formular-Elemente in seinem OS/Browser gewöhnt. Wenn die Input-Felder nun stark von der gewohnten Umgebung abweichen, ist er skeptischer beim Ausfüllen von Formularen und bricht u.U. den Prozess sogar ganz ab. (Quelle: Internet)

Auch wenn man es wollte, einige Formular-Elemente lassen sich zudem nur schwerlich, bis gar nicht cross-browser-konform stylen, z.B. das input[type="file"]. Für Checkboxen und Radio-Buttons möchte ich heute eine Möglichkeit zeigen, die zudem auch die neuen CSS3 Pseudo-Klasse :checked beinhaltet.

Als erstes erstellen wir ein kleines HTML5-Formular

<form class="comment-form" action="#" method="post">
  <fieldset>
    <ol>
      <li>
        <h3>War das Tutorial nützlich? <sup title="Das ist ein Pflichtfeld">*</sup></h3>
        <input id="radio_yes" type="radio" value="ja" name="radio" required> 
        <label for="radio_yes">Ja</label> 
        <input id="radio_no" type="radio" value="nein" name="radio" required> 
        <label for="radio_no">Nein</label> 
      </li>
      <li>
        <input type="checkbox" name="ckeck" id="check" value="japp" required>
        <label for="check">Ja, ich habe das Tutorial auch gelesen.<sup title="Das ist ein Pflichtfeld">*</sup></label> 
      </li>
      <li>
        <input type="submit" name="submit" id="submit" value="Absenden">
      </li>
    </ol>
  </fieldset>
</form>

Das Formular braucht zunächst ein wenig Grundgestaltung.

fieldset {
  border: none;
  margin: 0;
  padding: 0;
}
  
ol {
  list-style-type: none;
  margin: 0;
  padding: 0;
}
  
li {
  padding: 1em 0;
}
  
label {
  cursor: pointer;
}

Wie schon erwähnt, ist es fast unmöglich die Input-Types einheitlich zu stylen. Deshalb werden wir die Input-Felder über background-clip „ausblenden“ und das folgende label mit dem Styling versorgen.

input[type="checkbox"], input[type="radio"] {
  position: absolute; 
  clip: rect(0,0,0,0);
}

Jetzt sind die Input-Felder der Checkbox und auch die Radio-Buttons nicht mehr sichtbar, aber grundsätzlich noch für die Tasterturbenutzung erreichbar (Stichwort: barrierefrei). Da der Browser uns jetzt allerdings kein visionelles Feedback mehr geben kann, wenn die Checkbox oder Radio-Buttons fokusiert werden, verlegern wir das Verhalten auf das folgende Label. Wenn das Input-Feld fokusiert wird, wird das folgende label fett dargestellt:

input[type="checkbox"]:focus + label , input[type="radio"]:focus + label{
  font-weight: bold;
}

Spritegrafik hinzufügen

Als nächstes fügen wir eine Hintergrund-Spritegrafik hinzu, sowie das Styling für den CSS3 :checked Status:

input[type="radio"] + label {
  background: transparent url("s-radio.png") no-repeat 0 -34px;
  padding: 0 20px;
}
input[type="radio"][value*="nein"] + label {
  background-position: 0 -50px;
}
input[type="radio"]:checked + label {
  background-position: 0 -2px;
  color: green;
}
input[type="radio"][value*="nein"]:checked + label {
  background-position: 0 -18px;
  color: red;
}

Die Spritegrafik-Position wird also verschoben und visuell auf grün für „ja“ gesetzt, oder eben rot für „nein“. Dazu ist natürlich zu sagen, wenn man den Barrierefrei-Aspekt hinzuzieht, rot/grün natürlich nicht optimal sind und man sich darüber in klaren sein sollte, das ein Großteil der Nutzer eine Rot-Grün-Schwäche haben. Deshalb sind in unserem Beispiel zudem andere Symbole für ja/nein gewählt.

Ein ähnliches Verhalten implementieren wir nun auch für die Checkbox.

input[type="checkbox"] + label {
  background: transparent url("s-checkbox.png") no-repeat 0 -16px;
  padding-left: 20px;
}
  
input[type="checkbox"]:checked + label {
  background-position: 0 0;
}

Da im Beispiel ein HTML5-Formular mit dem Attribut required in den Inputs verwendet wurde, wird die browserseitige Validierung aktiv, wenn keine Option ausgewählt wurde, sowie wenn die Checkbox nicht aktiviert wurde.

Diesen Pseudo-Status kann ebenfalls stylen, ist allerdings in den verschiedenen Browsern mit Browser-Präfixen implementiert. Am Beispiel von Firefox, kann man :-moz-ui-invalid verwenden:

input[type="checkbox"]:-moz-ui-invalid + label {
  background: transparent url("s-checkbox.png") no-repeat 0 -32px; 
  color: red;
}
input[type="checkbox"]:-moz-ui-invalid + label:after {
  content: '<<<--- Pflichtfeld!';
}

Demo

Das HTML5-Formular mit individuellen Radio-Buttons

Browser-Support

Der verwendeten Pseudo-Selektoren sind bereits in CSS 2.1 spezifiziert, allerdings erst vollständig implementiert mit dem Release des IE9.

Weitere Infos zu dieser Technik gibt es beim CSS Ninja (Ryan Seddon) im Artikel "Custom radio and checkbox inputs using CSS" und in Lea Verou's Vortrag "CSS3 Secrets".

4 thoughts on “Individuelle Checkbox & Radio Inputs – CSS3 Adventskalender Tag 13”

  1. Sehr interessanter Ansatz

    Damit das Formular in älteren Browsern nicht komplett funktionsunfähig wird, könnte man allen Selektoren ein :not(root) oder ähnliches anhängen, damit z.B. die Anweisung zum verstecken der checkbox von älteren Browsern wie dem IE < 9 ignoriert wird

    Statt :-moz-ui-invalid funktioniert in allen aktuellen Browsern übrigens auch ein einfaches :invalid
    siehe http://jsfiddle.net/jNptL/

  2. http://selectivizr.com/ habe ich in einem Projekt für die Unterstützung der älteren Browser benutzt, aber das :not(root) muss ich mir mal ansehen.

    Das :invalid funktioniert bei Feldern, die required sind nicht so schön, wie ich finde, die sind sofort :invalid – besser geeignet ist :invalid bei Text-Inputs die ein pattern-Attribut haben, denke ich.

  3. Sehr cooles Tutorial. Da ich Selectivizr ohnehin grundsätzlich in alle Websites einbinde, kann ich das auch vollumfänglich überall verwenden :-) Gleich mal beim Relaunch meiner eigenen Website nächste Woche hineinbasteln.

Kommentare sind geschlossen.