Eine grundlegende Übersicht zum Erstellen farbadaptiver, responsiver und barrierefreier <button>
-Komponenten.
In diesem Beitrag möchte ich meine Gedanken dazu teilen, wie man ein farbadaptives, responsives und barrierefreies <button>
-Element erstellt.
Demo ausprobieren und Quellcode ansehen
Wenn du lieber ein Video ansiehst, findest du hier eine YouTube-Version dieses Beitrags:
Übersicht
Das Element <button>
ist für die Nutzerinteraktion gedacht. Die click
-Ereignisse werden unter anderem über Tastatur, Maus, Touch und Sprache ausgelöst und haben intelligente Regeln für das Timing. Außerdem sind in jedem Browser einige Standardstile enthalten, die Sie direkt 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 Umgebung 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.
Schaltflächen haben auch Pseudoklassen, die für das CSS-Styling verwendet werden. Mit diesen Klassen können Sie die Schaltfläche mithilfe von CSS-Hooks anpassen: :hover
für den Zustand, wenn die Maus den Mauszeiger auf die Schaltfläche bewegt, :active
für den Zustand, wenn die Maus oder Tastatur gedrückt wird, und :focus
oder :focus-visible
für die Unterstützung beim Styling von Hilfstechnologien.
button:hover {}
button:active {}
button:focus {}
button:focus-visible {}
Markieren & Zeichnen
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. Ich wechsle auch die Symbolstrategie von Inline-SVG zu einem maskierten SVG, um sicherzustellen, dass 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 zu diesem Zeitpunkt ziemlich überwältigend. Zwischen Schaltflächentypen, Pseudoklassen und der Zugehörigkeit zu einem Formular 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()
. So kann ich dafür sorgen, dass meine Benutzeroberflächen immer die Anforderungen von Tastaturen und Hilfstechnologien berücksichtigen.
button:is(:hover, :focus) {
…
}
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. Hier wird VisBug verwendet, um alle Bewertungen gleichzeitig zu prü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>
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 klar zu erkennen, dass das helle Design das Standarddesign ist und das dunkle Design nur bedingt angewendet wird.
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, ist für die Anpassung der Schaltfläche keine spezifische Angabe erforderlich. Schaltflächen werden häufig für alternative Szenarien angepasst und die Auswahl :where()
sorgt dafür, dass die Aufgabe einfach ist. Innerhalb von :where()
ist jeder Schaltflächentyp ausgewählt, einschließlich ::file-selector-button
, der 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
, die mit hsl()
erstellt wurden und dem Farbton 210
entsprechen:
--_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 nahe oder vor anderen Oberflächen erscheinen:
--_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. Das wird kritisch, wenn große Schaltflächen die font-size
und die Schaltflächenskala einfach proportional erhöhen können:
--_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
Mit diesen Eigenschaften wird eine Größe für die Übergangsanimation bei Interaktion festgelegt. Die Markierungsfarbe folgt dem adaptiven Farbsystem. Wie diese miteinander interagieren, wird später in diesem Beitrag erläutert. Sie werden aber letztendlich 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ächen
Jede Schaltfläche hat einen dezenten Textschatten. So wird der Text über der Schaltfläche angezeigt, 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
Die Symbole haben wieder die Größe von zwei Zeichen, da die relative Länge ch
verwendet wird. So wird das Symbol proportional zum Schaltflächentext skaliert. 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, auf die sie gelegt werden, getönt sein. Schatten in dunklen Designs 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%));
Außerdem verleiht ein 1px
Box-Schatten den Schaltflächen ein leicht dreidimensionales Aussehen:
--_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
: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); }
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.
Anpassungen für reduzierte Bewegung
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 gemeinsame 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);
}
Schaltflächen für das Design
Auswahleinstellung
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 Touchbedienung
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 bei Klicks nicht gewartet werden muss und ein potenzieller Doppelklick erkannt wird. So wirken die Schaltflächen schneller:
: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);
}
Schatten
Bei den Schaltflächen wurden einige gute Techniken angewendet. Das Symbol text-shadow
passt sich hellen und dunklen Umgebungen an, wodurch der Schaltflächentext dezent auf dem Hintergrund erscheint. Dem box-shadow
sind drei Schatten zugewiesen. Die erste, --_shadow-2
, ist ein normaler Schatten.
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);
}
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;
}
Abstand
Für den Abstand zwischen den Schaltflächen habe ich gap
verwendet, damit sich Geschwisterelemente nicht berühren, 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);
}
UX für Touchbedienung 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 Funktion, 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 auch.
: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 mithilfe der benutzerdefinierten Property mit Inline- und Blocklogik-Properties 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. Zum Schluss wähle ich Liniensymbole aus und weise diesen Stilen hier mit den Linienenden und -übergängen 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;
}
Sendeschaltflächen 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);
}
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. Die Anpassung erfolgt durch Ändern der entsprechenden hellen oder dunklen Hintergrundfarbe. Die Schaltfläche aktualisiert den Stil:
: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;
}
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);
}
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 hat max-inline-size
, damit er nicht größer wird als nötig, während inline-size: 100%
sich verkleinern und in Container passen lässt, die kleiner sind als er. Die Hintergrundfarbe ist auf eine adaptive Farbe festgelegt, die dunkler als andere Oberflächen ist, sodass sie hinter der Schaltfläche für die Dateiauswahl erscheint.
: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);
}
Besondere Ausnahmen für das dunkle Design
Ich habe den primären Aktionsschaltflächen einen dunkleren Hintergrund gegeben, um einen höheren Kontrast zum Text zu erzielen. Dadurch wirken sie etwas stärker hervorgehoben.
@media (prefers-color-scheme: dark) {
:where(
[type="submit"],
[type="reset"],
[disabled],
form button:not([type="button"])
) {
--_bg: var(--_input-well);
}
}
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 ist 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%);
}
Große Schaltfläche
Dieser Schaltflächenstil wird durch Ändern der benutzerdefinierten Property --_size
erreicht.
Ränder und andere Elemente für den Abstand sind relativ zu dieser Größe und werden proportional zur neuen Größe skaliert.
.btn-large {
--_size: 1.5rem;
}
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));
}
Fazit
Wie würden Sie das machen?
Lassen Sie uns unsere Ansätze diversifizieren und alle Möglichkeiten kennenlernen, wie Sie im Web entwickeln können.
Erstelle eine Demo, tweete mir Links und ich füge sie unten in den Abschnitt „Community-Remixe“ hinzu.
Remixe der Community
Noch keine Aktivität hierzu.
Ressourcen
- Quellcode auf GitHub