Schaltflächenkomponente erstellen

Eine grundlegende Übersicht zum Erstellen von farbadaptiven, responsiven und barrierefreien <button>-Komponenten.

In diesem Beitrag möchte ich meine Gedanken zum Erstellen eines farbadaptiven, responsiven und barrierefreien <button>-Elements teilen. Demo ansehen und Quelle ansehen

Im hellen und dunklen Design werden Schaltflächen über die Tastatur und die Maus bedient.

Wenn du lieber ein Video ansiehst, findest du hier eine YouTube-Version dieses Beitrags:

Übersicht

Unterstützte Browser

  • Chrome: 1.
  • Rand: 12.
  • Firefox: 1.
  • Safari: 1.

Quelle

Das Element <button> ist für die Nutzerinteraktion vorgesehen. Die click-Ereignistrigger werden unter anderem über Tastatur, Maus, Berührung, Stimme und mehr ausgelöst. Dabei werden intelligente Regeln für den zeitlichen Ablauf festgelegt. Außerdem sind in jedem Browser einige Standardstile vorhanden, die Sie direkt und ohne Anpassung verwenden können. Mit color-scheme kannst du auch die vom Browser bereitgestellten hellen und dunklen Schaltflächen aktivieren.

Es gibt auch verschiedene Arten von Schaltflächen, die im Codepen-Embed oben zu sehen sind. Ein <button> ohne Typ passt sich an die Position in einem <form> an und ändert sich in den Typ „Senden“.

<!-- buttons -->
<button></button>
<button type="submit"></button>
<button type="button"></button>
<button type="reset"></button>

<!-- button state -->
<button disabled></button>

<!-- input buttons -->
<input type="button" />
<input type="file">

Bei der GUI-Challenge dieses Monats erhält jede Schaltfläche einen Stil, um ihre Absicht visuell zu unterscheiden. Zurücksetzen-Schaltflächen werden in Warnfarben dargestellt, da sie zerstörerisch sind. Senden-Schaltflächen werden blau hervorgehoben, damit sie etwas stärker hervorgehoben werden als normale Schaltflächen.

Vorschau der endgültigen Version aller Schaltflächentypen, dargestellt in einem Formular und nicht in einem Formular, mit schönen Ergänzungen für Symbolschaltflächen und benutzerdefinierte Schaltflächen.
Vorschau der endgültigen Version aller Schaltflächentypen, dargestellt in einem Formular und nicht in einem Formular, mit schönen Ergänzungen für Symbolschaltflächen und benutzerdefinierte Schaltflächen

Schaltflächen haben auch Pseudoklassen, die für das CSS-Styling verwendet werden können. Diese Klassen bieten CSS-Hooks zum Anpassen des Schaltflächengefühls: :hover für den Fall, dass sich eine Maus über der Schaltfläche befindet, :active für das Drücken einer Maus oder Tastatur und :focus oder :focus-visible zur Unterstützung beim Gestalten assistiver Technologie.

button:hover {}
button:active {}
button:focus {}
button:focus-visible {}
Vorschau der endgültigen Version aller Schaltflächentypen im dunklen Design.
Vorschau der endgültigen Version aller Schaltflächentypen im dunklen Design

Markup

Zusätzlich zu den in der HTML-Spezifikation bereitgestellten Schaltflächentypen habe ich eine Schaltfläche mit einem Symbol und eine Schaltfläche mit einer benutzerdefinierten Klasse btn-custom hinzugefügt.

<button>Default</button>
<input type="button" value="<input>"/>
<button>
  <svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true">
    <path d="..." />
  </svg>
  Icon
</button>
<button type="submit">Submit</button>
<button type="button">Type Button</button>
<button type="reset">Reset</button>
<button disabled>Disabled</button>
<button class="btn-custom">Custom</button>
<input type="file">

Anschließend werden die Schaltflächen zum Testen in ein Formular eingefügt. So kann ich dafür sorgen, dass die Stile für die Standardschaltfläche, die als Sendeschaltfläche dient, richtig aktualisiert werden. Außerdem ändere ich die Symbolstrategie von Inline-SVG in ein maskiertes SVG, damit beide gleichermaßen gut funktionieren.

