Schaltflächenkomponente erstellen

Ein grundlegender Überblick über das Erstellen von farbanpassungsfähigen, responsiv und barrierefrei zugänglichen <button>-Komponenten.

In diesem Beitrag möchte ich dir mitteilen, wie man ein farbanpassungsfähiges, responsives und barrierefreies <button>-Element erstellt. Demo ansehen und Quelle ansehen

Im hellen und dunklen Design erfolgt die Interaktion mit Tasten per Tastatur und Maus.

Falls du lieber ein Video hast, findest du hier eine YouTube-Version dieses Beitrags:

Überblick

Unterstützte Browser

  • 1
  • 12
  • 1
  • ≤4

Quelle

Das Element <button> ist für die Nutzerinteraktion konzipiert. Das click-Ereignis wird unter anderem über die Tastatur, die Maus, die Touch-Geste oder die Stimme ausgelöst. Dabei werden intelligente Regeln zur Zeitsteuerung berücksichtigt. In jedem Browser sind auch einige Standardstile enthalten, sodass Sie diese direkt und ohne Anpassungen verwenden können. Verwenden Sie color-scheme, um vom Browser bereitgestellte helle und dunkle Schaltflächen zu aktivieren.

Es gibt auch verschiedene Arten von Schaltflächen, die alle in der vorherigen Codepen-Einbettung gezeigt werden. Ein <button> ohne Typ passt sich an eine <form> an und wird in den Übermittlungstyp geändert.

<!-- 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">

Im Rahmen der GUI Challenge dieses Monats erhalten alle Schaltflächen einen Stil, mit dem sie ihre Absicht visuell unterscheiden können. Schaltflächen zum Zurücksetzen haben Warnfarben, da sie destruktiv sind. Für Schaltfläche zum Senden wird ein blauer Akzenttext angezeigt, sodass sie etwas stärker hervorgehoben werden als normale Schaltflächen.

Vorschau des endgültigen Satzes aller Schaltflächentypen, der in einem Formular und nicht in einem Formular angezeigt wird, mit praktischen Ergänzungen für Symbolschaltflächen und benutzerdefinierte Schaltflächen.
Vorschau der endgültigen Gruppe aller Schaltflächentypen, die in einem Formular und nicht in einem Formular angezeigt wird, mit praktischen Ergänzungen für Symbolschaltflächen und benutzerdefinierte Schaltflächen

Schaltflächen haben auch Pseudoklassen, die CSS für Stile verwenden kann. Diese Klassen bieten CSS-Hooks zum Anpassen der Funktion der Schaltfläche: :hover für das Bewegen der Maus über der Schaltfläche, :active für das Drücken einer Maus oder Tastatur und :focus oder :focus-visible zur Unterstützung beim Gestalten von Hilfstechnologien.

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

Markup

Zusätzlich zu den Schaltflächentypen, die über die HTML-Spezifikation bereitgestellt werden, habe ich eine Schaltfläche mit einem Symbol und einer Schaltfläche mit der 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 wird jede Schaltfläche zum Testen in einem Formular platziert. Auf diese Weise kann ich dafür sorgen, dass die Stile für die Standardschaltfläche, die sich wie eine Senden-Schaltfläche verhält, korrekt aktualisiert werden. Außerdem stelle ich die Symbolstrategie von Inline-SVG auf maskierte SVG um, damit beide Elemente 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 dieser Stelle ziemlich überwältigend. Zwischen Schaltflächentypen und Pseudoklassen gibt es mehr als 20 Schaltflächenkombinationen, je nachdem, ob sie sich in einem Formular befinden oder nicht. Es ist gut, dass CSS uns hilft, die einzelnen Punkte klar zu formulieren.

Barrierefreiheit

Schaltflächenelemente sind natürlich zugänglich, es gibt jedoch einige gängige Verbesserungen.

Hover und fokussieren

Ich gruppiere :hover und :focus gern mit dem funktionalen Pseudoselektor :is(). Das trägt dazu bei, dass in meinen Benutzeroberflächen immer der Stil von Tastatur und Hilfstechnologien berücksichtigt wird.

button:is(:hover, :focus) {
  …
}
Demo ausprobieren.

Interaktiver Fokusring

