Xây dựng thành phần nút hành động nổi (FAB)

Thông tin tổng quan cơ bản về cách tạo thành phần FAB thích ứng màu, phản hồi và dễ tiếp cận.

Trong bài đăng này, tôi muốn chia sẻ suy nghĩ về cách tạo các thành phần FAB thích ứng màu sắc, thích ứng và dễ tiếp cận. Hãy xem thử bản minh hoạxem nguồn!

Nếu bạn thích video, đây là phiên bản YouTube của bài đăng này:

Tổng quan

FAB phổ biến trên thiết bị di động hơn so với máy tính, nhưng thường thấy trong cả hai trường hợp. Chúng hiển thị các hành động chính, giúp chúng thuận tiện và ở mọi nơi. Kiểu trải nghiệm người dùng này đã trở nên nổi tiếng nhờ Material UI. Bạn có thể tìm thấy các đề xuất về cách sử dụng và vị trí tại đây.

Phần tử và kiểu

HTML cho các chế độ điều khiển này liên quan đến một phần tử vùng chứa và một tập hợp gồm một hoặc nhiều nút. Vùng chứa này định vị các FAB trong khung nhìn và quản lý khoảng cách giữa các nút. Các nút có thể có kích thước thu nhỏ hoặc mặc định, tuỳ theo từng thao tác khác nhau giữa hành động chính và hành động phụ.

Vùng chứa FAB

Phần tử này có thể là một <div> thông thường, nhưng hãy ưu tiên những người dùng khiếm thị và gắn thẻ cho phần tử đó bằng một số thuộc tính hữu ích để giải thích mục đích và nội dung của vùng chứa này.

Mã đánh dấu FAB

Bắt đầu bằng một lớp .fabs để CSS kết nối với kiểu, sau đó thêm role="group"aria-label để không chỉ là một vùng chứa chung chung, mà được đặt tên và có mục đích.

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

Kiểu FAB

Để FAB được thuận tiện, chúng luôn nằm trong khung nhìn. Đây là trường hợp sử dụng tuyệt vời cho vị trí fixed. Trong vị trí khung nhìn này, tôi đã chọn sử dụng inset-blockinset-inline để vị trí sẽ bổ trợ cho chế độ tài liệu của người dùng, chẳng hạn như từ phải sang trái hoặc từ trái sang phải. Các thuộc tính tuỳ chỉnh cũng được dùng để ngăn tình trạng lặp lại và đảm bảo khoảng cách bằng nhau từ cạnh dưới cùng và cạnh bên của khung nhìn:

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

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

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

Tiếp theo, tôi cung cấp màn hình vùng chứa flex và thay đổi hướng bố cục của vùng chứa thành column-reverse. Thao tác này sẽ xếp chồng các phần tử con lên nhau (cột) và cũng đảo ngược thứ tự hình ảnh. Cách làm này có tác dụng đặt phần tử có thể làm tâm điểm đầu tiên làm phần tử dưới cùng thay vì trên cùng. Đây sẽ là vị trí thường được lấy tiêu điểm trên tài liệu HTML. Thao tác đảo ngược thứ tự hình ảnh sẽ hợp nhất trải nghiệm cho người dùng mắt và người dùng bàn phím, vì kiểu hành động chính lớn hơn các nút nhỏ cho người dùng sáng mắt biết rằng đó là hành động chính và người dùng bàn phím sẽ lấy đó làm mục đầu tiên trong nguồn.

Hai nút fab được hiển thị với Công cụ cho nhà phát triển phủ lên bố cục lưới. Cho thấy khoảng cách giữa các lớp đó bằng mẫu sọc, đồng thời cho thấy chiều cao và chiều rộng đã tính toán được.