<form>
  <button>Default</button>
  <input type="button" value="<input>"/>
  <button>Icon <span data-icon="cloud"></span></button>
  <button type="submit">Submit</button>
  <button type="button">Type Button</button>
  <button type="reset">Reset</button>
  <button disabled>Disabled</button>
  <button class="btn-custom btn-large" type="button">Large Custom</button>
  <input type="file">
</form>

Die Matrix der Kombinationen ist an diesem Punkt ziemlich überwältigend. Zwischen Schaltflächentypen, Pseudoklassen und dem Vorhandensein oder Fehlen eines Formulars gibt es über 20 Schaltflächenkombinationen. Zum Glück können wir mit CSS jede davon klar formulieren.

Bedienungshilfen

Schaltflächenelemente sind von Natur aus barrierefrei, aber es gibt einige gängige Verbesserungen.

Zusammen schwenken und fokussieren

Ich gruppiere :hover und :focus gerne mit dem funktionalen Pseudo-Sellektor :is(). Dadurch wird sichergestellt, dass meine Benutzeroberflächen immer die Tastatur- und Hilfstechnologien berücksichtigen.

button:is(:hover, :focus) {
  
}
Demo testen

Interaktiver Fokusring

Ich animiere den Fokusring für Nutzer mit Tastatur und Hilfstechnologien. Dazu animiere ich den Umriss um 5 Pixel von der Schaltfläche weg, aber nur, wenn die Schaltfläche nicht aktiv ist. Dadurch wird der Fokusring beim Drücken auf die Schaltfläche auf die Größe der Schaltfläche verkleinert.

:where(button, input):where(:not(:active)):focus-visible {
  outline-offset: 5px;
}

Farbkontrast prüfen

Es gibt mindestens vier verschiedene Farbkombinationen für helle und dunkle Designs, bei denen der Farbkontrast berücksichtigt werden muss: Schaltfläche, Sende-Schaltfläche, Rücksetz-Schaltfläche und deaktivierte Schaltfläche. VisBug wird hier verwendet, um alle Punktzahlen gleichzeitig zu überprüfen und anzuzeigen:

Symbole für Personen ausblenden, die sie nicht sehen können

Beim Erstellen einer Symbolschaltfläche sollte das Symbol den Text der Schaltfläche visuell unterstützen. Das bedeutet auch, dass das Symbol für Menschen mit Sehbehinderung nicht hilfreich ist. Glücklicherweise bietet der Browser eine Möglichkeit, Elemente vor Screenreadern zu verbergen, damit sehbehinderte Nutzer nicht von dekorativen Schaltflächenbildern gestört werden:

<button>
  <svg … aria-hidden="true">...</svg>
  Icon Button
</button>
Chrome-Entwicklertools mit dem Bedienungshilfen-Baum für die Schaltfläche Das Schaltflächenbild wird im Baum ignoriert, da „aria-hidden“ auf „wahr“ festgelegt ist.
Chrome-Entwicklertools mit dem Bedienungshilfen-Baum für die Schaltfläche. Das Schaltflächenbild wird in der Baumstruktur ignoriert, da „aria-hidden“ auf „true“ festgelegt ist.

Stile

Im nächsten Abschnitt erstelle ich zuerst ein benutzerdefiniertes Property-System zum Verwalten der adaptiven Stile der Schaltfläche. Mit diesen benutzerdefinierten Properties kann ich Elemente auswählen und ihr Aussehen anpassen.

Eine Strategie für benutzerdefinierte adaptive Zielgruppen

Die Strategie für benutzerdefinierte Properties, die in dieser GUI-Herausforderung verwendet wird, ähnelt der Strategie, die beim Erstellen eines Farbschemas verwendet wird. Für ein adaptives Farbsystem mit hellen und dunklen Farben wird für jedes Design eine benutzerdefinierte Property definiert und entsprechend benannt. Anschließend wird eine einzelne benutzerdefinierte Property verwendet, um den aktuellen Wert des Themas zu speichern. Diese wird einer CSS-Property zugewiesen. Später kann die einzelne benutzerdefinierte Eigenschaft auf einen anderen Wert aktualisiert und dann der Schaltflächenstil aktualisiert werden.

button {
  --_bg-light: white;
  --_bg-dark: black;
  --_bg: var(--_bg-light);

  background-color: var(--_bg);
}