Ich liebe es, den Fokusring für Nutzende von Tastaturen und Hilfstechnologien zu animieren. Dazu werde ich den Umriss um 5 Pixel von der Schaltfläche weg animieren, aber nur, wenn die Schaltfläche nicht aktiv ist. Dadurch wird der Fokusring beim Drücken auf die Größe der Schaltfläche verkleinert.

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

Sicherstellen, dass Farbkontraste weitergegeben werden

Es gibt mindestens vier verschiedene Farbkombinationen in hellen und dunklen Farben, die einen Farbkontrast berücksichtigen müssen: Schaltfläche, Senden-Schaltfläche, Schaltfläche zum Zurücksetzen und deaktivierte Schaltfläche. Hier wird VisBug verwendet, um alle ihre Punktzahlen auf einmal zu überprüfen und anzuzeigen:

Verbergen von Symbolen für Personen, die sie nicht sehen können

Beim Erstellen einer Symbolschaltfläche sollte das Symbol den Schaltflächentext visuell unterstützen. Das bedeutet auch, dass das Symbol für Personen mit Sehverlust keinen Wert hat. Glücklicherweise bietet der Browser die Möglichkeit, Elemente vor Screenreader-Technologie zu verbergen, damit Menschen mit Sehverlust nicht mit dekorativen Schaltflächenbildern gestört werden:

<button>
  <svg … aria-hidden="true">...</svg>
  Icon Button
</button>
Chrome-Entwicklertools mit der Baumansicht der Bedienungshilfen für die Schaltfläche. Die Baumstruktur ignoriert das Schaltflächenbild, weil „aria-hidden“ auf „true“ festgelegt ist.
Chrome-Entwicklertools mit der Baumansicht der Bedienungshilfen für die Schaltfläche. Die Baumstruktur ignoriert das Schaltflächenbild, weil „aria-hidden“ auf „true“ festgelegt ist

Stile

Im nächsten Abschnitt richte ich zuerst ein System mit benutzerdefinierten Eigenschaften ein, um die adaptiven Stile der Schaltfläche zu verwalten. Mit diesen benutzerdefinierten Eigenschaften kann ich Elemente auswählen und ihr Erscheinungsbild anpassen.

Adaptive Strategie für benutzerdefinierte Properties

Die in dieser GUI Challenge verwendete Strategie für benutzerdefinierte Eigenschaften ähnelt sehr der Strategie, die beim Erstellen eines Farbschemas verwendet wird. Bei einem adaptiven hellen und dunklen Farbsystem wird für jedes Design eine benutzerdefinierte Eigenschaft definiert und entsprechend benannt. Dann wird eine einzelne benutzerdefinierte Eigenschaft verwendet, die den aktuellen Wert des Designs enthält, und einer CSS-Eigenschaft zugewiesen. Später kann diese einzelne benutzerdefinierte Eigenschaft auf einen anderen Wert und dann den Stil der Schaltfläche 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);
  }
}

Was mir gefällt, ist, dass das helle und das dunkle Design aussagekräftig und klar sind. Die Indirektion und Abstraktion werden in das benutzerdefinierte Attribut --_bg übertragen, das jetzt die einzige „reaktive“ Eigenschaft ist. --_bg-light und --_bg-dark sind statisch. Außerdem ist zu erkennen, dass das helle Design das Standarddesign ist und das dunkle Design nur bedingt angewendet wird.

Auf Einheitlichkeit des Designs vorbereiten

Die gemeinsam genutzte Auswahl

Der folgende Selektor wird für die Ausrichtung auf alle verschiedenen Schaltflächentypen verwendet und ist anfangs etwas überwältigend. Da dabei :where() verwendet wird, ist das Anpassen der Schaltfläche nicht spezifisch. Schaltflächen werden häufig an alternative Szenarien angepasst. Mit der Auswahl :where() ist diese Aufgabe einfach. In :where() wird jeder Schaltflächentyp ausgewählt, einschließlich ::file-selector-button, der innerhalb von :is() oder :where() nicht 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 Eigenschaften werden innerhalb dieser Auswahl zugeordnet. Sehen wir uns nun alle benutzerdefinierten Eigenschaften an. In dieser Schaltfläche werden viele benutzerdefinierte Eigenschaften verwendet. Ich beschreibe die einzelnen Gruppen und stelle dann am Ende des Abschnitts den dunklen und reduzierten Bewegungskontext vor.

Akzentfarbe der Schaltfläche