.fabs {
  …

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

Việc căn giữa được xử lý bằng place-itemsgap sẽ thêm khoảng cách giữa mọi nút FAB được đặt trong vùng chứa.

Nút hành động nổi

Đã đến lúc tạo kiểu cho một số nút để chúng trông giống như lơ lửng ở trên cùng.

FAB mặc định

Nút đầu tiên để tạo kiểu là nút mặc định. Đây sẽ là cơ sở cho tất cả các nút hành động nổi. Sau đó, chúng ta sẽ tạo một biến thể đạt được giao diện thay thế trong khi sửa đổi càng ít kiểu cơ sở này càng tốt.

Mã đánh dấu FAB

Phần tử <button> là lựa chọn phù hợp. Chúng ta sẽ bắt đầu với điều này làm cơ sở vì nó mang đến trải nghiệm người dùng tuyệt vời bằng chuột, thao tác chạm và bàn phím. Khía cạnh quan trọng nhất của mã đánh dấu này là ẩn biểu tượng để người dùng trình đọc màn hình có aria-hidden="true" và thêm văn bản nhãn cần thiết vào chính mã đánh dấu <button>. Khi thêm nhãn trong những trường hợp như vậy, tôi cũng muốn thêm title để người dùng chuột có thể nhận được thông tin về nội dung mà biểu tượng muốn truyền tải.

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

Kiểu FAB

Trước tiên, hãy chuyển nút thành một nút tròn có khoảng đệm với một bóng đổ mạnh, vì đây là các tính năng xác định đầu tiên của nút:

.fab {
  --_size: 2rem;

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

Tiếp theo, hãy thêm màu sắc. Chúng ta sẽ sử dụng chiến lược từng được dùng trong Thử thách GUI (Giao diện người dùng đồ hoạ). Tạo một tập hợp thuộc tính tuỳ chỉnh có tên rõ ràng để giữ tĩnh màu sáng và tối, sau đó là một thuộc tính tuỳ chỉnh thích ứng sẽ được đặt thành biến ánh sáng hoặc tối tuỳ thuộc vào lựa chọn ưu tiên của người dùng về hệ thống về màu sắc:

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

Tiếp theo, hãy thêm một số kiểu để giúp biểu tượng SVG vừa với không gian.

.fab {
  …

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

Cuối cùng, hãy xoá dấu nhấn nổi bật khỏi nút này vì chúng ta đã thêm phản hồi bằng hình ảnh của riêng mình cho hoạt động tương tác:

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

FAB thu nhỏ

Mục tiêu của phần này là tạo một biến thể cho nút hành động nổi. Bằng cách làm cho một số FAB nhỏ hơn hành động mặc định, chúng ta có thể quảng bá hành động mà người dùng thực hiện thường xuyên nhất.

Mã đánh dấu Mini FAB

HTML giống với FAB nhưng chúng tôi thêm lớp ".mini" để cung cấp cho CSS hook vào biến thể.

<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>
Kiểu FAB thu nhỏ

Nhờ sử dụng các thuộc tính tuỳ chỉnh, bạn chỉ cần thay đổi điều chỉnh đối với biến --_size.

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

Ảnh chụp màn hình 2 nút fab xếp chồng lên nhau và nút trên cùng nhỏ hơn nút ở dưới cùng.

Hỗ trợ tiếp cận

Phần quan trọng nhất cần nhớ đối với khả năng hỗ trợ tiếp cận với FAB là vị trí trong luồng bàn phím trên trang. Bản minh hoạ này chỉ có FAB mà không có gì cạnh tranh về thứ tự và quy trình bàn phím, tức là bản minh hoạ này không có cơ hội minh hoạ một quy trình có ý nghĩa của bàn phím. Trong một trường hợp có các yếu tố cạnh tranh để lấy tiêu điểm, bạn nên suy nghĩ kỹ về vị trí trong luồng đó nếu người dùng thấy họ đang tham gia vào luồng nút FAB.

Minh hoạ hoạt động tương tác với bàn phím

Sau khi người dùng đã đặt tiêu điểm vào vùng chứa FAB, chúng tôi đã thêm role="group"aria-label="floating action buttons" để thông báo cho người dùng trình đọc màn hình về nội dung mà họ đã đặt tiêu điểm. Theo chiến lược, tôi đã đặt FAB mặc định trước để người dùng tìm thấy hành động chính trước. Sau đó, tôi sử dụng flex-direction: column-reverse; để sắp xếp một cách trực quan nút chính ở dưới cùng, gần với ngón tay của người dùng để dễ dàng truy cập. Đây là một điều tốt đẹp vì nút mặc định rất nổi bật và cũng là nút đầu tiên cho người dùng bàn phím, mang lại cho họ trải nghiệm rất giống nhau.

Cuối cùng, hãy nhớ ẩn các biểu tượng để người dùng trình đọc màn hình không nhìn thấy và đảm bảo bạn cung cấp cho họ nhãn cho nút để nút không bị bí ẩn. Việc này đã được thực hiện trong HTML với aria-hidden="true" trên <svg>aria-label="Some action" trên <button>.

Hoạt ảnh

Bạn có thể thêm nhiều loại ảnh động để nâng cao trải nghiệm người dùng. Giống như trong các Thử thách GUI khác, chúng tôi sẽ thiết lập một số thuộc tính tuỳ chỉnh để duy trì mục đích giảm trải nghiệm chuyển động và trải nghiệm chuyển động đầy đủ. Theo mặc định, các kiểu sẽ giả định người dùng muốn giảm chuyển động, sau đó sử dụng truy vấn phương tiện prefers-reduced-motion sẽ hoán đổi giá trị chuyển đổi thành chuyển động đầy đủ.

Chiến lược chuyển động rút gọn với các thuộc tính tuỳ chỉnh

Ba thuộc tính tuỳ chỉnh được tạo trong CSS sau: --_motion-reduced, --_motion-ok--_transition. Hai lượt chuyển đổi đầu tiên giữ lại các lượt chuyển đổi thích hợp do người dùng ưu tiên, và biến cuối cùng --_transition sẽ được đặt thành --_motion-reduced hoặc --_motion-ok tương ứng.

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

Với các thay đổi nêu trên, các thay đổi đối với box-shadow, background-color, transformoutline-offset có thể được chuyển đổi, cung cấp cho người dùng phản hồi tốt đẹp về giao diện người dùng rằng hoạt động tương tác của họ đã được nhận.

Tiếp theo, hãy tinh tế hơn một chút cho trạng thái :active bằng cách điều chỉnh translateY một chút. Việc này sẽ tạo ra hiệu ứng nhấn đẹp mắt cho nút:

.fab {
  …

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

Sau cùng, hãy chuyển đổi mọi thay đổi đối với biểu tượng SVG trong các nút:

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

Kết luận

Giờ bạn đã biết tôi làm được như thế nào, bạn sẽ làm thế nào 🙂

Hãy đa dạng hoá phương pháp tiếp cận của chúng ta và tìm hiểu tất cả các cách xây dựng trên web.

Hãy tạo một bản minh hoạ, đường liên kết tweet me và tôi sẽ thêm bản phối lại đó vào phần bản phối lại của cộng đồng bên dưới!

Bản phối lại của cộng đồng

Chưa có nội dung nào để xem ở đây.

Tài nguyên