@media (prefers-color-scheme: dark) {
  button {
    --_bg: var(--_bg-dark);
  }
}

Mir gefällt, dass das helle und das dunkle Design deklarativ und klar sind. Die Indirektion und Abstraktion werden an das benutzerdefinierte Attribut --_bg ausgelagert, das jetzt das einzige „reaktive“ Attribut ist. --_bg-light und --_bg-dark sind statisch. Außerdem ist das helle Design das Standarddesign und das dunkle Design wird nur bedingt angewendet.

Für Designkonsistenz vorbereiten

Die Auswahl für freigegebene Elemente

Mit der folgenden Auswahl können Sie die verschiedenen Arten von Schaltflächen ansteuern. Sie wirkt auf den ersten Blick etwas überwältigend. Da :where() verwendet wird, müssen Sie die Schaltfläche nicht genauer anpassen. Schaltflächen werden häufig für alternative Szenarien angepasst und die Auswahl :where() sorgt dafür, dass dies ganz einfach ist. In :where() ist jeder Schaltflächentyp ausgewählt, einschließlich ::file-selector-button, das nicht innerhalb von :is() oder :where() verwendet werden kann.

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"],
  input[type="file"]
),
:where(input[type="file"])::file-selector-button {
  
}

Alle benutzerdefinierten Properties werden in diesem Bereich festgelegt. Jetzt ist es an der Zeit, alle benutzerdefinierten Properties zu überprüfen. Für diese Schaltfläche werden ziemlich viele benutzerdefinierte Properties verwendet. Ich werde jede Gruppe nach und nach beschreiben und dann am Ende des Abschnitts die Kontexte für dunkle und reduzierte Bewegungen teilen.

Akzentfarbe der Schaltfläche

Mit Sendeschaltflächen und Symbolen können Sie Farbakzente setzen:

--_accent-light: hsl(210 100% 40%);
--_accent-dark: hsl(210 50% 70%);
--_accent: var(--_accent-light);

Schriftfarbe für Schaltfläche

Die Textfarben von Schaltflächen sind nicht weiß oder schwarz, sondern abgedunkelte oder aufgehellte Versionen von --_accent, wobei hsl() verwendet wird und der Farbton 210 beibehalten wird:

--_text-light: hsl(210 10% 30%);
--_text-dark: hsl(210 5% 95%);
--_text: var(--_text-light);

Hintergrundfarbe der Schaltfläche

Die Schaltflächen-Hintergründe folgen demselben hsl()-Muster, mit Ausnahme der Schaltflächen im hellen Design. Diese sind weiß, damit sie dem Nutzer näher erscheinen oder vor anderen Oberflächen zu liegen scheinen:

--_bg-light: hsl(0 0% 100%);
--_bg-dark: hsl(210 9% 31%);
--_bg: var(--_bg-light);

Schaltflächenhintergrund

Mit dieser Hintergrundfarbe wird eine Oberfläche hinter anderen Oberflächen angezeigt. Das ist z. B. für den Hintergrund der Dateieingabe nützlich:

--_input-well-light: hsl(210 16% 87%);
--_input-well-dark: hsl(204 10% 10%);
--_input-well: var(--_input-well-light);

Schaltflächenabstand

Der Abstand um den Text in der Schaltfläche herum wird mit der Einheit ch angegeben, einer relativen Länge zur Schriftgröße. Dies ist besonders wichtig, wenn große Schaltflächen das font-size einfach nach oben schieben können und die Schaltfläche proportional skaliert wird:

--_padding-inline: 1.75ch;
--_padding-block: .75ch;

Schaltflächenrand

Der Radius des Schaltflächenrahmens wird in einer benutzerdefinierten Eigenschaft gespeichert, damit die Dateieingabe den anderen Schaltflächen entsprechen kann. Die Rahmenfarben folgen dem etablierten adaptiven Farbsystem:

--_border-radius: .5ch;

--_border-light: hsl(210 14% 89%);
--_border-dark: var(--_bg-dark);
--_border: var(--_border-light);

Effekt für das Hervorheben von Schaltflächen bei Mausbewegung

