Tworzenie komponentu przycisku

Podstawowe informacje o tym, jak tworzyć elastyczne i łatwo dostępne komponenty <button> o różnych kolorach.

W tym poście chcę podzielić się przemyśleniami na temat tworzenia modułu <button> o różnej dostępności, elastycznych i łatwych w obsłudze. Wypróbuj wersję demonstracyjną i wyświetl źródło

W trybie jasnym i ciemnym przycisków możesz sterować za pomocą klawiatury i myszy.

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

Przegląd

Obsługa przeglądarek

  • 1
  • 12
  • 1
  • ≤4

Źródło

Element <button> został opracowany z myślą o interakcji użytkownika. Zdarzenia click uruchamiają się za pomocą klawiatury, myszy, dotyku, głosu i innych funkcji, a także za pomocą inteligentnych reguł dotyczących czasu. W każdej przeglądarce są też dostępne style domyślne, które można używać bezpośrednio bez konieczności dostosowywania. Użyj color-scheme, aby włączyć też jasne i ciemne przyciski dostarczane przez przeglądarkę.

Są też różne rodzaje przycisków, z których każdy omówiliśmy w poprzedniej sekcji Kodpen umieszczonej na stronie. Element <button> bez typu dostosuje się do typu <form> i zmieni 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 GUI każdy przycisk otrzyma style, które pomogą wizualnie wyróżnić ich zamiar. Przyciski resetowania będą miały kolory ostrzeżeń, ponieważ są szkodliwe, a przyciski przesyłania zostaną oznaczone niebieskim akcentem, więc będą się nieco bardziej wyróżniać niż zwykłe przyciski.

Podgląd ostatecznego zestawu wszystkich typów przycisków, wyświetlany w formularzu, a nie w formularzu, z ładnymi dodatkami do ikon i przycisków.
Podgląd ostatecznego zestawu wszystkich typów przycisków, wyświetlany w formie, a nie w formie, z ładnymi dodatkami do przycisków i ikon i przycisków niestandardowych

Przyciski mają też pseudoklasy, których CSS może używać do określania stylu. Te klasy pozwalają na dostosowywanie sposobu działania przycisku CSS: :hover (gdy mysz jest po naciśnięciu przycisku), :active (gdy naciskasz mysz lub klawiaturę) oraz :focus lub :focus-visible (pomoc w określaniu stylu technologii wspomagającej osoby z niepełnosprawnością).

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

Markup

Oprócz typów przycisków wskazanych w specyfikacji HTML dodaliśmy przycisk z ikoną i przyciskiem z niestandardową klasą 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 testów, umieszczasz każdy przycisk w formularzu. Dzięki temu mogę zapewnić odpowiednią aktualizację stylów przycisku domyślnego, który działa jak przycisk przesyłania. Zmieniam też strategię dotyczącą ikon z wbudowanego SVG na obraz SVG z maskowaniem, aby mieć pewność, że obie działają tak samo 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>

Zestaw kombinacji jest obecnie przytłaczający. Do wyboru jest ponad 20 kombinacji przycisków, między typami przycisków, pseudoklasami, wchodzącymi do formularza lub poza nim. Warto skorzystać z CSS, aby jasno przedstawić każdy z nich.

Ułatwienia dostępu

Elementy przycisku są dostępne w naturalny sposób, ale istnieją pewne ulepszenia.

Najeżdżaj kursorem i ustawiaj ostrość

Chcę grupować :hover i :focus za pomocą funkcjonalnego pseudoselektora :is(). Dzięki temu moje interfejsy zawsze uwzględniają styl klawiatury i technologii wspomagającej osoby z niepełnosprawnością.

button:is(:hover, :focus) {
  …
}
Zobacz prezentację.

Interaktywny pierścień ostrości

Lubię animować pierścień ostrości dla użytkowników klawiatury i technologii wspomagających osoby z niepełnosprawnością. Realizuję to, animując kontur od przycisku o 5 pikseli, ale tylko wtedy, gdy przycisk jest nieaktywny. Spowoduje to utworzenie efektu, który po naciśnięciu pierścień ostrości zmniejsza się do rozmiaru przycisku.

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

Zapewnianie kontrastu kolorów

Istnieją co najmniej 4 kombinacje kolorów jasnego i ciemnego, które wymagają uwzględnienia kontrastu kolorów: przycisk, przycisk przesyłania, przycisk resetowania i przycisk wyłączony. VisBug służy do badania i wyświetlania wszystkich wyników jednocześnie:

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

Tworząc przycisk ikony, powinna ona stanowić wizualną pomoc związaną z tekstem przycisku. Oznacza to też, że ikona nie jest wartościowa dla osób z wadą wzroku. Na szczęście przeglądarka umożliwia ukrycie elementów przed czytnikami ekranu, dzięki czemu osoby niedowidzące nie muszą zawracać sobie głowy ozdobnymi obrazami przycisków:

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

