Product Management
Đăng nhập
ESC

Nhập từ khóa để tìm kiếm

↑↓ Di chuyển
Enter Mở
ESC Đóng

Bài 28 — Touch Targets — Size & Spacing

Đã đọc 0/15 mục · còn khoảng 11 phút
Cách chúng tôi ghi nhận

Một mục được tính là đã đọc khi nó nằm giữa màn hình đủ lâu so với độ dài của nó (bảng và sơ đồ tính một nửa), bạn vẫn đang cuộn hoặc bấm phím, và bạn đã thấy tới cuối mục. Lướt nhanh hoặc để tab mở không được tính. Chúng tôi chỉ lưu thời gian đọc từng mục — không lưu gì khác.

Mở đầu — vì sao bài này quan trọng

Hãy tưởng tượng bạn đang ngồi trên xe buýt tuyến 08 giữa giờ cao điểm ở Sài Gòn, một tay bám cột, một tay cầm điện thoại cố gắng bấm nút "Thanh toán" trên app đặt vé. Nút quá nhỏ, ngón tay cái của bạn cứ trượt sang nút "Hủy" bên cạnh. Bạn bấm lại ba, bốn lần, xe rung lắc, và cuối cùng bạn bỏ cuộc. Đó không phải lỗi của bạn — đó là lỗi của người thiết kế đã đặt các mục tiêu chạm (touch target) quá nhỏ và quá sát nhau.

Touch target — vùng mà người dùng có thể chạm để kích hoạt một phần tử tương tác — là một trong những yếu tố accessibility bị xem nhẹ nhất, nhưng lại ảnh hưởng đến gần như tất cả mọi người. Nó không chỉ dành cho người khuyết tật. Người có run tay do Parkinson, người lớn tuổi mắt kém và tay không còn linh hoạt, người bị chấn thương tạm thời phải dùng tay không thuận, hay đơn giản là người bình thường đang di chuyển — tất cả đều hưởng lợi khi target đủ lớn.

Trong bài này, chúng ta tập trung riêng vào kích thước (size) và khoảng cách (spacing) của touch target. Đây là chủ đề độc lập với keyboard navigation (Bài 11) hay focus indicator (Bài 12) — ở đây ta nói về ngón tay, con trỏ chuột, bút stylus, và mọi thiết bị trỏ (pointer input). Bạn sẽ hiểu chính xác con số WCAG yêu cầu, tại sao lại là con số đó, và cách áp dụng vào công việc thiết kế lẫn code hằng ngày.

Khái niệm cốt lõi

Touch target là gì?

Touch target là toàn bộ vùng có thể nhận thao tác chạm/click để kích hoạt một hành động — chứ không chỉ là phần đồ họa nhìn thấy được. Một nút có icon 16×16 pixel nhưng có padding xung quanh tạo thành vùng chạm 44×44 pixel thì touch target của nó là 44×44, không phải 16×16. Đây là điểm mấu chốt mà nhiều người hiểu nhầm: vùng chạm không bằng vùng nhìn thấy.

Vì sao ngón tay cần vùng lớn?

Ngón tay con người không chính xác như con trỏ chuột. Nghiên cứu về ergonomics chỉ ra rằng đầu ngón tay người lớn khi chạm màn hình tạo ra vùng tiếp xúc trung bình khoảng 8–10mm, và phần thịt của ngón cái có thể lên tới 45–57 pixel. Vì màn hình không "nhìn thấy" chính xác điểm bạn định chạm, hệ thống phải đoán tâm điểm. Target càng nhỏ, xác suất đoán sai càng cao — dẫn đến chạm nhầm.

Hai tiêu chuẩn WCAG bạn phải nắm

Có hai success criteria (tiêu chí thành công) liên quan trực tiếp, và bạn cần phân biệt rõ:

WCAG 2.1 — SC 2.5.5 Target Size (mức AAA): > "The size of the target for pointer inputs is at least 44 by 44 CSS pixels." (Kích thước của target cho thiết bị trỏ tối thiểu là 44×44 CSS pixel.)

Đây là mức AAA — mức cao nhất, khó đạt nhất, và con số vàng là 44×44 CSS pixel. Con số 44 không phải ngẫu nhiên: nó xuất phát từ hướng dẫn Human Interface Guidelines của Apple (44pt) và tương đồng với khuyến nghị của Google là 48dp.