Die Schaltflächen und Symbole zum Einreichen von Inhalten eignen sich hervorragend für einen farbigen Touch:

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

Schriftfarbe für Schaltfläche

Die Farben der Schaltflächentexte sind nicht weiß oder schwarz. Sie sind dunklere oder aufgehellte Versionen von --_accent mit hsl() und dem Farbton 210:

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

Hintergrundfarbe der Schaltfläche

Die Hintergründe für Schaltflächen folgen demselben hsl()-Muster, mit Ausnahme der Schaltflächen im hellen Design. Sie sind auf Weiß eingestellt, damit sie mit ihrer Oberfläche in der Nähe des Nutzers oder vor anderen Oberflächen erscheinen können:

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

Schaltflächenhintergrund

Mit dieser Hintergrundfarbe lässt sich eine Oberfläche hinter anderen Oberflächen erscheinen. Dies ist nützlich für den Hintergrund der Dateieingabe:

--_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 wird mit der Einheit ch festgelegt, einer relativen Länge zur Schriftgröße. Dies ist wichtig, wenn große Schaltflächen font-size einfach nach oben bewegen können und die Schaltfläche proportional skaliert wird:

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

Schaltflächenrahmen

Der Radius des Schaltflächenrahmens wird in eine benutzerdefinierte Eigenschaft verschoben, damit die Dateieingabe mit den anderen Schaltflächen übereinstimmen kann. Die Rahmenfarben entsprechen dem etablierten adaptiven Farbsystem:

--_border-radius: .5ch;

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

Hervorhebungseffekt für Schaltfläche

Diese Eigenschaften definieren eine Größeneigenschaft für den Übergang bei einer Interaktion, und die Hervorhebungsfarbe folgt dem adaptiven Farbsystem. Wir besprechen später in diesem Beitrag, wie diese interagieren, aber letztendlich werden sie für einen 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äche

Jede Schaltfläche hat einen dezenten Textschatten. So hat der Text mehr Platz auf der Schaltfläche, was die Lesbarkeit verbessert und die Präsentation noch 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 haben die Größe von zwei Zeichen, da wieder die Einheit ch für die relative Länge verwendet wird, damit das Symbol proportional zum Schaltflächentext skaliert wird. Die Symbolfarbe stützt sich auf --_accent-color für eine adaptive Farbe, die innerhalb des Designs liegt.

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

Schaltflächenschatten

Damit sich Schatten richtig an Licht und Dunkel anpassen, müssen sowohl Farbe als auch Deckkraft geändert werden. Schatten im hellen Design sind am besten, wenn sie subtil und in Richtung der Oberflächenfarbe, die sie überlagern, eingefärbt sind. Schatten im dunklen Design müssen dunkler und gesättigter sein, damit dunklere Oberflächenfarben überlagert werden 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%));

Um den Schaltflächen eine etwas 3D-Darstellung zu verleihen, erzeugt ein 1px-Feldschatten diese 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 für die Optionen des Designsystems:

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

Alle Properties in der Auswahl

Alle benutzerdefinierten Eigenschaften 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 des dunklen Designs

Der Wert der statischen Attribute -light und -dark wird deutlich, wenn die Attribute für das dunkle Design festgelegt sind:

@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, Nutzer können sich aber auch darauf verlassen, dass sie sich angemessen an die Nutzerpräferenzen anpassen.

Reduzierte Bewegungsanpassung

Wenn die Bewegung für diesen Besucher in Ordnung ist, weisen Sie var(--_transition-motion-ok) --_transition 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 gemeinsame Stile

Für Schaltflächen und Eingaben muss die Schriftarten auf inherit festgelegt sein, damit sie mit den restlichen Seitenschriftarten übereinstimmen. Andernfalls werden sie vom Browser formatiert. Dies gilt auch für letter-spacing. Wenn Sie line-height auf 1.5 setzen, wird die Größe des Buchstabenfelds so festgelegt, dass dem Text darüber und unten etwas Platz eingeräumt wird:

: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 vorhergehenden Stile

Stile für Schaltflächen festlegen

Anpassung der Auswahl

Der Selektor input[type="file"] ist nicht der Schaltflächenteil der Eingabe, sondern das Pseudoelement ::file-selector-button. Deshalb 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 {
  
}

Cursor- und Touch-Anpassungen