Style

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

Adaptacyjna strategia właściwości niestandardowych

Strategia dotycząca właściwości niestandardowych wykorzystywana w tym Wyzwaniu GUI jest bardzo podobna do tej użytej przy tworzeniu schematu kolorów. W przypadku adaptacyjnego systemu kolorów jasnego i ciemnego dla każdego motywu jest zdefiniowana i odpowiednia nazwa. 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 tę samą właściwość niestandardową można zaktualizować do innej wartości, a potem zmienić 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ę to, że motywy jasne i ciemne są jednoznaczne i wyraźne. Właściwości pośrednie i abstrakcja są przejmowane do właściwości niestandardowej --_bg, która jest obecnie jedyną właściwością reaktywną; --_bg-light i --_bg-dark są statyczne. Widać też, że motywem domyślnym jest jasny motyw, a ciemny jest stosowany tylko warunkowo.

Przygotowanie do zachowania spójności projektu

Udostępniony selektor

Poniższy selektor służy do kierowania wszystkich rodzajów przycisków i na początku może być przytłaczający. Używamy :where(), więc dostosowanie przycisku nie wymaga precyzyjnego działania. Przyciski są często przystosowane do alternatywnych scenariuszy, a selektor :where() ułatwia zadanie. W obrębie :where() wybierany jest każdy typ przycisku, w tym ::file-selector-button, którego nie można używać w tagach :is() i :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ą uwzględnione w tym selektorze. Czas przyjrzeć się wszystkich właściwościom niestandardowym. Ten przycisk ma sporo właściwości niestandardowych. Opiszę każdą grupę w dalszej części, a na końcu przedstawię kontekst ciemnego i zmniejszonego ruchu.

Kolor uzupełniający przycisku

Ikony i przyciski przesyłania to doskonałe miejsce na odrobinę 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. Są to ciemne lub rozjaśnione wersje elementu --_accent za pomocą hsl() i zachowane zgodnie z barwem 210:

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

Kolor tła przycisku

Tło przycisków ma ten sam wzór hsl(), ale z wyjątkiem przycisków jasnego motywu. Są one ustawione na białe, więc powierzchnia przycisków sprawia, że są widoczne blisko użytkownika lub innych powierzchni:

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

Tło przycisku

Ten kolor tła umożliwia wyświetlanie powierzchni za innymi powierzchniami i jest przydatny jako tło danych wejściowych 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 na przycisku są wprowadzane za pomocą jednostki ch, której długość jest względna w stosunku do rozmiaru czcionki. Ma to kluczowe znaczenie, gdy duże przyciski mogą po prostu zwiększyć font-size, a przyciski skalują się proporcjonalnie:

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

Obramowanie przycisku

Promień obramowania przycisku jest umieszczony w 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 przycisku po najechaniu kursorem

Określają one właściwość rozmiaru, która powoduje przejście po interakcji, a kolor zaznaczenia jest zgodny z systemem kolorów adaptacyjnych. Interakcje te omówimy w dalszej części tego postu, ale ostatecznie zostaną one wykorzystane 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. Pomaga to umieścić tekst na przycisku, poprawia jego czytelność i nadaje estetyczny wygląd.

--_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ą długość 2 znaków, dzięki czemu jest ona ponownie zależna od długości ch. Dzięki temu ikony będą skalowane proporcjonalnie do tekstu przycisku. Kolor ikony opiera się na --_accent-color, aby określić kolor adaptacyjny i w ramach motywu.

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

Cień przycisku

Aby cienie prawidłowo przystosowały się do światła i ciemności, muszą odpowiednio zmienić kolor i przezroczystość. Cienie z jasnym motywem są najlepsze, gdy są subtelne i przyciemne względem koloru powierzchni, na które się nakłada. Cienie ciemnego motywu muszą być ciemniejsze i bardziej nasycone, aby mogły nakładać się 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);

Stosując elastyczne kolory i siłę cieni, mogę połączyć 2 głębiny 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 nadać przyciskom trochę trójwymiarowego wyglądu, użyj cienia ramki 1px, aby stworzyć 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 przycisków

Zgodnie ze wzorcem kolorów adaptacyjnych tworzę dwie właściwości statyczne do przechowywania opcji systemu projektowania:

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

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

Przyciski domyślne wyświetlają się obok siebie w kolorze jasnym i ciemnym.

Adaptacje ciemnego motywu

Wartość wzorca statycznych rekwizytów -light i -dark staje się jasna po ustawieniu ciemnych rekwizytów:

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

