Podstawowe informacje o tym, jak tworzyć komponenty <button> dostosowujące się do koloru, responsywne i dostępne.
W tym poście chcę podzielić się moimi przemyśleniami na temat tworzenia elementu <button>, który dostosowuje się do koloru, jest responsywny i dostępny.
Wypróbuj wersję demonstracyjną i wyświetl kod źródłowy
Jeśli wolisz film, obejrzyj tę wersję posta w YouTube:
Przegląd
Element
<button>
jest przeznaczony do interakcji z użytkownikiem. click zdarzenia wywoływane przez klawiaturę, mysz, dotyk, głos i inne elementy, z inteligentnymi regułami dotyczącymi czasu; Każda przeglądarka ma też domyślne style, których możesz używać bezpośrednio bez żadnych dostosowań. Użyj color-scheme, aby włączyć też jasne i ciemne przyciski udostępniane przez przeglądarkę.
Istnieją też różne rodzaje przycisków, z których każdy jest widoczny w poprzednim osadzonym elemencie Codepen. Element <button> bez typu dostosuje się do elementu <form> i zmieni typ na przesyłanie.
<!-- 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">
W tym miesiącu w ramach GUI Challenge każdy przycisk otrzyma style, które pomogą wizualnie odróżnić jego przeznaczenie. Przyciski resetowania będą miały kolory ostrzegawcze, ponieważ są destrukcyjne, a przyciski przesyłania będą miały niebieski tekst akcentujący, dzięki czemu będą nieco bardziej wyróżnione niż zwykłe przyciski.
Przyciski mają też pseudoklasy, których CSS może używać do określania stylu. Te klasy zapewniają zaczepy CSS do dostosowywania wyglądu przycisku: :hover, gdy kursor myszy znajduje się nad przyciskiem, :active, gdy mysz lub klawiatura jest wciśnięta, oraz :focus lub :focus-visible, aby ułatwić stylizację technologii wspomagających.
button:hover {}
button:active {}
button:focus {}
button:focus-visible {}
Znacznik
Oprócz typów przycisków określonych w specyfikacji HTML dodałem przycisk z ikoną i przycisk z klasą niestandardową btn-custom.
<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">
Następnie na potrzeby testowania każdy przycisk jest umieszczany w formularzu. Dzięki temu mogę mieć pewność, że style są odpowiednio aktualizowane w przypadku przycisku domyślnego, który działa jak przycisk przesyłania. Zmieniam też strategię dotyczącą ikon z wstawionego pliku SVG na zamaskowany plik SVG, aby oba rozwiązania działały równie dobrze.
<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>
Macierz kombinacji jest w tym momencie dość przytłaczająca. Istnieje ponad 20 kombinacji przycisków, które różnią się typem, pseudoklasą oraz tym, czy znajdują się w formularzu. Na szczęście usługi porównywania cen pomagają nam jasno określić każdy z tych aspektów.
Ułatwienia dostępu
Elementy typu button są z natury dostępne, ale istnieje kilka typowych ulepszeń.
Najedź kursorem i skup się na tym, co ważne
Chcę zgrupować :hover i :focus za pomocą selektora pseudoklasy :is(). Dzięki temu moje interfejsy zawsze uwzględniają style klawiatury i technologii wspomagających.
button:is(:hover, :focus) {
…
}
Interaktywny pierścień ostrości
Chcę animować pierścień zaznaczenia dla użytkowników klawiatury i technologii wspomagających. Osiągam to, animując kontur przycisku w odległości 5 pikseli od niego, ale tylko wtedy, gdy przycisk nie jest aktywny. Spowoduje to efekt, w którym pierścień fokusu zmniejszy się do rozmiaru przycisku po jego naciśnięciu.
:where(button, input):where(:not(:active)):focus-visible {
outline-offset: 5px;
}
Zapewnianie odpowiedniego kontrastu kolorów
W przypadku jasnych i ciemnych motywów należy wziąć pod uwagę co najmniej 4 różne kombinacje kolorów, które wymagają sprawdzenia kontrastu kolorów: przycisk, przycisk przesyłania, przycisk resetowania i wyłączony przycisk. VisBug służy do sprawdzania i wyświetlania wszystkich wyników jednocześnie:
Ukrywanie ikon przed osobami, które nie widzą
Podczas tworzenia przycisku z ikoną ikona powinna wizualnie wspierać tekst przycisku. Oznacza to również, że ikona nie jest przydatna dla osób z wadą wzroku. Na szczęście przeglądarka umożliwia ukrywanie elementów przed czytnikami ekranu, dzięki czemu osoby z wadami wzroku nie są rozpraszane przez dekoracyjne obrazy przycisków:
<button>
<svg … aria-hidden="true">...</svg>
Icon Button
</button>
Style
W następnej sekcji najpierw utworzę system właściwości niestandardowych do zarządzania stylami adaptacyjnymi przycisku. Dzięki tym właściwościom niestandardowym mogę zacząć wybierać elementy i dostosowywać ich wygląd.
Strategia adaptacyjnych właściwości niestandardowych
Strategia dotycząca właściwości niestandardowych użyta w tym wyzwaniu związanym z GUI jest bardzo podobna do tej, która została zastosowana w tworzeniu schematu kolorów. W przypadku adaptacyjnego systemu kolorów jasnych i ciemnych definiowana jest właściwość niestandardowa dla każdego motywu i odpowiednio nazywana. Następnie pojedyncza właściwość niestandardowa służy do przechowywania bieżącej wartości motywu i jest przypisywana do właściwości CSS. Później pojedynczą właściwość niestandardową można zaktualizować do innej wartości, a następnie zaktualizować styl przycisku.
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);
}
}
Podoba mi się, że motywy jasny i ciemny są deklaratywne i przejrzyste. Pośredniość i abstrakcja są przenoszone do --_bg właściwości niestandardowej, która jest teraz jedyną właściwością „reaktywną”; --_bg-light i --_bg-dark są statyczne. Jest też wyraźnie napisane, że jasny motyw jest domyślny, a ciemny jest stosowany tylko warunkowo.
Przygotowanie do zachowania spójności projektu
Udostępniony selektor
Ten selektor służy do kierowania na wszystkie rodzaje przycisków i na początku może wydawać się nieco przytłaczający. :where() jest używany, więc dostosowanie przycisku nie wymaga określania szczegółów. Przyciski są często dostosowywane do alternatywnych scenariuszy, a selektor :where() ułatwia wykonanie zadania. W elemencie :where() wybrano każdy typ przycisku, w tym ::file-selector-button, którego nie można używać w elementach :is() ani :where().
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"],
input[type="file"]
),
:where(input[type="file"])::file-selector-button {
…
}
Wszystkie właściwości niestandardowe będą miały zakres ograniczony do tego selektora. Czas sprawdzić wszystkie właściwości niestandardowe. W tym przycisku jest używanych sporo właściwości niestandardowych. Każdą grupę opiszę po kolei, a na końcu sekcji przedstawię konteksty ciemnego motywu i ograniczonego ruchu.
Kolor akcentu przycisku
Przyciski przesyłania i ikony to świetne miejsce na dodanie odrobiny koloru:
--_accent-light: hsl(210 100% 40%);
--_accent-dark: hsl(210 50% 70%);
--_accent: var(--_accent-light);
Kolor tekstu przycisku
Kolory tekstu przycisku nie są białe ani czarne, ale są przyciemnionymi lub rozjaśnionymi wersjami koloru --_accent, w których użyto hsl() i zachowano odcień 210:
--_text-light: hsl(210 10% 30%);
--_text-dark: hsl(210 5% 95%);
--_text: var(--_text-light);
Kolor tła przycisku
Tła przycisków są zgodne z tym samym wzorem hsl(), z wyjątkiem przycisków w jasnym motywie – są one ustawione na biały, dzięki czemu wydają się bliżej użytkownika lub przed innymi powierzchniami:
--_bg-light: hsl(0 0% 100%);
--_bg-dark: hsl(210 9% 31%);
--_bg: var(--_bg-light);
Tło przycisku
Ten kolor tła służy do umieszczania powierzchni za innymi powierzchniami. Jest przydatny w przypadku tła pola wprowadzania pliku:
--_input-well-light: hsl(210 16% 87%);
--_input-well-dark: hsl(204 10% 10%);
--_input-well: var(--_input-well-light);
Dopełnienie przycisku
Odstępy wokół tekstu w przycisku są określane za pomocą jednostki ch, która jest długością względną w stosunku do rozmiaru czcionki. Ma to kluczowe znaczenie, gdy duże przyciski mogą po prostu zwiększać font-size i skalę przycisków proporcjonalnie:
--_padding-inline: 1.75ch;
--_padding-block: .75ch;
Obramowanie przycisku
Promień obramowania przycisku jest przechowywany we właściwości niestandardowej, dzięki czemu dane wejściowe pliku mogą pasować do innych przycisków. Kolory obramowania są zgodne z ustalonym adaptacyjnym systemem kolorów:
--_border-radius: .5ch;
--_border-light: hsl(210 14% 89%);
--_border-dark: var(--_bg-dark);
--_border: var(--_border-light);
Efekt podświetlenia po najechaniu kursorem na przycisk
Te właściwości określają właściwość rozmiaru, która ma być zmieniana podczas interakcji, a kolor wyróżnienia jest zgodny z adaptacyjnym systemem kolorów. W dalszej części tego posta omówimy, jak te elementy ze sobą współdziałają, ale ostatecznie służą one do uzyskania efektu box-shadow:
--_highlight-size: 0;
--_highlight-light: hsl(210 10% 71% / 25%);
--_highlight-dark: hsl(210 10% 5% / 25%);
--_highlight: var(--_highlight-light);
Cień tekstu przycisku
Każdy przycisk ma subtelny styl cienia tekstu. Dzięki temu tekst będzie znajdować się nad przyciskiem, co poprawi czytelność i doda element estetyczny.
--_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);
Ikona przycisku
Ikony mają rozmiar 2 znaków dzięki jednostce długości względnej ch, co pomaga skalować ikonę proporcjonalnie do tekstu przycisku. Kolor ikony jest oparty na kolorze --_accent-color, aby zapewnić adaptacyjny kolor w ramach motywu.
--_icon-size: 2ch;
--_icon-color: var(--_accent);
Cień przycisku
Aby cienie prawidłowo dostosowywały się do trybu jasnego i ciemnego, muszą zmieniać zarówno kolor, jak i przezroczystość. Cienie w jasnym motywie najlepiej wyglądają, gdy są subtelne i mają odcień zbliżony do koloru powierzchni, na której są wyświetlane. Cienie w trybie ciemnym muszą być ciemniejsze i bardziej nasycone, aby można było je nakładać na ciemniejsze kolory powierzchni.
--_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);
Dzięki adaptacyjnym kolorom i intensywnościom mogę uzyskać 2 głębokości cieni:
--_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%));
Dodatkowo, aby przyciski wyglądały na trójwymiarowe, zastosowano 1pxbox-shadow
tworzący iluzję:
--_shadow-depth-light: 0 1px var(--_border-light);
--_shadow-depth-dark: 0 1px var(--_bg-dark);
--_shadow-depth: var(--_shadow-depth-light);
Przejścia przycisków
Zgodnie z wzorcem kolorów adaptacyjnych tworzę 2 statyczne właściwości, które będą przechowywać opcje systemu projektowania:
--_transition-motion-reduce: ;
--_transition-motion-ok:
box-shadow 145ms ease,
outline-offset 145ms ease
;
--_transition: var(--_transition-motion-reduce);
Wszystkie usługi razem w selektorze
: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); }