Zuerst gestalte ich den Cursor im Stil pointer, sodass die Schaltfläche Nutzern der Maus anzeigt, dass sie interaktiv ist. Dann füge ich touch-action: manipulation hinzu, damit Klicks nicht warten und einen möglichen Doppelklick beobachten müssen, damit sich die Schaltflächen schneller anfühlen:

: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 mithilfe einiger der zuvor beschriebenen adaptiven benutzerdefinierten Eigenschaften an:

: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 vorhergehenden Stile

Schatten

Bei den Schaltflächen wurden tolle Techniken angewandt. Das text-shadow passt sich an Hell- und Dunkel an und sorgt für ein dezentes Erscheinungsbild des Schaltflächentexts, der schön über dem Hintergrund liegt. Dem box-shadow werden drei Schatten zugewiesen. Die erste, --_shadow-2, ist ein normaler Boxschatten. Der zweite Schatten ist ein Trick für das Auge, der den Eindruck vermittelt, dass die Schaltfläche etwas abgeschrägt wirkt. Der letzte Schatten ist für die Hervorhebung durch Bewegen des Mauszeigers bestimmt. Zu Beginn hat er die Größe 0, erhält aber später eine Größe und geht über die Schaltfläche hinaus.

: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 Anwendung der vorhergehenden Stile

Layout

Ich habe der Schaltfläche ein Flexbox-Layout gegeben, genauer gesagt ein inline-flex-Layout, das in den Inhalt passt. Dann zentriere ich den Text und richte die untergeordneten Elemente vertikal und horizontal an der center-Position aus. Symbole und andere Schaltflächenelemente können dann richtig ausgerichtet werden.

: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 vorhergehenden Stile

Abstand

Für den Schaltflächenabstand habe ich gap verwendet, um gleichgeordnete Elemente nicht zu berühren, und logische Eigenschaften für den Abstand, damit der Schaltflächenabstand bei allen 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 Anwendung der vorhergehenden Stile

UX für Touch- und Maus-Steuerung

Der nächste Abschnitt richtet sich hauptsächlich an Nutzer mit Touchscreen auf Mobilgeräten. Die erste Eigenschaft user-select ist für alle Nutzer verfügbar. Sie verhindert, dass Text den Schaltflächentext hervorhebt. Dies macht sich vor allem auf Geräten mit Touchscreen bemerkbar, wenn eine Taste gedrückt wird und das Betriebssystem den Text der Schaltfläche markiert.

Ich habe im Allgemeinen festgestellt, dass dies nicht die Nutzererfahrung mit Schaltflächen in integrierten Apps ist. Deshalb deaktiviere ich sie, indem ich user-select auf „none“ setze. Tipp-Hervorhebungsfarben (-webkit-tap-highlight-color) und Betriebssystem-Kontextmenüs (-webkit-touch-callout) sind weitere sehr weborientierte Schaltflächenfunktionen, die nicht den allgemeinen Nutzererwartungen der 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 ist dem Attribut 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, während er nicht aktiv drückt, passen Sie die Größe der Schatten-Hervorhebung so an, dass der Fokus von der Schaltfläche aus größer wird:

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

Vergrößere im Fokus den Fokus, um den Abstand zur Schaltfläche zu vergrößern, damit die Schaltfläche auch optisch zu sehen ist:

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

Symbole

Zur Verarbeitung von Symbolen wurde im Selektor ein :where()-Selektor für direkte untergeordnete SVG-Elemente oder Elemente mit dem benutzerdefinierten Attribut data-icon hinzugefügt. Die Symbolgröße wird mit der benutzerdefinierten Eigenschaft mithilfe von Inline- und Blocklogikeigenschaften festgelegt. Die Strichfarbe wird festgelegt und es wird ein drop-shadow für text-shadow festgelegt. flex-shrink ist auf 0 gesetzt, sodass das Symbol nie zusammengedrückt wird. Zuletzt wähle ich Liniensymbole aus und weise diese Stile hier mit den Linienabschlüssen 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 vorhergehenden Stile

Senden-Schaltflächen anpassen

Ich wollte, dass das Erscheinungsbild der Schaltflächen etwas verbessert wird. Dazu habe ich die Textfarbe der Schaltflächen als Akzentfarbe festgelegt:

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

Screenshot mit Schaltflächen nach Anwendung der vorhergehenden Stile

Tasten zum Zurücksetzen anpassen