Diese Eigenschaften legen eine Größeneigenschaft für den Übergang bei einer Interaktion fest und die Hervorhebungsfarbe folgt dem adaptiven Farbsystem. Wir werden später in diesem Beitrag noch genauer auf die Interaktion dieser beiden Abschnitte eingehen. Letztendlich werden sie jedoch für den box-shadow-Effekt verwendet:

--_highlight-size: 0;

--_highlight-light: hsl(210 10% 71% / 25%);
--_highlight-dark: hsl(210 10% 5% / 25%);
--_highlight: var(--_highlight-light);

Textschatten für Schaltflächen

Jede Schaltfläche hat einen subtilen Textschattenstil. Dadurch wird der Text über der Schaltfläche platziert, was die Lesbarkeit verbessert und die Präsentation insgesamt ansprechender macht.

--_ink-shadow-light: 0 1px 0 var(--_border-light);
--_ink-shadow-dark: 0 1px 0 hsl(210 11% 15%);
--_ink-shadow: var(--_ink-shadow-light);

Buttersymbol

Symbole sind dank der relativen Längeneinheit ch wieder so groß wie zwei Zeichen, wodurch das Symbol proportional zum Schaltflächentext skaliert werden kann. Die Symbolfarbe orientiert sich an --_accent-color, um eine adaptive und zum Design passende Farbe zu erhalten.

--_icon-size: 2ch;
--_icon-color: var(--_accent);

Schaltflächenschatten

Damit sich Schatten richtig an helle und dunkle Umgebungen anpassen, müssen sowohl ihre Farbe als auch ihre Deckkraft verändert werden. Schatten in hellen Designs sollten dezent sein und in Richtung der Farbe der Oberfläche gehen, auf die sie gelegt werden. Schatten im dunklen Design müssen dunkler und satter sein, damit sie dunklere Oberflächenfarben überlagern können.

--_shadow-color-light: 220 3% 15%;
--_shadow-color-dark: 220 40% 2%;
--_shadow-color: var(--_shadow-color-light);

--_shadow-strength-light: 1%;
--_shadow-strength-dark: 25%;
--_shadow-strength: var(--_shadow-strength-light);

Mit adaptiven Farben und Stärken kann ich zwei Schattentiefen zusammenstellen:

--_shadow-1: 0 1px 2px -1px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 9%));

--_shadow-2: 
  0 3px 5px -2px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 3%)),
  0 7px 14px -5px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 5%));

Damit die Schaltflächen leicht 3D aussehen, erzeugt ein 1px-Feldschatten die Illusion:

--_shadow-depth-light: 0 1px var(--_border-light);
--_shadow-depth-dark: 0 1px var(--_bg-dark);
--_shadow-depth: var(--_shadow-depth-light);

Schaltflächenübergänge

Gemäß dem Muster für adaptive Farben erstelle ich zwei statische Eigenschaften, um die Optionen des Designsystems zu speichern:

--_transition-motion-reduce: ;
--_transition-motion-ok:
  box-shadow 145ms ease,
  outline-offset 145ms ease
;
--_transition: var(--_transition-motion-reduce);

Alle Properties zusammen in der Auswahl

Alle benutzerdefinierten Properties in einer Auswahl

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"],
  input[type="file"]
),
:where(input[type="file"])::file-selector-button {
  --_accent-light: hsl(210 100% 40%);
  --_accent-dark: hsl(210 50% 70%);
  --_accent: var(--_accent-light);

--_text-light: hsl(210 10% 30%); --_text-dark: hsl(210 5% 95%); --_text: var(--_text-light);

--_bg-light: hsl(0 0% 100%); --_bg-dark: hsl(210 9% 31%); --_bg: var(--_bg-light);

--_input-well-light: hsl(210 16% 87%); --_input-well-dark: hsl(204 10% 10%); --_input-well: var(--_input-well-light);

--_padding-inline: 1.75ch; --_padding-block: .75ch;

--_border-radius: .5ch; --_border-light: hsl(210 14% 89%); --_border-dark: var(--_bg-dark); --_border: var(--_border-light);

--_highlight-size: 0; --_highlight-light: hsl(210 10% 71% / 25%); --_highlight-dark: hsl(210 10% 5% / 25%); --_highlight: var(--_highlight-light);

--_ink-shadow-light: 0 1px 0 hsl(210 14% 89%); --_ink-shadow-dark: 0 1px 0 hsl(210 11% 15%); --_ink-shadow: var(--_ink-shadow-light);

--_icon-size: 2ch; --_icon-color-light: var(--_accent-light); --_icon-color-dark: var(--_accent-dark); --_icon-color: var(--accent, var(--_icon-color-light));

--_shadow-color-light: 220 3% 15%; --_shadow-color-dark: 220 40% 2%; --_shadow-color: var(--_shadow-color-light); --_shadow-strength-light: 1%; --_shadow-strength-dark: 25%; --_shadow-strength: var(--_shadow-strength-light); --_shadow-1: 0 1px 2px -1px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 9%)); --_shadow-2: 0 3px 5px -2px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 3%)), 0 7px 14px -5px hsl(var(--_shadow-color)/calc(var(--_shadow-strength) + 5%)) ;