Dostosowania ciemnego motywu
Wartość wzorca statycznych właściwości -light i -dark staje się jasna, gdy ustawione są właściwości ciemnego motywu:
@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);
}
}
Nie tylko dobrze się to czyta, ale też użytkownicy tych niestandardowych przycisków mogą bez obaw korzystać z właściwości podstawowych, ponieważ dostosują się one do preferencji użytkownika.
Dostosowania dotyczące ograniczenia ruchu
Jeśli użytkownik nie ma nic przeciwko ruchowi, przypisz --_transition do
var(--_transition-motion-ok):
@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);
}
}
Kilka stylów udostępnionych
Czcionki przycisków i pól wejściowych muszą być ustawione na inherit, aby pasowały do czcionek na pozostałych stronach. W przeciwnym razie będą stylizowane przez przeglądarkę. Dotyczy to również letter-spacing. Ustawienie line-height na 1.5 powoduje ustawienie rozmiaru pola na litery, aby zapewnić tekstowi trochę miejsca nad i pod nim:
: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);
}

Style przycisków
Regulacja selektora
Selektor input[type="file"] nie jest częścią przycisku w polu wejściowym, ale pseudoelement ::file-selector-button już tak. Dlatego usunąłem input[type="file"] z listy:
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"],
input[type="file"]
),
:where(input[type="file"])::file-selector-button {
}
Dostosowywanie kursora i dotyku
Najpierw nadaję kursorowi styl pointer, który informuje użytkowników myszy, że przycisk jest interaktywny. Następnie dodaję touch-action: manipulation, aby kliknięcia nie musiały czekać i obserwować potencjalnego podwójnego kliknięcia, co sprawia, że przyciski działają szybciej:
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
cursor: pointer;
touch-action: manipulation;
}
Kolory i obramowania
Następnie dostosowuję rozmiar czcionki, tło, tekst i kolory obramowania, używając niektórych z wcześniej utworzonych adaptacyjnych właściwości niestandardowych:
: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);
}