WCAG 2.2 — SC 2.5.8 Target Size (Minimum) (mức AA): Khi WCAG 2.2 ra đời (tháng 10/2023), người ta nhận ra mức AAA 44px quá khó bắt buộc trên diện rộng, nên bổ sung một tiêu chí ở mức AA dễ đạt hơn: target tối thiểu 24×24 CSS pixel. Quan trọng hơn, SC 2.5.8 cho phép nhiều ngoại lệ (exception):

  • Spacing (khoảng cách): Nếu target nhỏ hơn 24px nhưng có một vòng tròn đường kính 24px vẽ quanh tâm nó mà không đè lên vòng tròn của target kế bên, thì vẫn đạt. Nói cách khác, target nhỏ nhưng cách xa nhau vẫn ổn.
  • Inline: Target nằm trong dòng văn bản (như link trong đoạn text) được miễn.
  • Essential: Khi vị trí/kích thước target bị ràng buộc bởi bản chất thông tin (ví dụ các thành phố sát nhau trên bản đồ).
  • User agent control: Kích thước do trình duyệt kiểm soát.

Phân biệt CSS pixel vs pixel vật lý

Một hiểu lầm phổ biến: 44 CSS pixel không phải 44 pixel vật lý của màn hình. Trên điện thoại retina/high-DPI (như iPhone), một CSS pixel có thể tương ứng 2–3 pixel vật lý. WCAG đo bằng CSS pixel, tức là đơn vị px trong code của bạn. Điều này tốt cho ta: chỉ cần viết min-width: 44px là đúng chuẩn, không cần tính toán mật độ điểm ảnh.

Tóm gọn con số để nhớ

  • 24×24 px — mức tối thiểu bắt buộc (AA, WCAG 2.2). Đây là "sàn".
  • 44×44 px — mức lý tưởng (AAA, WCAG 2.1). Đây là "mục tiêu nên hướng tới".
  • 48×48 px — khuyến nghị Material Design của Google, an toàn cho mobile.
  • 8 px — khoảng cách tối thiểu nên có giữa các target liền kề để tránh chạm nhầm.

Tình huống thực tế

Ví dụ 1 — App gọi xe và nút "Hủy chuyến" chết người

Một startup gọi xe giả định tên GoRide ở Hà Nội gặp tình trạng tỷ lệ hủy chuyến nhầm cao bất thường: khoảng 6% chuyến bị hủy trong 3 giây đầu sau khi tài xế nhận. Đội sản phẩm điều tra và phát hiện: trên màn hình chờ tài xế, nút "Hủy chuyến" (icon X, 20×20px) nằm ngay sát nút "Nhắn tin tài xế" (24×24px), khoảng cách giữa hai nút chỉ 4px. Người dùng đứng chờ dưới nắng, tay đổ mồ hôi, muốn nhắn tin nhưng lại chạm trúng nút hủy.

Đội thiết kế tăng vùng chạm của mỗi nút lên 44×44px (giữ nguyên icon 20px nhưng thêm padding), và giãn khoảng cách giữa hai nút lên 16px. Sau hai tuần, tỷ lệ hủy nhầm giảm còn 1,4%.

Bài học: Vấn đề không nằm ở icon nhỏ — icon nhỏ vẫn đẹp. Vấn đề là vùng chạm nhỏ và khoảng cách hẹp. Hai hành động có hậu quả trái ngược (hủy vs nhắn tin) mà đặt sát nhau là công thức cho lỗi. Nguyên tắc: hành động nguy hiểm phải có vùng chạm rộng rãi và tách biệt khỏi hành động thường dùng.

Ví dụ 2 — Sàn thương mại điện tử và bộ lọc trên mobile

Một sàn TMĐT phong cách Shopee/Lazada chạy audit accessibility và phát hiện phần "Bộ lọc" (filter) trên mobile có các checkbox màu sắc, kích cỡ chỉ 18×18px, xếp thành lưới với gap 6px. Người dùng lớn tuổi phản hồi rằng họ "không tick được đúng ô mình muốn", thường phải zoom màn hình lên mới chọn được.

Đội frontend áp dụng SC 2.5.8: họ giữ ô checkbox hiển thị 18px nhưng bọc mỗi ô trong một <label> có vùng chạm 44×44px, đồng thời tăng gap giữa các ô lên 12px để thỏa điều kiện spacing. Kết quả đo được qua session recording: thời gian trung bình để hoàn tất chọn bộ lọc giảm 22%, và số lần "tap-miss" (chạm hụt) giảm rõ rệt.

Bài học: Bạn không cần phóng to phần đồ họa để đạt chuẩn. Kỹ thuật "vùng chạm bao quanh label" cho phép giữ thiết kế gọn gàng mà vẫn đạt 44px. Đây là mẹo áp dụng được cho gần như mọi form checkbox/radio.