--_shadow-depth-light: hsl(210 14% 89%); --_shadow-depth-dark: var(--_bg-dark); --_shadow-depth: var(--_shadow-depth-light);

--_transition-motion-reduce: ; --_transition-motion-ok: box-shadow 145ms ease, outline-offset 145ms ease ; --_transition: var(--_transition-motion-reduce); }

Standardschaltflächen werden im hellen und dunklen Design nebeneinander angezeigt.

Anpassungen für dunkles Design

Der Wert des Musters für statische Props -light und -dark wird klar, wenn die Props für das dunkle Design festgelegt werden:

@media (prefers-color-scheme: dark) {
  :where(
    button,
    input[type="button"],
    input[type="submit"],
    input[type="reset"],
    input[type="file"]
  ),
  :where(input[type="file"])::file-selector-button {
    --_bg: var(--_bg-dark);
    --_text: var(--_text-dark);
    --_border: var(--_border-dark);
    --_accent: var(--_accent-dark);
    --_highlight: var(--_highlight-dark);
    --_input-well: var(--_input-well-dark);
    --_ink-shadow: var(--_ink-shadow-dark);
    --_shadow-depth: var(--_shadow-depth-dark);
    --_shadow-color: var(--_shadow-color-dark);
    --_shadow-strength: var(--_shadow-strength-dark);
  }
}

Das ist nicht nur gut lesbar, sondern Nutzer dieser benutzerdefinierten Schaltflächen können die anpassbaren Assets auch mit der Gewissheit verwenden, dass sie sich den Nutzereinstellungen entsprechend anpassen.

Reduzierte Bewegungsanpassung

Wenn Bewegungen für diesen Besucher zulässig sind, weisen Sie --_transition zu var(--_transition-motion-ok) zu:

@media (prefers-reduced-motion: no-preference) {
  :where(
    button,
    input[type="button"],
    input[type="submit"],
    input[type="reset"],
    input[type="file"]
  ),
  :where(input[type="file"])::file-selector-button {
    --_transition: var(--_transition-motion-ok);
  }
}

Einige freigegebene Stile

Die Schriftart von Schaltflächen und Eingabefeldern muss auf inherit festgelegt sein, damit sie mit der restlichen Schrift auf der Seite übereinstimmt. Andernfalls wird sie vom Browser formatiert. Das gilt auch für letter-spacing. Wenn Sie line-height auf 1.5 festlegen, wird der Textbereich so groß, dass der Text oben und unten etwas Platz hat:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"],
  input[type="file"]
),
:where(input[type="file"])::file-selector-button {
  /* …CSS variables */

  font: inherit;
  letter-spacing: inherit;
  line-height: 1.5;
  border-radius: var(--_border-radius);
}

Screenshot mit Schaltflächen nach Anwendung der vorherigen Stile

Schaltflächen für das Design

Selektoranpassung

Der Selector input[type="file"] ist nicht der Schaltflächenteil der Eingabe, sondern das Pseudo-Element ::file-selector-button. Daher habe ich input[type="file"] aus der Liste entfernt:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"],
  input[type="file"]
),
:where(input[type="file"])::file-selector-button {
  
}

Anpassungen für Cursor und Berührung

Zuerst style ich den Cursor im Stil pointer, damit die Schaltfläche Nutzern mit Maus signalisiert, dass sie interaktiv ist. Dann füge ich touch-action: manipulation hinzu, damit Klicks nicht warten und einen potenziellen Doppelklick beobachten müssen, wodurch die Schaltflächen schneller erscheinen:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  cursor: pointer;
  touch-action: manipulation;
}