Cienie
Przyciski wykorzystują kilka świetnych technik. text-shadow dostosowuje się do jasnego i ciemnego tła, dzięki czemu tekst przycisku jest subtelnie widoczny na tle. W przypadku
box-shadow przypisane są 3 cienie. Pierwszy z nich, --_shadow-2, to zwykły cień.
Drugi cień to trik, który sprawia, że przycisk wydaje się lekko wypukły. Ostatni cień służy do wyróżnienia po najechaniu kursorem. Początkowo ma rozmiar 0, ale później zostanie mu przypisany rozmiar i zostanie zastosowana do niego animacja, aby wyglądał, jakby powiększał się z przycisku.
: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);
}

Układ
Przycisk ma układ flexbox, a konkretnie układ inline-flex, który będzie pasować do jego zawartości. Następnie wyśrodkowuję tekst i wyrównuję elementy podrzędne w pionie i poziomie do środka. Dzięki temu ikony i inne elementy przycisków będą prawidłowo wyrównane.
: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;
}

Odstępy
W przypadku odstępów między przyciskami użyłem gap, aby elementy sąsiadujące nie stykały się ze sobą, oraz właściwości logicznych w przypadku dopełnienia, dzięki czemu odstępy między przyciskami działają w przypadku wszystkich układów tekstu.
: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 na urządzeniach dotykowych i myszach
Następna sekcja jest przeznaczona głównie dla użytkowników urządzeń mobilnych z ekranem dotykowym. Pierwsza właściwość,
user-select, jest przeznaczona dla wszystkich użytkowników. Zapobiega ona wyróżnianiu tekstu przycisku. Jest to najbardziej widoczne na urządzeniach dotykowych, gdy przycisk jest naciskany i przytrzymywany, a system operacyjny wyróżnia tekst przycisku.
Zazwyczaj nie jest to sposób działania przycisków w aplikacjach wbudowanych, więc wyłączam tę funkcję, ustawiając user-select na none. Kolory podświetlenia (-webkit-tap-highlight-color) i menu kontekstowe systemu operacyjnego (-webkit-touch-callout) to inne funkcje przycisków, które są bardzo zorientowane na internet i nie są zgodne z ogólnymi oczekiwaniami użytkowników, więc też je usuwam.
: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;
}
Przejścia
Zmienna adaptacyjna --_transition jest przypisana do właściwości transition:
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"]
),
:where(input[type="file"])::file-selector-button {
…
transition: var(--_transition);
}
Po najechaniu kursorem, gdy użytkownik nie naciska aktywnie przycisku, dostosuj rozmiar cienia, aby uzyskać efekt skupienia, który sprawia wrażenie, że cień rośnie wewnątrz przycisku:
:where(
button,
input[type="button"],
input[type="submit"],
input[type="reset"]
):where(:not(:active):hover) {
--_highlight-size: .5rem;
}
Po zaznaczeniu zwiększ przesunięcie konturu zaznaczenia od przycisku, aby uzyskać efekt zaznaczenia, który wydaje się rosnąć wewnątrz przycisku:
:where(button, input):where(:not(:active)):focus-visible {
outline-offset: 5px;
}
Ikony
W przypadku ikon selektor ma dodatkowy selektor :where() dla bezpośrednich elementów podrzędnych SVG lub elementów z atrybutem niestandardowym data-icon. Rozmiar ikony jest ustawiany za pomocą właściwości niestandardowej z użyciem właściwości logicznych w wierszu i bloku. Ustawiono kolor obrysu, a także drop-shadow, aby pasował do text-shadow. flex-shrink jest ustawiona na 0, więc ikona nigdy nie jest
spłaszczona. Na koniec wybieram ikony liniowe i przypisuję im style z fill: none i round:
: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;
}

