Tworzenie komponentu przycisku

Podstawowe omówienie tworzenia komponentów <button> dostosowanych do kolorów, elastycznych i dostępnych.

W tym poście chcę podzielić się swoimi przemyśleniami na temat tworzenia elementu <button>, który dostosowuje się do kolorów, jest responsywny i dostępny. Wypróbuj wersję demonstracyjnąwyświetl kod źródłowy

W jasnym i ciemnym motywie przyciski można obsługiwać za pomocą klawiatury i myszy.

Jeśli wolisz film, oto wersja tego posta w YouTube:

Omówienie

Browser Support

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

Source

Element <button> jest przeznaczony do interakcji z użytkownikiem. click zdarzenia aktywowane przez klawiaturę, mysz, dotyk, głos i inne, z inteligentnymi regułami dotyczącymi ich czasu. Zawiera też kilka domyślnych stylów w każdej przeglądarce, dzięki czemu możesz ich używać bezpośrednio bez konieczności wprowadzania zmian. Użyj color-scheme, aby włączyć też jasne i ciemne przyciski udostępniane przez przeglądarkę.

Istnieją też różne typy przycisków, z których każdy jest pokazany w poprzednim embedzie Codepen. Element <button> bez typu zostanie dostosowany do elementu <form>, zmieniając się na typ przesyłania.

<!-- 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 wyzwania dotyczącego interfejsu użytkownika każdy przycisk otrzyma style, które wizualnie odróżnią jego przeznaczenie. Przyciski resetowania będą miały kolory ostrzegawcze, ponieważ ich użycie powoduje trwałe zmiany, a przyciski przesyłania będą miały tekst w niebieskim kolorze, aby wyróżniały się na tle zwykłych przycisków.

Podgląd ostatecznego zestawu wszystkich typów przycisków, pokazany w formularzu i poza nim, z dodatkami dla przycisków z ikonami i przycisków niestandardowych.
Podgląd ostatecznego zestawu wszystkich typów przycisków, wyświetlanych w formularzu i poza nim, z dodatkami dla przycisków z ikonami i przycisków niestandardowych

Przyciski mają też pseudoklasy, które służą do stylizacji za pomocą CSS. Te klasy zapewniają elementy obsługi CSS do dostosowywania wyglądu przycisku: :hover – gdy kursor myszy znajduje się nad przyciskiem, :active – gdy mysz lub klawiatura są naciśnięte, :focus lub :focus-visible – aby pomóc w stylowaniu technologii wspomagających.

button:hover {}
button:active {}
button:focus {}
button:focus-visible {}
Podgląd ostatecznego zestawu wszystkich typów przycisków w ciemnym motywie
Podgląd ostatecznego zestawu wszystkich typów przycisków w ciemnym motywie

Znacznik

Oprócz typów przycisków podanych 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, w celu przetestowania, każdy przycisk jest umieszczany w formularzu. Dzięki temu mogę mieć pewność, że style są odpowiednio aktualizowane w przypadku domyślnego przycisku, który działa jak przycisk przesyłania. Zmieniam też strategię dotyczącą ikony, z wstawionego pliku SVG na zamaskowany plik SVG, aby upewnić się, że oba rozwiązania działają 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>

W tej chwili matryca kombinacji jest przytłaczająca. Biorąc pod uwagę typy przycisków, pseudoklasy i to, czy przycisk znajduje się w formularzu czy poza nim, istnieje ponad 20 kombinacji przycisków. Dobrze, że usługa porównywania cen może nam pomóc w jasnym przedstawieniu każdego z nich.

Ułatwienia dostępu

Elementy typu button są oczywiście dostępne, ale istnieje kilka typowych ulepszeń.

Przesuwanie i skupienie uwagi

Lubię grupować elementy :hover:focus za pomocą pseudoselektora funkcjonalnego :is(). Dzięki temu moje interfejsy zawsze uwzględniają klawiaturę i style technologii wspomagających.

button:is(:hover, :focus) {
  
}
Wypróbuj prezentację.

Interaktywny pierścień ostrości