Farben und Rahmen

Als Nächstes passe ich die Schriftgröße, den Hintergrund, den Text und die Rahmenfarben an. Dazu verwende ich einige der zuvor erstellten benutzerdefinierten adaptiven Eigenschaften:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  

  font-size: var(--_size, 1rem);
  font-weight: 700;
  background: var(--_bg);
  color: var(--_text);
  border: 2px solid var(--_border);
}

Screenshot mit Schaltflächen nach Anwendung der vorherigen Stile

Schatten

Bei den Schaltflächen wurden einige gute Techniken angewendet. Das Symbol text-shadow passt sich hellen und dunklen Hintergründen an, wodurch der Schaltflächentext dezent auf dem Hintergrund erscheint. Dem box-shadow sind drei Schatten zugewiesen. Die erste, --_shadow-2, ist ein normaler Kastenschatten. Der zweite Schatten ist ein optischer Trick, der die Schaltfläche ein wenig abgeschrägt erscheinen lässt. Der letzte Schatten ist für das Hover-Highlight, das anfangs eine Größe von 0 hat. Später wird ihm eine Größe zugewiesen und es wird so animiert, dass es so aussieht, als würde es aus der Schaltfläche herauswachsen.

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  

  box-shadow: 
    var(--_shadow-2),
    var(--_shadow-depth),
    0 0 0 var(--_highlight-size) var(--_highlight)
  ;
  text-shadow: var(--_ink-shadow);
}

Screenshot mit Schaltflächen nach dem Anwenden der vorherigen Stile

Layout

Ich habe der Schaltfläche ein Flexbox-Layout gegeben, genauer gesagt ein inline-flex-Layout, das zu ihrem Inhalt passt. Anschließend zentriere ich den Text und richte die untergeordneten Elemente vertikal und horizontal in der Mitte aus. So lassen sich Symbole und andere Schaltflächenelemente leichter ausrichten.

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  

  display: inline-flex;
  justify-content: center;
  align-items: center;
  text-align: center;
}

Screenshot mit Schaltflächen nach Anwendung der vorherigen Stile

Abstand

Für den Abstand zwischen den Schaltflächen habe ich gap verwendet, damit sich Geschwisterelemente nicht überschneiden, und logische Eigenschaften für den Abstand, damit der Abstand zwischen den Schaltflächen für alle Textlayouts funktioniert.

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  

  gap: 1ch;
  padding-block: var(--_padding-block);
  padding-inline: var(--_padding-inline);
}

Screenshot mit Schaltflächen nach dem Anwenden der vorherigen Stile

Benutzeroberflächen bei Berührung und Maus

Dieser nächste Abschnitt richtet sich hauptsächlich an Nutzer von Touchbedienungen auf Mobilgeräten. Die erste Eigenschaft, user-select, gilt für alle Nutzer und verhindert, dass Text den Schaltflächentext hervorhebt. Das ist vor allem auf Touchbildschirmen zu sehen, wenn eine Schaltfläche angetippt und gedrückt wird und das Betriebssystem den Text der Schaltfläche hervorhebt.

Ich habe festgestellt, dass dies in der Regel nicht der Fall ist. Daher deaktiviere ich die Option, indem ich user-select auf „Kein“ setze. Die Farben für die Markierung durch Tippen (-webkit-tap-highlight-color) und die Kontextmenüs des Betriebssystems (-webkit-touch-callout) sind weitere sehr weborientierte Schaltflächenfunktionen, die nicht den allgemeinen Erwartungen der Nutzer an Schaltflächen entsprechen. Daher entferne ich sie ebenfalls.

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  

  user-select: none;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

Übergänge

Die adaptive Variable --_transition wird der Eigenschaft transition zugewiesen:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
  

  transition: var(--_transition);
}

Wenn der Nutzer den Mauszeiger auf die Schaltfläche bewegt, aber nicht aktiv darauf klickt, passen Sie die Größe des Schatten-Akzents an, damit er einen schönen Fokuseffekt erzeugt, der so wirkt, als würde er aus der Schaltfläche herauswachsen:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
):where(:not(:active):hover) {
  --_highlight-size: .5rem;
}

