Tworzenie komponentu pływającego przycisku polecenia (FAB)

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

W tym poście chcę podzielić się przemyśleniami na temat tworzenia elastycznych i dostępnych komponentów typu FAB. Wypróbuj wersję demonstracyjną i wyświetl źródło.

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

Przegląd

FAB występują częściej na urządzeniach mobilnych niż na komputerach, ale są powszechne w obu sytuacjach. Wyświetlają główne działania, dzięki czemu są wygodne i wszechstronne. To styl korzystania z usługi stał się znany dzięki interfejsowi Material UI. Jego sugestie dotyczące użycia i rozmieszczenia można znaleźć tutaj.

Elementy i style

Kod HTML tych elementów sterujących zawiera element kontenera i zestaw z co najmniej jednym przyciskiem. Kontener umieszcza przyciski PPP w widocznym obszarze i zarządza odstępami między przyciskami. Przyciski mogą być małe lub domyślne, co zapewnia pewną różnorodność między działaniami głównymi i dodatkowymi.

kontener typu FAB

Ten element może być zwykłym elementem <div>, ale wyświadczmy go niezauważonym użytkownikom i oznaczmy go przydatnymi atrybutami, które pomogą wyjaśnić przeznaczenie i zawartość tego kontenera.

Znaczniki przycisku typu FAB

Zacznij od klasy .fabs, którą CSS dostosuje do stylu, a następnie dodaj role="group" i aria-label, aby nie był to po prostu ogólny kontener, ale jego nazwa i cel.

<div class="fabs" role="group" aria-label="Floating action buttons">
  <!-- buttons will go here -->
</div>

Styl przycisków PPP

Aby wygodnie korzystać z przycisków typu FAB, są one cały czas przyklejone w widocznym obszarze. To świetny przypadek użycia dla pozycji fixed. Pozycja widocznego obszaru inset-block i inset-inline dopełnia tryb dokumentu użytkownika, np. od prawej do lewej lub od lewej do prawej. Właściwości niestandardowe pozwalają też zapobiegać powtarzaniu się i zapewniają równe odległości od dolnej i bocznej krawędzi widocznego obszaru:

.fabs {
  --_viewport-margin: 2.5vmin;

  position: fixed;
  z-index: var(--layer-1);

  inset-block: auto var(--_viewport-margin);
  inset-inline: auto var(--_viewport-margin);
}

Następnie wyświetlam wyświetlacz kontenera flex i zmieniam kierunek jego układu na column-reverse. Spowoduje to grupowanie elementów podrzędnych względem siebie (kolumnę), a także odwrócenie ich wizualnej kolejności. W efekcie pierwszy z możliwych do zaznaczenia element staje się dolnym elementem, a nie górnym, w tym miejscu w dokumencie HTML będzie normalnie zaznaczony element. Odwrót

Widoczne są 2 przyciski typu FAB z Narzędziami deweloperskimi nakładającymi się na układ siatki. Pokazuje przerwa między nimi w paski, a także pokazuje ich obliczoną wysokość i szerokość.

.fabs {
  …

  display: flex;
  flex-direction: column-reverse;
  place-items: center;
  gap: var(--_viewport-margin);
}

Wyśrodkowywanie jest obsługiwane za pomocą funkcji place-items, a gap dodaje odstęp między przyciskami PPP w kontenerze.

Przyciski PPP

Czas zmienić styl niektórych przycisków, aby wyglądały tak, jakby unosiły się nad wszystkim.

Domyślny przycisk typu FAB

Pierwszy przycisk do stylu jest przyciskiem domyślnym. Będą one podstawą wszystkich przycisków tego typu. Później utworzymy wariant, który uzyska alternatywny wygląd, modyfikując jak najmniejszą liczbę stylów podstawowych.

Znaczniki FAB