Dostosowywanie przycisków przesyłania
Chciałem, aby przyciski przesyłania miały nieco bardziej wyróżniający się wygląd, więc ustawiłem kolor tekstu przycisków na kolor akcentu:
:where(
[type="submit"],
form button:not([type],[disabled])
) {
--_text: var(--_accent);
}

Dostosowywanie przycisków resetowania
Chciałem, aby przyciski resetowania miały wbudowane znaki ostrzegawcze, które informowałyby użytkowników o potencjalnie destrukcyjnym działaniu. Zdecydowałem się też na dodanie do przycisku jasnego motywu więcej czerwonych akcentów niż do ciemnego motywu. Dostosowywanie polega na zmianie odpowiedniego jasnego lub ciemnego koloru bazowego, a przycisk zaktualizuje styl:
: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%);
}
Pomyślałem też, że kolor obrysu fokusu powinien pasować do akcentu czerwieni. Kolor tekstu zmienia się z ciemnoczerwonego na jasnoczerwony. Kolor obrysu dopasowuję do słowa kluczowego:currentColor
:where([type="reset"]):focus-visible {
outline-color: currentColor;
}

Dostosowywanie wyłączonych przycisków
Często zdarza się, że wyłączone przyciski mają słaby kontrast kolorów, ponieważ próbuje się je przyciemnić, aby wyglądały na mniej aktywne. Sprawdziłem każdy zestaw kolorów i upewniłem się, że spełnia wymagania, zmieniając wartość jasności HSL, aż wynik w Narzędziach deweloperskich lub VisBug był prawidłowy.
: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);
}