Erhöhen Sie den Abstand des Fokus-Umrisses von der Schaltfläche, wenn der Fokus darauf liegt. So entsteht ein ansprechender Fokuseffekt, der so wirkt, als würde er aus der Schaltfläche herauswachsen:

:where(button, input):where(:not(:active)):focus-visible {
  outline-offset: 5px;
}

Symbole

Für die Verarbeitung von Symbolen wurde dem Selektor ein :where()-Selektor für direkte SVG-Kinder oder Elemente mit dem benutzerdefinierten Attribut data-icon hinzugefügt. Die Symbolgröße wird mit der benutzerdefinierten Eigenschaft mithilfe logischer Inline- und Blockattribute festgelegt. Die Strichfarbe und eine drop-shadow, die mit der text-shadow übereinstimmt, werden festgelegt. flex-shrink ist auf 0 festgelegt, damit das Symbol nie verkleinert wird. Abschließend wähle ich Liniensymbole aus und weise diese Stile hier mit Linienabschlüssen und Linienverbindungen (fill: none und round) zu:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
) > :where(svg, [data-icon]) {
  block-size: var(--_icon-size);
  inline-size: var(--_icon-size);
  stroke: var(--_icon-color);
  filter: drop-shadow(var(--_ink-shadow));

  flex-shrink: 0;
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

Screenshot mit Schaltflächen nach Anwendung der vorherigen Stile

Schaltflächen zum Senden anpassen

Ich wollte, dass die Schaltflächen zum Senden etwas hervorgehoben werden. Das habe ich erreicht, indem ich die Textfarbe der Schaltflächen zur Akzentfarbe gemacht habe:

:where(
  [type="submit"], 
  form button:not([type],[disabled])
) {
  --_text: var(--_accent);
}

Screenshot mit Schaltflächen, nachdem die vorherigen Stile angewendet wurden

Tasten zum Zurücksetzen anpassen

Ich wollte, dass die Schaltflächen zum Zurücksetzen einige integrierte Warnhinweise enthalten, um die Nutzer auf ihr potenziell schädliches Verhalten aufmerksam zu machen. Außerdem habe ich die Schaltfläche für das helle Design mit mehr roten Akzenten gestaltet als die für das dunkle Design. Dazu wird die entsprechende helle oder dunkle zugrunde liegende Farbe geändert. Mit der Schaltfläche wird der Stil aktualisiert:

:where([type="reset"]) {
  --_border-light: hsl(0 100% 83%);
  --_highlight-light: hsl(0 100% 89% / 20%);
  --_text-light: hsl(0 80% 50%);
  --_text-dark: hsl(0 100% 89%);
}

Außerdem wäre es schön, wenn die Farbe der Fokus-Kontur mit dem roten Akzent übereinstimmt. Die Textfarbe wird von Dunkelrot zu Hellrot angepasst. Ich passe die Farbe der Umrisse an das Keyword currentColor an:

:where([type="reset"]):focus-visible {
  outline-color: currentColor;
}

Screenshot mit Schaltflächen nach Anwendung der vorherigen Stile

Deaktivierte Schaltflächen anpassen

Es kommt häufig vor, dass deaktivierte Schaltflächen einen schlechten Farbkontrast haben, weil sie weniger hervorgehoben werden sollen, damit sie weniger aktiv erscheinen. Ich habe jeden Farbsatz getestet und dafür gesorgt, dass er bestanden hat. Dazu habe ich den HSL-Helligkeitswert angepasst, bis der Wert in DevTools oder VisBug bestanden hat.

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"]
)[disabled] {
  --_bg: none;
  --_text-light: hsl(210 7% 40%);
  --_text-dark: hsl(210 11% 71%);

  cursor: not-allowed;
  box-shadow: var(--_shadow-1);
}

Screenshot mit Schaltflächen nach Anwendung der vorherigen Stile

Dateieingabeschaltflächen anpassen

Die Schaltfläche für die Dateieingabe ist ein Container für einen Span und eine Schaltfläche. Mit CSS können Sie den Eingabecontainer und die verschachtelte Schaltfläche ein wenig stylen, aber nicht den Span. Der Container erhält max-inline-size, damit er nicht größer wird, als nötig, während inline-size: 100% sich selbst verkleinert und Container kleiner als er passt. Als Hintergrundfarbe wird eine adaptive Farbe festgelegt, die dunkler als andere Oberflächen ist, sodass sie hinter der Dateiauswahlschaltfläche liegt.

