Membuat komponen tombol tindakan mengambang (FAB)

Ringkasan dasar tentang cara membangun komponen FAB yang adaptif warna, responsif, dan mudah diakses.

Dalam postingan ini, saya ingin berbagi pendapat tentang cara membangun komponen FAB yang adaptif warna, responsif, dan dapat diakses. Coba demonya dan lihat sumbernya.

Jika Anda lebih suka video, berikut versi YouTube postingan ini:

Ringkasan

FAB lebih umum di perangkat seluler daripada desktop, tetapi sering terjadi di kedua skenario tersebut. Mereka tetap menampilkan tindakan utama, sehingga praktis dan tersedia. Gaya pengalaman pengguna ini dipopulerkan oleh UI Material dan saran penggunaan dan penempatannya dapat ditemukan di sini.

Elemen dan gaya

HTML untuk kontrol ini melibatkan elemen penampung dan kumpulan satu atau beberapa tombol. Penampung memosisikan FAB dalam area tampilan dan mengelola celah di antara tombol. Tombolnya bisa berukuran mini atau default, yang memberikan beberapa variasi bagus antara tindakan utama dan sekunder.

Penampung FAB

Elemen ini dapat berupa <div> reguler, tetapi mari kita bantu pengguna yang tidak berpenglihatan ini dan memberinya tag dengan beberapa atribut bermanfaat untuk menjelaskan tujuan dan konten penampung ini.

Markup FAB

Mulai dengan class .fabs agar CSS dapat dikaitkan dengan gaya, lalu tambahkan role="group" dan aria-label sehingga ini bukan hanya penampung umum, tetapi dinamai dan terarah.

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

Gaya FAB

Agar nyaman, FAB selalu berada dalam area pandang. Ini adalah kasus penggunaan yang bagus untuk posisi fixed. Dalam posisi area pandang ini, saya memilih untuk menggunakan inset-block dan inset-inline sehingga posisinya akan melengkapi mode dokumen pengguna, seperti kanan-ke-kiri atau kiri-ke-kanan. Properti khusus juga digunakan untuk mencegah pengulangan dan memastikan jarak yang sama dari tepi bawah dan samping area pandang:

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

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

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

Selanjutnya, saya memberi container tampilan flex dan mengubah arah tata letaknya menjadi column-reverse. Tindakan ini akan menumpuk turunan di atas satu sama lain (kolom) dan juga membalikkan urutan visualnya. Hal ini memiliki efek menjadikan elemen pertama yang dapat difokuskan sebagai elemen bawah, bukan bagian atas, yang menjadi tempat fokus secara normal berjalan per dokumen HTML. Membalik urutan visual akan menyatukan pengalaman bagi pengguna yang berpenglihatan normal dan pengguna keyboard, karena gaya visual tindakan utama karena lebih besar dari tombol mini menunjukkan kepada pengguna yang terlihat bahwa tindakan tersebut adalah tindakan utama, dan pengguna keyboard akan memfokuskannya sebagai item pertama dalam sumber.

Dua tombol fab ditampilkan dengan DevTools yang menempatkan tata letak gridnya. Menampilkan jarak di antara keduanya dengan pola bergaris dan juga menampilkan tinggi dan lebar yang dihitung.