Ví dụ 3 — Ngân hàng số và bàn phím nhập mã PIN

Một app ngân hàng số ở Đông Nam Á (giả định tên VietPay) thiết kế bàn phím số ảo để nhập mã PIN 6 chữ số. Ban đầu, để giao diện "sang trọng", họ làm các phím số nhỏ (36×36px) với nhiều khoảng trắng thẩm mỹ. Bộ phận chăm sóc khách hàng ghi nhận nhiều người dùng lớn tuổi than phiền nhập sai PIN dẫn đến bị khóa tài khoản sau 3 lần sai.

Sau khi làm việc với chuyên gia accessibility, họ đặt mỗi phím số ở kích thước 56×56px (vượt cả mức AAA), khoảng cách 8px, và thêm phản hồi rung (haptic) nhẹ khi chạm. Số ca bị khóa tài khoản do nhập sai PIN giảm khoảng 40% trong quý sau đó.

Bài học: Với các thao tác quan trọng và lặp lại nhanh như nhập PIN, đừng chỉ đạt mức tối thiểu — hãy vượt chuẩn. 56px không phá vỡ thẩm mỹ, nhưng cứu được rất nhiều trải nghiệm bực bội. Accessibility và tính bảo mật/tin cậy đi cùng nhau.

Hướng dẫn từng bước

Dưới đây là quy trình bạn có thể áp dụng ngay cho bất kỳ giao diện nào.

Bước 1 — Xác định tất cả các phần tử tương tác. Liệt kê mọi thứ người dùng có thể chạm/click: nút, link dạng nút, icon-button, checkbox, radio, tab, các nút đóng (X), nút tăng/giảm số lượng, mũi tên carousel. Đừng bỏ sót các icon nhỏ ở góc.

Bước 2 — Đo vùng chạm hiện tại, không phải vùng nhìn. Trong DevTools trình duyệt, hover vào phần tử và xem kích thước box thực tế (bao gồm padding). Đây mới là touch target. Một nút icon <button> chỉ có icon 16px mà không padding thì vùng chạm chỉ 16px — chưa đạt.

Bước 3 — Áp mức tối thiểu 24px, hướng tới 44px. Với mọi target độc lập, đặt min-width và min-height. Ví dụ CSS cho một icon-button:

.icon-button {
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
}

Icon bên trong vẫn 16–24px, nhưng vùng chạm đã đủ lớn.

Bước 4 — Kiểm tra khoảng cách. Giữa hai target liền kề, đảm bảo có ít nhất 8px khoảng trống. Nếu vì lý do thiết kế phải giữ target dưới 24px, hãy tăng khoảng cách để thỏa điều kiện spacing của SC 2.5.8 (vòng tròn 24px quanh mỗi tâm không được chồng lên nhau).

Bước 5 — Kỹ thuật mở rộng vùng chạm mà không đổi thẩm mỹ. Khi thiết kế yêu cầu phần tử nhìn nhỏ (ví dụ nút X 20px), dùng pseudo-element để mở rộng vùng chạm vô hình:

.small-close-btn {
  position: relative;
}
.small-close-btn::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 44px;
  height: 44px;
  transform: translate(-50%, -50%);
}

Vùng ::before trong suốt nhưng vẫn nhận click, giúp target đạt 44px mà mắt vẫn thấy nút nhỏ.

Bước 6 — Với label bọc input. Cho checkbox/radio, luôn dùng <label> gắn với input và cho label vùng chạm rộng. Chạm vào label cũng kích hoạt input, nên vùng label chính là touch target.

Bước 7 — Kiểm thử thật. Mở giao diện trên điện thoại thật (không chỉ giả lập trên desktop). Thử chạm bằng ngón cái khi đang cầm điện thoại một tay. Nhờ một người lớn tuổi hoặc người có tay không linh hoạt thử — họ sẽ phát hiện lỗi bạn không thấy.

Lỗi thường gặp & mẹo

Lỗi 1 — Nhầm vùng nhìn với vùng chạm. Thiết kế icon 16px rồi tưởng vùng chạm là 16px. Luôn kiểm tra padding và kích thước box thực tế.

Lỗi 2 — Nút text nhỏ trên desktop bị bỏ qua. Nhiều người nghĩ touch target chỉ cho mobile. Nhưng SC 2.5.8 áp dụng cho mọi pointer input, kể cả chuột và màn hình cảm ứng laptop. Nút link "Xem thêm" cao 18px trên desktop vẫn có thể vi phạm.