:where(input[type="file"]) {
  inline-size: 100%;
  max-inline-size: max-content;
  background-color: var(--_input-well);
}

Die Schaltflächen für die Dateiauswahl und den Eingabetyp werden speziell mit appearance: none angegeben, um alle vom Browser bereitgestellten Stile zu entfernen, die nicht von den anderen Schaltflächenstilen überschrieben wurden.

:where(input[type="button"]),
:where(input[type="file"])::file-selector-button {
  appearance: none;
}

Zum Schluss wird dem inline-end der Schaltfläche ein Rand hinzugefügt, um den Span-Text von der Schaltfläche wegzuschieben und so etwas Platz zu schaffen.

:where(input[type="file"])::file-selector-button {
  margin-inline-end: var(--_padding-inline);
}

Screenshot mit Schaltflächen nach Anwendung der vorherigen Stile

Besondere Ausnahmen für das dunkle Design

Ich habe den primären Aktionsschaltflächen einen dunkleren Hintergrund für einen höheren Kontrast zugewiesen.

@media (prefers-color-scheme: dark) {
  :where(
    [type="submit"],
    [type="reset"],
    [disabled],
    form button:not([type="button"])
  ) {
    --_bg: var(--_input-well);
  }
}

Screenshot mit Schaltflächen, nachdem die vorherigen Stile angewendet wurden

Varianten erstellen

Aus Spaß und weil es praktisch ist, zeige ich, wie Sie einige Varianten erstellen. Eine Variante ist sehr farbenfroh, ähnlich wie primäre Schaltflächen oft aussehen. Eine weitere Variante ist groß. Die letzte Variante hat ein Symbol mit Farbverlauf.

Leuchtende Schaltfläche

Um diesen Schaltflächenstil zu erreichen, habe ich die Basis-Props direkt mit blauen Farben überschrieben. Das geht zwar schnell und einfach, aber die adaptiven Requisiten werden entfernt und das Bild sieht sowohl im hellen als auch im dunklen Design gleich aus.

.btn-custom {
  --_bg: linear-gradient(hsl(228 94% 67%), hsl(228 81% 59%));
  --_border: hsl(228 89% 63%);
  --_text: hsl(228 89% 100%);
  --_ink-shadow: 0 1px 0 hsl(228 57% 50%);
  --_highlight: hsl(228 94% 67% / 20%);
}

Die benutzerdefinierte Schaltfläche wird hell und dunkel dargestellt. Sie ist wie bei den meisten primären Aktionsschaltflächen sehr leuchtend blau.

Große Schaltfläche

Für diesen Schaltflächenstil wird die benutzerdefinierte Eigenschaft --_size geändert. Padding- und andere Abstandselemente sind relativ zu dieser Größe und werden proportional zur neuen Größe skaliert.

.btn-large {
  --_size: 1.5rem;
}

Die große Schaltfläche wird neben der benutzerdefinierten Schaltfläche angezeigt und ist etwa 150-mal größer.

Symbolschaltfläche

Dieser Symboleffekt hat nichts mit unseren Schaltflächenstilen zu tun, zeigt aber, wie er mit nur wenigen CSS-Properties erreicht werden kann und wie gut die Schaltfläche mit Symbolen umgeht, die kein Inline-SVG sind.

[data-icon="cloud"] {
  --icon-cloud: url("https://api.iconify.design/mdi:apple-icloud.svg") center / contain no-repeat;

  -webkit-mask: var(--icon-cloud);
  mask: var(--icon-cloud);
  background: linear-gradient(to bottom, var(--_accent-dark), var(--_accent-light));
}

Eine Schaltfläche mit einem Symbol wird im hellen und dunklen Design angezeigt.

Fazit

Wie würden Sie es machen?

Lassen Sie uns unsere Ansätze diversifizieren und alle Möglichkeiten kennenlernen, wie Sie im Web entwickeln können.

Erstelle eine Demo und sende Tweets an mich. Ich füge sie dann unten im Abschnitt zu Community-Remixen hinzu.

Remixe der Community

Noch keine Aktivität hierzu.

Ressourcen