.fabs {
  …

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

Pemusatan ditangani dengan place-items, dan gap menambahkan ruang di antara tombol FAB yang ditempatkan dalam penampung.

Tombol FAB

Saatnya menata gaya beberapa tombol agar terlihat seperti mengambang di atas semuanya.

FAB default

Tombol pertama untuk menata gaya adalah tombol default. Ini akan berfungsi sebagai dasar untuk semua tombol FAB. Nanti, kita akan membuat varian yang mencapai tampilan alternatif sambil memodifikasi sesedikit mungkin gaya dasar ini.

Markup FAB

Elemen <button> adalah pilihan yang tepat. Kita akan mulai dengan ini sebagai dasarnya karena dilengkapi dengan pengalaman pengguna mouse, sentuhan, dan keyboard. Aspek yang paling penting dari markup ini adalah menyembunyikan ikon dari pengguna pembaca layar dengan aria-hidden="true" dan menambahkan teks label yang diperlukan ke markup <button> itu sendiri. Saat menambahkan label dalam kasus ini, saya juga suka menambahkan title sehingga pengguna mouse bisa mendapatkan informasi tentang apa yang ingin dikomunikasikan oleh ikon.

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

Gaya FAB

Pertama, mari kita ubah tombol menjadi tombol bulat dengan padding dengan bayangan yang kuat, karena ini adalah fitur pertama yang mendefinisikan tombol:

.fab {
  --_size: 2rem;

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

Selanjutnya mari kita tambahkan warna. Kita akan gunakan strategi yang pernah kita gunakan di Tantangan GUI sebelumnya. Buat kumpulan properti kustom bernama jelas yang secara statis menyimpan warna terang dan gelap, lalu properti kustom adaptif yang akan disetel ke variabel terang atau gelap, bergantung pada preferensi sistem pengguna untuk warna:

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

Selanjutnya, tambahkan beberapa gaya untuk membantu ikon SVG sesuai dengan ruang.

.fab {
  …

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

Terakhir, hapus tanda ketuk dari tombol karena kita telah menambahkan masukan visual kita sendiri untuk interaksi:

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

FAB Mini

Sasaran bagian ini adalah membuat varian untuk tombol FAB. Dengan membuat beberapa FAB lebih kecil daripada tindakan default, kita dapat mempromosikan tindakan yang paling sering dilakukan pengguna.

Markup FAB mini

HTML sama dengan FAB tetapi kita menambahkan kelas ".mini" untuk memberi CSS hook ke dalam varian.

<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>
Gaya FAB mini

Berkat penggunaan properti khusus, satu-satunya perubahan yang diperlukan adalah penyesuaian pada variabel --_size.

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

Tangkapan layar dari dua tombol fab yang ditumpuk dan tombol atas lebih kecil dari yang ada di bagian bawah.

Aksesibilitas

Bagian terpenting yang harus diingat untuk aksesibilitas dengan FAB adalah penempatan dalam alur keyboard halaman. Demo ini hanya memiliki FAB. Tidak ada tantangan dalam hal urutan dan alur keyboard, yang berarti tidak memiliki kesempatan untuk mendemonstrasikan alur keyboard yang bermakna. Dalam skenario di mana ada elemen yang bersaing untuk mendapatkan fokus, sebaiknya pikirkan secara mendalam tentang di mana alur tersebut harus dimasukkan pengguna ke dalam alur tombol FAB.

Demonstrasi interaksi keyboard

Setelah pengguna berfokus ke penampung FAB, kami telah menambahkan role="group" dan aria-label="floating action buttons" yang memberi tahu pengguna pembaca layar tentang konten yang telah mereka fokuskan. Secara strategis, saya telah menempatkan FAB default terlebih dahulu, sehingga pengguna menemukan tindakan utama terlebih dahulu. Kemudian, saya menggunakan flex-direction: column-reverse; untuk mengurutkan secara visual tombol utama di bagian bawah, dekat dengan jari pengguna agar mudah diakses. Ini adalah keuntungan yang bagus karena tombol default terlihat jelas dan juga pertama untuk pengguna keyboard, sehingga memberi mereka pengalaman yang sangat serupa.

Terakhir, jangan lupa untuk menyembunyikan ikon Anda dari pengguna pembaca layar dan pastikan Anda memberi mereka label untuk tombol sehingga hal ini tidak menjadi misteri. Hal ini telah dilakukan di HTML dengan aria-hidden="true" pada <svg> dan aria-label="Some action" pada <button>.

Animasi

Berbagai jenis animasi dapat ditambahkan untuk meningkatkan pengalaman pengguna. Seperti dalam Tantangan GUI lainnya, kita akan menyiapkan beberapa properti khusus untuk menyimpan intent pengalaman gerakan yang dikurangi dan pengalaman gerakan penuh. Secara default, gaya akan mengasumsikan bahwa pengguna menginginkan gerakan yang lebih sedikit, lalu dengan menggunakan kueri media prefers-reduced-motion, nilai transisi akan ditukar menjadi gerakan penuh.

Strategi gerakan yang dikurangi dengan properti khusus

Tiga properti khusus dibuat di CSS berikut: --_motion-reduced, --_motion-ok, dan --_transition. Dua yang pertama memiliki transisi yang sesuai berdasarkan preferensi pengguna, dan variabel terakhir --_transition akan disetel ke --_motion-reduced atau --_motion-ok masing-masing.

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

Dengan menerapkan hal di atas, perubahan pada box-shadow, background-color, transform, dan outline-offset dapat ditransisikan, yang memberi pengguna masukan UI yang baik bahwa interaksi mereka telah diterima.

Selanjutnya, tambahkan sedikit gaya ke status :active dengan menyesuaikan translateYsedikit, ini akan memberi tombol efek penekanan yang bagus:

.fab {
  …

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

Lalu yang terakhir, transisikan perubahan apa pun pada ikon SVG di tombol:

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

Kesimpulan

Setelah Anda tahu cara saya melakukannya, bagaimana Anda‽ 🙂

Mari lakukan diversifikasi pendekatan dan pelajari semua cara untuk membangun di web.

Buat demo, link tweet me, dan saya akan menambahkannya ke bagian remix komunitas di bawah.

Remix komunitas

Belum ada apa-apa di sini.

Referensi