Chcę animować pierścień fokusa dla użytkowników klawiatury i technologii wspomagających. Osiągam to, animując obrys w odległości 5 pikseli od przycisku, ale tylko wtedy, gdy przycisk jest nieaktywny. Spowoduje to efekt, w którym pierścień fokusa skurczy się do rozmiaru przycisku po jego naciśnięciu.

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

Zapewnienie odpowiedniego kontrastu kolorów

W przypadku ciemnych i jasnych kolorów są co najmniej 4 różne kombinacje kolorów, które wymagają uwzględnienia kontrastu kolorów: przycisk, przycisk przesyłania, przycisk resetowania i przycisk wyłączony. Używamy tutaj narzędzia VisBug do sprawdzania i wyświetlania wszystkich wyników naraz:

Ukrywanie ikon przed osobami, które ich nie widzą

Podczas tworzenia ikony przycisku należy pamiętać, że powinna ona wizualnie wspierać tekst przycisku. Oznacza to również, że ikona nie jest przydatna dla osób z utratą wzroku. Na szczęście przeglądarka umożliwia ukrywanie elementów przed czytnikami ekranu, aby osoby z problemami ze wzrokiem nie były rozpraszane przez ozdobne przyciski.

<button>
  <svg … aria-hidden="true">...</svg>
  Icon Button
</button>
Narzędzia deweloperskie Chrome wyświetlające drzewo ułatwień dostępu dla przycisku. Drzewo ignoruje obraz przycisku, ponieważ ma atrybut aria-hidden ustawiony na wartość true.
Narzędzia deweloperskie w Chrome wyświetlają drzewo ułatwień dostępu dla przycisku. Drzewo ignoruje obraz przycisku, ponieważ ma atrybut aria-hidden ustawiony na wartość true.

Style

W następnej sekcji najpierw ustanowię system niestandardowych właściwości do zarządzania adaptacyjnymi stylami przycisku. Dzięki tym właściwościom niestandardowym mogę zacząć wybierać elementy i dostosowywać ich wygląd.

strategia z niestandardową właściwością dostosowaną do potrzeb

Strategia niestandardowej usługi używana w tym wyzwaniu GUI jest bardzo podobna do tej, która jest wykorzystywana w tworzeniu schematu kolorów. W przypadku systemu kolorów dostosowujących się do jasności i ciemności dla każdego motywu definiowana i odpowiednio nazywana jest odpowiednia właściwość niestandardowa. Następnie do przechowywania bieżącej wartości motywu używana jest jedna właściwość niestandardowa, która jest przypisywana do właściwości CSS. Później można zmienić wartość tej właściwości niestandardowej na inną, 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 jasny i ciemny motyw są deklaratywne i przejrzyste. Przekierowanie i abstrahowanie są przenoszone do właściwości niestandardowej --_bg, która jest teraz jedyną „reaktywnie” działającą właściwością. --_bg-light--_bg-dark są statyczne. Widać też wyraźnie, że jasny motyw jest domyślnym motywem, a ciemny jest stosowany tylko warunkowo.

Przygotowanie się do zapewnienia spójności projektu

Selektor udostępniony

Ten selektor służy do kierowania na różne typy przycisków i może być na początku przytłaczający. Używany jest parametr :where(), więc dostosowywanie przycisku nie wymaga żadnych szczególnych działań. Przyciski są często dostosowane do alternatywnych scenariuszy, a selektor :where() ułatwia to zadanie. W sekcji :where() wybrano wszystkie typy przycisków, w tym ::file-selector-button, którego nie można używać w sekcji :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ą ograniczone do tego selektora. Czas przejrzeć wszystkie usługi niestandardowe. W tym przycisku jest używanych sporo właściwości niestandardowych. Po kolei opiszę każdą grupę, a na koniec tej sekcji podam konteksty ciemnego i ograniczonego ruchu.

Kolor akcentu przycisku

Przyciski przesyłania i ikony to świetne miejsce na dodanie koloru:

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

Kolor tekstu przycisku

Kolory tekstu przycisków nie są białe ani czarne, lecz przyciemnione lub rozjaśnione wersje koloru --_accent (hsl()) w oparciu o odcienie 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ą w tym samym stylu hsl(), z wyjątkiem przycisków w ciemnym motywie, które są białe, dzięki czemu wyglądają jakby były blisko 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 wyświetlania powierzchni za innymi powierzchniami. Jest przydatny w przypadku tła dla danych wejściowych pliku:

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