Dostosowywanie przycisków wprowadzania plików
Przycisk wprowadzania pliku to kontener obejmujący element span i przycisk. CSS może nieco ostylować kontener wejściowy i zagnieżdżony przycisk, ale nie może ostylować elementu span. Kontener ma ustawioną wartość max-inline-size, dzięki czemu nie będzie większy niż to konieczne, a wartość inline-size: 100% pozwoli mu się zmniejszyć i dopasować do kontenerów mniejszych od niego. Kolor tła jest ustawiony na kolor adaptacyjny, który jest ciemniejszy niż inne powierzchnie, dzięki czemu wygląda jak tło przycisku wyboru pliku.
:where(input[type="file"]) {
inline-size: 100%;
max-inline-size: max-content;
background-color: var(--_input-well);
}
Przycisk wyboru pliku i przyciski typu wejścia mają przypisane style,appearance: none aby usunąć wszystkie style dostarczone przez przeglądarkę, które nie zostały zastąpione przez inne style przycisków.
:where(input[type="button"]),
:where(input[type="file"])::file-selector-button {
appearance: none;
}
Na koniec do elementu inline-end przycisku dodawany jest margines, aby odsunąć tekst elementu span od przycisku i utworzyć odstęp.
:where(input[type="file"])::file-selector-button {
margin-inline-end: var(--_padding-inline);
}

Wyjątki dotyczące specjalnego ciemnego motywu
Przyciski głównego działania mają ciemniejsze tło, co zapewnia większy kontrast tekstu i sprawia, że są bardziej widoczne.
@media (prefers-color-scheme: dark) {
:where(
[type="submit"],
[type="reset"],
[disabled],
form button:not([type="button"])
) {
--_bg: var(--_input-well);
}
}

Tworzenie wariantów
Dla zabawy i z praktycznego punktu widzenia postanowiłem pokazać, jak utworzyć kilka wariantów. Jeden z nich jest bardzo żywy, podobnie jak przyciski główne. Inny wariant to duży. Ostatni wariant ma ikonę wypełnioną gradientem.
Wyrazisty przycisk
Aby uzyskać ten styl przycisku, bezpośrednio zastąpiłem podstawowe właściwości niebieskimi kolorami. Chociaż jest to szybkie i łatwe, usuwa właściwości adaptacyjne i wygląda tak samo w motywie jasnym i ciemnym.
.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%);
}

Duży przycisk
Ten styl przycisku uzyskuje się przez zmodyfikowanie właściwości niestandardowej --_size.
Wypełnienie i inne elementy przestrzeni są określane względem tego rozmiaru i skalowane proporcjonalnie do nowego rozmiaru.
.btn-large {
--_size: 1.5rem;
}

Przycisk ikony
Ten efekt ikony nie ma nic wspólnego ze stylami przycisków, ale pokazuje, jak go uzyskać za pomocą zaledwie kilku właściwości CSS, oraz jak dobrze przycisk radzi sobie z ikonami, które nie są wbudowanymi plikami SVG.
[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));
}
![]()
Podsumowanie
Teraz, gdy wiesz, jak to zrobiłem, jak Ty byś to zrobił? 🙂
Urozmaićmy nasze podejście i poznajmy wszystkie sposoby tworzenia treści w internecie.
Utwórz demo, wyślij mi na Twitterze linki, a ja dodam je do sekcji remiksów społeczności poniżej.
Remiksy społeczności
Na razie jest tu pusto.
Zasoby
- Kod źródłowy na GitHubie