Przyciski te nie tylko dobrze się czytają, ale użytkownicy mogą też bez obaw korzystać z tych rekwizytów, które dopasują się do preferencji użytkownika.

Ograniczone adaptacje ruchu

Jeśli ruch jest prawidłowy dla tego użytkownika, przypisz --_transition do użytkownika 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

Czcionki przycisków i elementów wejściowych muszą być ustawione na inherit, aby pasowały do pozostałych czcionek na stronie. W przeciwnym razie styl zostanie dostosowany przez przeglądarkę. Dotyczy to też zasady letter-spacing. Ustawienie line-height na 1.5 powoduje ustawienie rozmiaru pola literowego, tak aby tekst był widoczny nad i poniżej:

: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 przedstawiający przyciski po zastosowaniu poprzednich stylów.

Przyciski stylu

Dostosowanie selektora

Selektor input[type="file"] nie jest przyciskiem danych wejściowych, a pseudoelementem ::file-selector-button, więc usunąłem z listy element input[type="file"]:

:where(
  button,
  input[type="button"],
  input[type="submit"],
  input[type="reset"],
  input[type="file"]
),
:where(input[type="file"])::file-selector-button {
  
}

Dostosowania kursora i dotyku

Najpierw ustawiam kursor na stylu pointer, dzięki czemu przycisk jest interaktywny. Następnie dodaję touch-action: manipulation, aby kliknięcia nie musiały czekać i rejestrowały potencjalne dwukrotne kliknięcia. Dzięki temu 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 ramki

Następnie dostosowuję rozmiar czcionki, tło, tekst i kolory obramowania, używając pewnych typowych właściwości niestandardowych adaptacyjnych:

: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 przedstawiający przyciski po zastosowaniu poprzednich stylów.

Cienie

W przypadku przycisków zastosowano świetne techniki. text-shadow dostosowuje się do jasnego i ciemnego tła, tworząc przyjemny, subtelny wygląd tekstu przycisku. W przypadku instancji box-shadow przypisane są 3 cienie. Pierwszy z nich to zwykły cień ramki, czyli --_shadow-2. Drugi cień to sztuczka, która powoduje, że przycisk wydaje się nieco ścięty. Ostatni cień jest przeznaczony dla wyróżnienia po najechaniu kursorem. Początkowo ma wartość 0, ale później zostanie określony i zmieniony, tak aby był widoczny po kliknięciu.

: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 przedstawiający przyciski po zastosowaniu poprzednich stylów.

Układ

Przycisk ma układ flexbox, a konkretnie inline-flex, który pasuje do jego treści. Wyśrodkowuję tekst, a potem wyrównuję go w pionie i poziomie do środka. Dzięki temu ikony i inne elementy przycisków będą się prawidłowo wyrównać.

: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 przedstawiający przyciski po zastosowaniu poprzednich stylów.

Odstępy

Jako odstępów w przyciskach użyłem gap, by rodzeństwo nie miało dotykania i właściwości logicznych dopełnienia. Dzięki temu odstępy między przyciskami będą działać we wszystkich układach 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 przedstawiający przyciski po zastosowaniu poprzednich stylów.

Dotyk i mysz

Ta sekcja jest przeznaczona głównie dla użytkowników urządzeń mobilnych korzystających z dotyku. Pierwsza właściwość, user-select, jest przeznaczona dla wszystkich użytkowników i zapobiega wyróżnianiu tekstu przycisku. Jest to zwykle widoczne na urządzeniach dotykowych, gdy użytkownik naciśnie i przytrzyma przycisk, a system operacyjny wyróżni jego tekst.

Ogólnie rzecz biorąc, nie dzieje się tak w przypadku przycisków we wbudowanych aplikacjach, dlatego wyłączam tę funkcję, ustawiając dla zasady user-select brak wartości. Kliknij kolory wyróżnienia (-webkit-tap-highlight-color) i menu kontekstowe systemu operacyjnego (-webkit-touch-callout) to inne funkcje przycisków, które nie spełniają ogólnych oczekiwań użytkownikó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.

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

Gdy użytkownik nie będzie naciskać przycisku po najechaniu kursorem, dostosuj rozmiar podświetlenia cienia, aby uzyskać ładny efekt ostrości, który wygląda, jakby rozwijał się po kliknięciu przycisku:

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

Po zaznaczeniu zwiększaj odsunięcie konturu zaznaczenia od przycisku, aby nadać mu ładny wygląd, jakby rozwijał się po jego kliknięciu:

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

Ikony