Właściwym wyborem jest element <button>. Zaczniemy od podstaw, bo to świetny sposób obsługi myszy, dotyku i klawiatury. Najważniejszym aspektem tych znaczników jest ukrywanie ikony przed użytkownikami za pomocą aria-hidden="true" i dodanie niezbędnego tekstu etykiety do samego znacznika <button>. Przy dodawaniu etykiet w takich przypadkach lubię też dodawać element title, aby użytkownicy myszy wiedzieli, co ma przekazać ikona.

<button data-icon="plus" class="fab" title="Add new action" aria-label="Add new action">
  <svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24">...</svg>
</button>

Styl przycisku PPP

Zacznijmy od przekształcenia przycisku w wyściełany okrągły przycisk z mocnym cieniem, ponieważ to jego pierwsze cechy charakterystyczne:

.fab {
  --_size: 2rem;

  padding: calc(var(--_size) / 2);
  border-radius: var(--radius-round);
  aspect-ratio: 1;
  box-shadow: var(--shadow-4);
}

Teraz dodajmy kolor. Wykorzystamy strategię, z której korzystaliśmy wcześniej w wyzwaniach GUI. Utwórz jasno nazwany zestaw właściwości niestandardowych, które statycznie utrzymują jasne i ciemne kolory, a potem dodaj adaptacyjną właściwość niestandardową, która w zależności od preferencji systemowych użytkownika dotyczących kolorów będzie wybierana na „jasny” lub „ciemny”:

.fab {
  …

  /* light button and button hover */
  --_light-bg: var(--pink-6);
  --_light-bg-hover: var(--pink-7);

  /* dark button and button hover */
  --_dark-bg: var(--pink-4);
  --_dark-bg-hover: var(--pink-3);

  /* adaptive variables set to light by default */
  --_bg: var(--_light-bg);

  /* static icon colors set to the adaptive foreground variable */
  --_light-fg: white;
  --_dark-fg: black;
  --_fg: var(--_light-fg);

  /* use the adaptive properties on some styles */
  background: var(--_bg);
  color: var(--_fg);

  &:is(:active, :hover, :focus-visible) {
    --_bg: var(--_light-bg-hover);

    @media (prefers-color-scheme: dark) {
      --_bg: var(--_dark-bg-hover);
    }
  }

  /* if users prefers dark, set adaptive props to dark */
  @media (prefers-color-scheme: dark) {
    --_bg: var(--_dark-bg);
    --_fg: var(--_dark-fg);
  }
}

Następnie dodaj style, aby ikony SVG dopasować się do obszaru.

.fab {
  …

  & > svg {
    inline-size: var(--_size);
    block-size: var(--_size);
    stroke-width: 3px;
  }
}

Na koniec usuń podświetlenie kliknięcia przycisku, ponieważ dodaliśmy własną wizualną odpowiedź na potrzeby interakcji:

.fab {
  -webkit-tap-highlight-color: transparent;
}

Miniprzycisk typu FAB

Celem tej sekcji jest utworzenie wariantu przycisku FAB. Zmniejszając liczbę elementów typu FAB jako czynności domyślne, możemy promować działanie, które użytkownik wykonuje najczęściej.

Znaczniki miniprzycisku typu FAB

Kod HTML jest taki sam jak przycisk typu FAB, ale dodajemy klasę „.mini”, by wskazać CSS wariantowi.

<button data-icon="heart" class="fab mini" title="Like action" aria-label="Like action">
  <svg aria-hidden="true" width="24" height="24" viewBox="0 0 24 24">...</svg>
</button>
Styl miniprzycisku typu FAB

Dzięki wykorzystaniu właściwości niestandardowych jedyną potrzebną zmianą jest dostosowanie zmiennej --_size.

.fab.mini {
  --_size: 1.25rem;
}

Zrzut ekranu przedstawiający 2 przyciski typu fabu, przy czym górny przycisk jest mniejszy niż ten na dole.

Ułatwienia dostępu

