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
Wenn du lieber ein Video ansiehst, findest du hier eine YouTube-Version dieses Beitrags:
Übersicht
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.
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 {}
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) {
…
}
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>
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
: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.
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);
}
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);
}
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);
}
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 ü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);
}
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;
}
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);
}
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;
}
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 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);
}
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);
}
}
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%);
}
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;
}
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 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
- Quellcode auf GitHub