Lỗi 3 — Đặt hai hành động đối nghịch sát nhau. "Lưu" cạnh "Xóa", "Xác nhận" cạnh "Hủy" mà không có khoảng cách — công thức gây tai họa. Tách biệt và cho hành động phá hủy vùng chạm rõ ràng.

Lỗi 4 — Chỉ đạt đúng 24px rồi dừng. 24px là sàn, không phải mục tiêu. Với các nút chính, hướng tới 44–48px để trải nghiệm mượt cho tất cả.

Lỗi 5 — Bỏ qua các icon-button dày đặc trên toolbar. Thanh công cụ với 8 icon 20px sát nhau là điểm nóng vi phạm. Giãn ra hoặc gộp bớt.

Mẹo:

  • Mẹo về ngón cái: Vùng dưới cùng màn hình (thumb zone) dễ chạm nhất khi cầm một tay — đặt hành động chính ở đó và cho nó target lớn.
  • Mẹo kiểm tra nhanh: Cài extension như axe DevTools hoặc dùng Lighthouse; chúng có thể cảnh báo target nhỏ. (Chi tiết công cụ ở Bài 37.)
  • Mẹo Figma: Trong file thiết kế, tạo một component "touch guide" là ô vuông 44×44px trong suốt, kéo phủ lên các nút để kiểm tra trực quan trước khi giao cho dev.
  • Mẹo cho carousel/slider: Các nút mũi tê nhỏ là nạn nhân kinh điển — luôn cho chúng ít nhất 44px.

Bài tập thực hành

  • Audit một app bạn dùng hằng ngày. Mở một app Việt Nam bất kỳ (ví dụ MoMo, ZaloPay, Grab). Chụp màn hình 3 giao diện. Dùng thước đo trên ảnh hoặc DevTools để ước lượng vùng chạm của 5 nút. Ghi lại nút nào dưới 24px, nút nào dưới 44px.
  • Sửa một component thật. Lấy một icon-button nhỏ trong dự án của bạn (hoặc tạo mới một nút X 20px). Viết CSS để đưa vùng chạm lên 44×44px bằng cả hai cách: (a) dùng padding, (b) dùng pseudo-element ::before. So sánh ưu nhược điểm.
  • Thiết kế lại một hàng nút nguy hiểm. Cho một dòng có 3 nút: "Chia sẻ", "Chỉnh sửa", "Xóa" đang sát nhau (gap 4px, mỗi nút 28px). Thiết kế lại sao cho đạt SC 2.5.8: đủ kích thước và đủ khoảng cách, đồng thời tách "Xóa" ra để tránh chạm nhầm. Vẽ phác hoặc dựng bằng HTML/CSS.
  • Kiểm thử với người thật. Nhờ một người trên 55 tuổi hoặc người có tay không linh hoạt thử chạm vào giao diện bạn vừa sửa và giao diện gốc. Ghi lại số lần chạm hụt của mỗi phiên bản. Bạn sẽ thấy con số nói lên tất cả.

Tóm tắt

Touch target là vùng người dùng chạm để kích hoạt hành động — và nó thường lớn hơn phần đồ họa nhìn thấy. Hãy khắc ghi hai con số: 24×24 CSS pixel là mức tối thiểu bắt buộc (WCAG 2.2 SC 2.5.8, mức AA), và 44×44 CSS pixel là mục tiêu lý tưởng (WCAG 2.1 SC 2.5.5, mức AAA). Đo bằng CSS pixel, không phải pixel vật lý.

Ba nguyên tắc vàng: (1) tăng vùng chạm chứ không nhất thiết tăng phần đồ họa — dùng padding hoặc pseudo-element; (2) giữ khoảng cách tối thiểu 8px giữa các target, và tách biệt hẳn các hành động phá hủy; (3) đừng dừng ở mức tối thiểu cho các nút quan trọng. Như các ví dụ GoRide, sàn TMĐT và VietPay cho thấy, chỉ vài chục pixel chênh lệch có thể là ranh giới giữa một trải nghiệm mượt mà và một cơn ức chế khiến người dùng bỏ đi. Target lớn hơn không chỉ giúp người khuyết tật — nó giúp tất cả mọi người, trong mọi hoàn cảnh cầm điện thoại thực tế.

Học xong bài này rồi? Tạo tài khoản miễn phí để lưu lại — lần sau vào là biết ngay đang dở ở đâu, và học hết khóa thì có chứng chỉ. Lưu tiến độ của tôi