Najważniejszą rzeczą, o której należy pamiętać w przypadku ułatwień dostępu w przypadku przycisków FAB, jest ich położenie względem klawiatury. W tej wersji demonstracyjnej dostępne są tylko przyciski typu FAB, nie ma z nim nic do rywalizacji pod względem kolejności i przepływu klawiatury, co oznacza, że nie ma możliwości zademonstrowania poprawnego działania klawiatury. W sytuacji, w której istnieją konkurencyjne elementy, warto zastanowić się, w których częściach tego procesu użytkownik powinien wchodzić w interakcję z przyciskiem PPP.

Demonstracja interakcji z klawiaturą

Gdy użytkownik przejdzie do kontenera FAB, dodaliśmy już właściwości role="group" i aria-label="floating action buttons", które informują czytniki ekranu o treści, którą wybrali. Domyślny przycisk typu FAB został umieszczony na początku, aby użytkownicy widzieli jako pierwsze działanie główne. Następnie używam flex-direction: column-reverse;, aby wizualnie uporządkować przycisk główny na dole, blisko palców użytkowników, aby był łatwo dostępny. To przydatna zaleta, ponieważ domyślny przycisk jest dobrze widoczny i pierwszy również dla użytkowników klawiatury. Dzięki temu interfejs jest bardzo podobny.

Pamiętaj też o ukryciu ikon przed użytkownikami czytników ekranu i nadanie im etykiety z przyciskiem, aby nie była tajemnica. Zostało to już wykonane w kodzie HTML z atrybutem aria-hidden="true" w elementach <svg> i aria-label="Some action" na <button>.

Animacja

Można dodawać różne rodzaje animacji, aby poprawić wrażenia użytkownika. Podobnie jak w innych wyzwaniach GUI skonfigurujemy kilka niestandardowych właściwości, które mają na celu ograniczenie ruchu i pełne doznanie ruchu. Domyślnie style zakładają, że użytkownik chce uzyskać ograniczony ruch, a za pomocą zapytania o multimedia prefers-reduced-motion zamień wartość przejścia na pełny ruch.

Strategia z ograniczonym ruchem z właściwościami niestandardowymi

W tym kodzie CSS tworzone są 3 właściwości niestandardowe: --_motion-reduced, --_motion-ok i --_transition. Pierwsze 2 opcje umożliwiają odpowiednie przejście zależnie od preferencji użytkownika, a ostatnia zmienna --_transition zostanie ustawiona odpowiednio na --_motion-reduced lub --_motion-ok.

.fab {
  /* box-shadow and background-color can safely be transitioned for reduced motion users */
  --_motion-reduced:
    box-shadow .2s var(--ease-3),
    background-color .3s var(--ease-3);

  /* add transform and outline-offset for users ok with motion */
  --_motion-ok:
    var(--_motion-reduced),
    transform .2s var(--ease-3),
    outline-offset 145ms var(--ease-2);

  /* default the transition styles to reduced motion */
  --_transition: var(--_motion-reduced);

  /* set the transition to our adaptive transition custom property*/
  transition: var(--_transition);

  /* if motion is ok, update the adaptive prop to the respective transition prop */
  @media (prefers-reduced-motion: no-preference) {
    --_transition: var(--_motion-ok);
  }
}

Po wprowadzeniu powyższych zmian zmiany w box-shadow, background-color, transform i outline-offset można przenieść, co sprawi, że interfejs będzie podobał się użytkownikowi.

Następnie dodaj urozmaicenia do stanu :active, dostosowując go nieco translateY. Po naciśnięciu przycisk uzyska przyjemny efekt:

.fab {
  …

  &:active {
    @media (prefers-reduced-motion: no-preference) {
      transform: translateY(2%);
    }
  }
}

Na koniec umieść wszelkie zmiany w ikonach SVG w przyciskach:

.fab {
  …

  &[data-icon="plus"]:hover > svg {
    transform: rotateZ(.25turn);
  }

  & > svg {
    @media (prefers-reduced-motion: no-preference) {
      will-change: transform;
      transition: transform .5s var(--ease-squish-3);
    }
  }
}

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