Do obsługi ikon selektor ma dodany selektor :where() na potrzeby 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 za pomocą właściwości logicznych wbudowanych i bloków. Ustawiony jest kolor kreski, a także drop-shadow, który odpowiada kolorowi text-shadow. flex-shrink ma wartość 0, więc ikona nigdy nie jest ściskana. Na koniec wybieram ikony z liniami i przydzielam te style do tych stylów z zakończeniami wierszy fill: none i round oraz ich połączeniami:

: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 przedstawiający przyciski po zastosowaniu poprzednich stylów.

Dostosowywanie przycisków przesyłania

Chciałam, żeby przyciski były trochę promowane, i byłam to, zmieniając kolor tekstu przycisków na kolor uzupełniający:

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

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

Dostosuj przyciski resetowania

Chciałam, żeby przyciski resetowania miały wbudowane znaki ostrzegawcze, które ostrzegały użytkowników o potencjalnie szkodliwym zachowaniu. Zdecydowałem się też na dodanie do przycisku jasnego motywu bardziej czerwonych akcentów niż ciemny motyw. Dostosowanie 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 dobrze byłoby też dopasować kolor konturu ostrości do akcentu czerwonego. Kolor tekstu zmienia kolor z ciemnoczerwonych na jasnoczerwony. Kolor konturu odpowiada temu słowu kluczowemu currentColor:

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

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

Dostosuj wyłączone przyciski

Często jest zbyt często, aby wyłączone przyciski miały niski kontrast kolorów podczas próby stłumienia nieaktywnego przycisku, przez co wydaje się on mniej aktywny. Przetestowałam każdy zestaw kolorów i upewniłam się, że jest zaliczona, przesuwając wartość jasności HSL do momentu, w którym wynik został przekazany w Narzędziach deweloperskich 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 przedstawiający przyciski po zastosowaniu poprzednich stylów.

Dostosowywanie przycisków wprowadzania danych

Przycisk wprowadzania pliku to kontener na span i przycisk. CSS może nieco zmienić styl kontenera wejściowego, a także zagnieżdżony przycisk, ale nie zakres. Kontener otrzymuje max-inline-size, dzięki czemu nie jest większy, niż jest wymagany. inline-size: 100% pozwala natomiast na zmniejszanie i dopasowanie kontenerów do mniejszych kontenerów. Kolor tła jest ustawiany na kolor adaptacyjny, który jest ciemniejszy od innych powierzchni, przez co jest widoczny za przyciskiem wyboru plików.

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

Przycisk wyboru pliku i przyciski typu danych są specjalnie podane appearance: none, aby usuwać style dostarczane przez przeglądarkę, które nie zostały zastąpione innymi stylami przycisku.

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

Na koniec do inline-end przycisku dodawany jest margines, aby odsunąć tekst rozpiętości od przycisku, co pozwoli utworzyć trochę odstępu.

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

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

Wyjątki dla specjalnego ciemnego motywu

Dodałam ciemniejsze tło głównych przycisków polecenia, aby tekst o wyższym kontraście był trochę bardziej promowany.

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

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

Tworzę warianty

Dla zabawy, a także w praktyce, pokażę, jak utworzyć kilka wariantów. Jedna z nich jest bardzo kolorowa, podobnie jak często wyglądają przyciski główne. Inny wariant jest duży. Ostatni wariant ma ikonę wypełnioną gradientem.

Tętniący życiem przycisk

Aby osiągnąć ten styl, zastąpiłam podstawowe rekwizyty kolorami niebieskimi. To proste i szybkie rozwiązanie, ale usuwa adaptacyjne rekwizyty i wygląda tak samo zarówno w przypadku jasnych, jak i ciemnych motywów.

.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 jasnym i ciemnym kolorze. Jest bardzo jaskrawoniebieski, jak to zazwyczaj bywa.

Duży przycisk

Ten styl przycisku uzyskuje się przez zmianę właściwości niestandardowej --_size. Dopełnienie i inne elementy odstępu są zależne od tego rozmiaru i skalują się proporcjonalnie do nowego rozmiaru.

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

Obok przycisku niestandardowego wyświetla się duży przycisk (ok. 150 razy większy).

Przycisk ikony

Efekt ikony nie ma nic wspólnego ze stylami przycisków, ale pokazuje, jak to zrobić za pomocą kilku właściwości CSS, oraz pokazuje, jak dobrze przycisk obsługuje ikony niewbudowane w 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ą jest wyświetlany w ciemnych i jasnych motywach.

Podsumowanie

Wiesz już, jak to zrobiłem, więc jak to zrobisz 🙂

Stwórzmy różne metody i nauczmy się wszystkiego, jak rozwijać się w internecie.

Utwórz demonstrację i udostępnię mi linki na Twitterze, a dodam ją do sekcji remiksów w ramach społeczności poniżej.

Remiksy społeczności

Na razie niczego tu nie ma.

Zasoby