Odstęp przycisku

Odstępy wokół tekstu na przycisku są tworzone za pomocą jednostki ch, która jest długością względną do rozmiaru czcionki. Jest to szczególnie ważne, gdy duże przyciski mogą po prostu zwiększać rozmiar font-size i proporcjonalnie skalować przyciski:

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

Obramowanie przycisku

Promień obramowania przycisku jest przechowywany w własnej właściwości, aby dane wejściowe pliku pasowały do innych przycisków. Kolory obramowania są zgodne z ustanowionym systemem kolorów dostosowanych do potrzeb:

--_border-radius: .5ch;

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

Efekt podświetlenia przycisku

Te właściwości określają rozmiar, który zmienia się w reakcji na interakcję, a kolor wyróżnienia jest zgodny z systemem kolorów adaptacyjnych. W dalszej części tego artykułu opiszemy, jak te elementy współdziałają ze sobą, ale na koniec warto wspomnieć, że służą one do 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 cień tekstu. Dzięki temu tekst będzie znajdować się na przycisku, co poprawi jego czytelność i doda przyjemny element prezentacji.

--_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 względnej długości ch, która pomoże skalować ikonę proporcjonalnie do tekstu przycisku. Kolor ikony jest oparty na kolorze --_accent-color, aby zapewnić kolorystykę dostosowaną do motywu.

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

Cień przycisku

Aby cienie prawidłowo dostosowywały się do światła i ciemności, muszą zmieniać zarówno kolor, jak i przezroczystość. Cienie w motywie jasnym najlepiej wyglądają, gdy są subtelne i przyciemnione do koloru powierzchni, na którą nakładają się. Cienie w ciemnym motywie muszą być ciemniejsze i bardziej nasycone, aby mogły nakładać się 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 dostosowywaniu kolorów i intensywności mogę stworzyć 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%));

Aby nadać przyciskom nieco trójwymiarowego wyglądu, zastosowaliśmy cień wewnętrzny 1px, który tworzy złudzenie:

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

Przejścia między przyciskami

Zgodnie ze wzorcem kolorów dostosowujących tworzymy 2 właściwości statyczne, 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

Wszystkie właściwości niestandardowe 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); }

Domyślne przyciski są wyświetlane obok siebie w jasnym i ciemnym motywie.

dostosowywanie ciemnego motywu,

Wartość wzorca statycznych rekwizytów -light-dark staje się jasna, gdy ustawisz rekwizyty 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);
  }
}

Jest to nie tylko czytelne, ale też użytkownicy tych niestandardowych przycisków mogą używać pustych elementów z pewną świadomością, że będą one odpowiednio dopasowane do preferencji użytkowników.

Adaptacje z obniżonym ruchem

Jeśli ruch jest dozwolony dla tego użytkownika, 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 wspólnych stylów

Fonty przycisków i pola tekstowego muszą być ustawione na inherit, aby pasowały do reszty czcionek na stronie. W przeciwnym razie styl będzie ustawiany przez przeglądarkę. Dotyczy to również letter-spacing. Ustawienie wartości line-height na 1.5 powoduje, że pole na litery ma odpowiedni rozmiar, aby zapewnić tekstowi odpowiednią ilość miejsca u góry i u dołu:

: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);
}

Zrzut ekranu pokazujący przyciski po zastosowaniu poprzednich stylów.

Stylizacja przycisków

Regulacja selektora

Selektor input[type="file"] nie jest częścią przycisku w danych wejściowych, ale pseudoelement ::file-selector-button, więc 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 {
  
}

Ustawienia kursora i dotyku

Najpierw stylizuję kursor w stylu pointer, aby pokazać użytkownikom, że przycisk jest interaktywny. Następnie dodaję touch-action: manipulation, aby kliknięcia nie wymagały oczekiwania i obserwowania potencjalnego podwójnego kliknięcia, co sprawia, że przyciski wydają się szybsze:

: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 ramki

Następnie dostosowuję rozmiar czcionki, kolory tła, tekstu i ramki, korzystając z niektórych z ustawień niestandardowych dostosowania:

: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);
}