Ich wollte, dass die Schaltflächen zum Zurücksetzen mit eingebauten Warnhinweisen ausgestattet sind, um Nutzer auf potenziell destruktives Verhalten aufmerksam zu machen. Ich habe auch die Schaltfläche für das helle Design mit mehr roten Akzenten gestaltet als das dunkle. Für die Anpassung wird die entsprechende helle oder dunkle Farbe geändert und der Stil über die Schaltfläche 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 fand ich es gut, dass die Farbe des Fokusumrisses zum Rot passt. Die Textfarbe passt sich von Dunkelrot in Hellrot an. Dafür muss die Umrissfarbe dem Keyword currentColor entsprechen:

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

Screenshot mit Schaltflächen nach Anwendung der vorhergehenden Stile

Deaktivierte Schaltflächen anpassen

Es kommt häufig vor, dass bei deaktivierten Schaltflächen während des Versuchs, die deaktivierte Schaltfläche zu deaktivieren, einen schlechten Farbkontrast hat, sodass sie weniger aktiv erscheint. Ich habe jeden Farbsatz getestet und überprüft, ob sie bestanden wurde. Dabei werte ich den HSL-Helligkeitswert aus, bis der Wert in den Entwicklertools oder VisBug bestanden wurde.

: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 vorhergehenden Stile

Schaltflächen zur Dateieingabe anpassen

Die Schaltfläche zur Dateieingabe ist ein Container für einen Span und eine Schaltfläche. CSS kann den Eingabecontainer und die verschachtelte Schaltfläche entsprechend gestalten, aber nicht den Span. Der Container erhält max-inline-size, damit er nicht größer als nötig wird, während inline-size: 100% Container verkleinert und kleiner als sie ist. Die Hintergrundfarbe wird auf eine adaptive Farbe festgelegt, die dunkler ist als andere Oberflächen, 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äche für die Dateiauswahl und die Schaltflächen für den Eingabetyp erhalten appearance: none, 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;
}

Zuletzt wird der Rand zu inline-end der Schaltfläche hinzugefügt, um den Span-Text von der Schaltfläche wegzuschieben und dadurch etwas Platz zu schaffen.

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

Screenshot mit Schaltflächen nach Anwendung der vorhergehenden Stile

Spezielle Ausnahmen für das dunkle Design

Für den Text habe ich einen dunkleren Hintergrund für die primären Aktionsschaltflächen gewählt.

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

Screenshot mit Schaltflächen nach Anwendung der vorhergehenden Stile

Varianten erstellen

Aus Spaß und weil es praktisch ist, habe ich gezeigt, wie man ein paar Varianten erstellt. Eine Variante ist sehr farbenfroh, ähnlich wie primäre Schaltflächen häufig aussehen. Eine weitere Variante ist groß. Die letzte Variante hat ein Symbol mit Farbverlauf.

Leuchtende Schaltfläche

Für diesen Schaltflächenstil habe ich die Basis-Requisiten direkt mit blauen Farben überschrieben. Dies war zwar schnell und einfach, aber die adaptiven Requisiten wurden entfernt und sehen in hellen und dunklen Designs 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 angezeigt. Es ist sehr leuchtend blau, wie es typische primäre Aktionsschaltflächen in der Regel tun.

Große Schaltfläche

Dieser Schaltflächenstil wird durch Ändern der benutzerdefinierten Eigenschaft --_size erreicht. Innenabstände und andere Abstandselemente sind relativ zu dieser Größe und werden proportional mit der neuen Größe skaliert.

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

Neben der benutzerdefinierten Schaltfläche wird eine große Schaltfläche angezeigt, die etwa 150-mal größer ist.

Symbolschaltfläche

Dieser Symboleffekt hat nichts mit unseren Schaltflächenstile zu tun, zeigt aber, wie er mit nur wenigen CSS-Eigenschaften erreicht wird und wie gut die Schaltfläche Symbole verarbeitet, 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 in hellen und dunklen Designs angezeigt.

Fazit

Jetzt weißt du, wie ich es gemacht habe. Wie würdest du es erreichen? 🙂

Diversifizieren wir unsere Ansätze und lernen Sie alle Möglichkeiten kennen, wie wir das Web nutzen können.

Erstelle eine Demo und twittere mich über Links, und ich füge sie unten zum Abschnitt über Community-Remixe hinzu.

Community-Remixe

Hier gibt es noch nichts zu sehen.

Ressourcen