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

Tổng quan cơ bản về cách tạo các thành phần FAB thích ứng với màu sắc, thích ứng và dễ tiếp cận.

Trong bài đăng này, tôi muốn chia sẻ suy nghĩ của mình về cách tạo các thành phần FAB thích ứng với màu sắc, phản hồi và hỗ trợ tiếp cận. Dùng thử bản minh hoạxem mã nguồn!

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

Tổng quan

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

Phần tử và kiểu

HTML cho các thành phần điều khiển này bao gồm một phần tử vùng chứa và một nhóm gồm một hoặc nhiều nút. Vùng chứa đặt các FAB trong khung nhìn và quản lý khoảng trống giữa các nút. Các nút có thể là nhỏ hoặc mặc định, để có sự khác biệt thú vị giữa các thao tác chính và phụ.

Vùng chứa FAB

Phần tử này có thể là <div> thông thường, nhưng hãy ưu tiên cho người dùng khó nhìn và gắn thẻ 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 với lớp .fabs để CSS có thể liên kết với kiểu, sau đó thêm role="group"aria-label để không chỉ là một vùng chứa chung, mà còn đượ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

Để thuận tiện, các FAB luôn nằm trong khung nhìn. Đây là một 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í này sẽ bổ sung 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 chặn việc 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 sẽ cung cấp màn hình vùng chứa flex và thay đổi hướng bố cục thành column-reverse. Thao tác này sẽ xếp các phần tử con chồng lên nhau (cột) và cũng đảo ngược thứ tự hình ảnh của chúng. Phương pháp này có tác dụng khiến phần tử có thể làm tâm điểm đầu tiên trở thành phần tử dưới cùng thay vì phần tử trên cùng (tức là nơi đặt tiêu điểm bình thường trên mỗi tài liệu HTML). Việc đảo ngược thứ tự hình ảnh sẽ hợp nhất trải nghiệm cho người dùng khiếm thị và người dùng bàn phím, vì kiểu của thao tác chính lớn hơn các nút nhỏ cho người dùng khiếm thị biết đó là thao tác chính và người dùng bàn phím sẽ lấy đó làm mục đầu tiên trong nguồn.

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

.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 trống giữa mọi nút FAB được đặt trong vùng chứa.

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

Đã đến lúc tạo kiểu cho một số nút để trông như chúng đang nổi lên trên mọi thứ.

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 FAB. Sau đó, chúng ta sẽ tạo một biến thể có giao diện thay thế trong khi sửa đổi ít kiểu cơ sở này nhất có thể.

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 lớp này làm cơ sở vì lớp này mang lại trải nghiệm người dùng tuyệt vời với chuột, cảm ứng 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 khỏi người dùng trình đọc màn hình bằng 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 nà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.

<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 biến nút này thành một nút tròn có đệm với bóng đổ mạnh, vì đây là những đặc điểm đầu tiên xác định 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. Chúng ta sẽ dùng một chiến lược đã từng sử dụng trong phần Thử thách về giao diện người dùng đồ hoạ trước đây. Tạo một tập hợp các thuộc tính tuỳ chỉnh được đặt tên rõ ràng giữ cố định màu sáng và tối, sau đó một thuộc tính tuỳ chỉnh thích ứng sẽ được thiết lập thành biến 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ề màu sắc trong hệ thống:

.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á phần đánh dấu nhấn khỏi nút vì chúng ta đã thêm phản hồi hình ảnh riêng 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 FAB. Bằng cách tạo 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 FAB nhỏ

HTML giống với FAB nhưng chúng tôi thêm lớp ".mini" để CSS kết nối với 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 điều chỉnh biến --_size.

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

Ảnh chụp màn hình của hai 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ớ về khả năng hỗ trợ tiếp cận bằng FAB là vị trí trong luồng bàn phím của trang. Bản minh hoạ này chỉ có các FAB, không có gì để cạnh tranh về thứ tự và luồng bàn phím, nghĩa là bản minh hoạ này không có cơ hội để thể hiện một luồng bàn phím có ý nghĩa. Trong trường hợp có các phần tử cạnh tranh để lấy tiêu điểm, bạn nên suy nghĩ kỹ về vị trí trong luồng đó mà người dùng sẽ thấy mình đang chuyển sang luồng nút FAB.

Minh hoạ tương tác bằng bàn phím

Sau khi người dùng đặt tiêu điểm vào vùng chứa FAB, chúng ta đã 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 của những gì họ đã đặt tiêu điểm. Về chiến lược, tôi đã đặt FAB mặc định trước tiên để người dùng tìm thấy hành động chính trước tiên. Sau đó, tôi sử dụng flex-direction: column-reverse; để sắp xếp trực quan nút chính ở dưới cùng, gần với các ngón tay của người dùng để dễ dàng truy cập. Đây là một kết quả tốt vì nút mặc định có hình ảnh nổi bật và cũng là nút đầu tiên dành cho người dùng bàn phím, mang lại cho họ những trải nghiệm rất giống nhau.

Cuối cùng, đừng quên ẩn các biểu tượng khỏi người dùng trình đọc màn hình và đảm bảo rằng bạn cung cấp cho họ nhãn cho nút để đảm bảo không phải là điều 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 các <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 ta sẽ thiết lập một số thuộc tính tuỳ chỉnh để lưu giữ ý định về trải nghiệm giả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 giảm chuyển động bằng 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 biến đầu tiên chứa các hiệu ứng chuyển đổi phù hợp với lựa chọn ưu tiên của người dùng 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 những nội dung 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 thêm một chút tinh tế vào trạng thái :active bằng cách điều chỉnh translateY một chút, điều này sẽ tạo cho nút một hiệu ứng nhấn đẹp mắt:

.fab {
  

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

Cuối 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 cách tôi thực hiện điều đó, bạn sẽ làm cách nào‽ 🙂

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

Hãy tạo bản minh hoạ, gửi đường liên kết cho tôi trên Twitter và tôi sẽ thêm bản minh hoạ đó vào phầ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.

Tài nguyên