Zrzut ekranu pokazujący przyciski po zastosowaniu poprzednich stylów.

Cienie

Przyciski zostały wykonane za pomocą świetnych technik. text-shadow dostosowuje się do jasnych i ciemnych kolorów, dzięki czemu tekst przycisku prezentuje się przyjemnie na tle. W przypadku box-shadow przypisane są 3 cienie. Pierwszy, --_shadow-2, to zwykły cień ramki. Drugi cień to sztuczka optyczna, która sprawia, że przycisk wygląda na lekko zaokrąglony. Ostatni cień jest przeznaczony do podświetlenia podczas najechania kursorem. Początkowo ma rozmiar 0, ale później zostanie mu nadany rozmiar i przejdzie w stan przejściowy, w którym będzie wyglądał tak, jakby wyrastał 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);
}

Zrzut ekranu pokazujący przyciski po zastosowaniu poprzednich stylów.

Układ

Przycisk ma układ flexbox, a w szczególności układ inline-flex, który pasuje do jego zawartości. Następnie wyśrodkowuję tekst, a elementy podrzędne wyrównuję w pionie i w poziomie do środka. Pomoże to w prawidłowym wyrównaniu ikon i innych elementów przycisku.

: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;
}

Zrzut ekranu pokazujący przyciski po zastosowaniu poprzednich stylów.

Odstępy

W przypadku odstępów między przyciskami użyłem atrybutu gap, aby elementy pokrewne nie stykały się ze sobą, oraz atrybutów logicalznych, aby odstępy między przyciskami działały 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);
}

Zrzut ekranu pokazujący przyciski po zastosowaniu poprzednich stylów.

UX dotykowy i myszy

Ta sekcja jest przeznaczona głównie dla użytkowników urządzeń dotykowych. 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 użytkownik naciska i przytrzymuje przycisk, a system operacyjny wyróżnia tekst przycisku.

Ogólnie uważam, że nie jest to wygodne dla użytkowników, więc wyłączam to ustawienie, ustawiając user-select na „brak”. Kolory podświetlenia (-webkit-tap-highlight-color) i menu kontekstowe systemu operacyjnego (-webkit-touch-callout) to inne funkcje przycisków bardzo skoncentrowane na Internecie, które nie są zgodne z ogólnymi oczekiwaniami użytkowników przycisków, dlatego 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

Parametr --_transition jest przypisany 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);
}

Gdy użytkownik najedzie kursorem na przycisk, ale nie naciśnie go, dostosuj rozmiar cienia podświetlenia, aby nadać mu ładny wygląd. Powinno ono rosnąć od środka przycisku:

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

Po zaznaczeniu zwiększ odstęp obrysu od przycisku, a także nadaj mu wygląd, który wydaje się rozszerzać od środka przycisku:

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

Ikony

Aby obsługiwać ikony, selektor ma dodany selektor :where() dla bezpośrednich elementów potomnych SVG lub elementów z atrybutem niestandardowym data-icon. Rozmiar ikony jest ustawiany za pomocą właściwości niestandardowej za pomocą właściwości logicznych wstawianych i blokowych. Ustawiono kolor obrysu, a także kolor drop-shadow, aby pasował do koloru text-shadow. Aplikacja flex-shrink jest ustawiona na 0, więc ikona nigdy nie jest skompresowana. Na koniec wybieram ikony z liniami i przypisuję im te style za pomocą fill: noneround:

: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;
}

Zrzut ekranu pokazujący przyciski po zastosowaniu poprzednich stylów.

Dostosowywanie przycisków przesyłania

Chciałem, aby przyciski przesyłania miały nieco wyróżniający wygląd. Osiągnąłem to, zmieniając kolor tekstu przycisków na kolor akcentu:

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

Zrzut ekranu pokazujący przyciski po zastosowaniu poprzednich stylów.

Dostosowywanie przycisków resetowania

Chciałem, aby przyciski resetowania zawierały wbudowane ostrzeżenia, które ostrzegałyby użytkowników przed potencjalnie szkodliwymi działaniami. W przypadku jasnego motywu przycisk ma też więcej czerwonych akcentów niż w ciemnym. Dostosowywanie polega na zmianie odpowiedniego jasnego lub ciemnego koloru podstawowego, 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%);
}

Myślę też, że kolor obrysu okna fokusu powinien pasować do czerwonego akcentu. Kolor tekstu zmienia się z ciemnego na czerwony na jasny czerwony. Kolor obrysu dopasowuję do słowa kluczowego currentColor:

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

Zrzut ekranu pokazujący przyciski po zastosowaniu poprzednich stylów.

Dostosowywanie wyłączonych przycisków

Często zdarza się, że przyciski wyłączone mają zły kontrast kolorów, ponieważ próbujemy je przyciemnić, aby wydawały się mniej aktywne. Testowałem każdy zestaw kolorów i upewniłem się, że spełniają wymagania. Zmieniałem wartość jasności w HSL, aż uzyskałem wynik akceptowalny w DevTools lub VisBug.

: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);
}

Zrzut ekranu pokazujący przyciski po zastosowaniu poprzednich stylów.

Dostosowywanie przycisków wprowadzania plików

Przycisk wyboru pliku to kontener dla elementu span i przycisku. CSS może nieco sformatować kontener pola wejściowego oraz wbudowany przycisk, ale nie element span. Kontenery mają wartość max-inline-size, dzięki czemu nie będą większe niż to konieczne, a wartość inline-size: 100% pozwoli im się zmniejszyć i pasować do kontenerów mniejszych niż one. Kolor tła jest ustawiony na kolor adaptacyjny, który jest ciemniejszy niż inne powierzchnie, dzięki czemu jest widoczny za przyciskiem selektora plików.

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

Przycisk selektora plików i przyciski typu danych są przeznaczone specjalnie do usuwania wszelkich stylów dostarczanych przez przeglądarkę, które nie zostały zastąpione przez inne style przycisków.appearance: none

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

Na koniec dodaję margines do inline-end przycisku, aby przesunąć tekst elementu span od przycisku, tworząc w ten sposób odstęp.

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

Zrzut ekranu pokazujący przyciski po zastosowaniu poprzednich stylów.

Wyjątki dotyczące ciemnego motywu

Przyciski głównych działań mają ciemniejsze tło, aby tekst był bardziej kontrastowy, co nadaje im nieco bardziej promowany wygląd.

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

Zrzut ekranu pokazujący przyciski po zastosowaniu poprzednich stylów.

Tworzenie wariantów

Dla zabawy i z powodu praktyczności pokażę, jak utworzyć kilka wariantów. Jeden z wariantów jest bardzo żywy, podobny do przycisków głównych. Innym wariantem jest duży. Ostatni wariant ma ikonę z gradientem.

Intensywny przycisk

Aby uzyskać ten styl przycisku, zastąpiłam podstawowe elementy kolorem niebieskim. Chociaż było to szybkie i łatwe, powoduje usunięcie elementów dostosowanych do urządzenia 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%);
}

Przycisk niestandardowy jest wyświetlany w wersji jasnej i ciemnej. Jest bardzo intensywnie niebieski, jak typowe przyciski działań podstawowych.

Duży przycisk

Ten styl przycisku uzyskuje się przez modyfikację właściwości niestandardowej --_size. Odstępy i inne elementy przestrzeni są względne do tego rozmiaru i zmieniają się proporcjonalnie do nowego rozmiaru.

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

Obok przycisku niestandardowego wyświetla się duży przycisk, który jest około 150 razy większy.

Ikona

Ten efekt ikony nie ma nic wspólnego z naszymi stylami przycisków, ale pokazuje, jak osiągnąć ten efekt za pomocą zaledwie kilku właściwości CSS oraz jak dobrze przycisk radzi sobie z ikonami, które nie są wbudowane w formatie 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));
}

Przycisk z ikoną wyświetlany w jasnym i ciemnym motywie.

Podsumowanie

Teraz, gdy już wiesz, jak to zrobić, jak Ty to zrobisz? 🙂

Zróżnicujemy nasze podejścia i poznamy wszystkie sposoby tworzenia stron internetowych.

Utwórz wersję demonstracyjną, wyślij mi linki, a ja dodam je do sekcji z remiksami społeczności.

Remiksy społeczności

Na razie jest tu pusto.

Zasoby