Trình tạo tab CSS

Tiếp theo

Tab xuất hiện ở khắp mọi nơi – trong cửa sổ cài đặt, trang tài liệu hay thư viện sản phẩm. HTML thuần không có thành phần tab riêng, nên các nhà phát triển tự dựng lấy. Trình tạo này dựng một thanh tab đơn giản bằng HTML + CSS: màu nhấn cho tab đang hoạt động, bo góc cho các nút và trạng thái di chuột. Dán mã đánh dấu vào dự án của bạn và kết nối việc chuyển tab với JavaScript tự viết.

Cách tạo tab

  1. 1

    Chọn màu nhấn

    Màu nền và màu chữ của tab đang hoạt động. Hãy chọn màu phù hợp với thương hiệu của bạn.

  2. 2

    Đặt độ bo góc

    Bo tròn các góc trên của nút tab. Giá trị lớn hơn tạo cảm giác mềm mại hơn.

  3. 3

    Chỉnh nhãn

    Kết quả gồm ba nút "Overview", "Details" và "Settings": hãy đổi tên cho khớp với nội dung của bạn.

  4. 4

    Sao chép mã

    Phần đánh dấu tab đi kèm khối <style> riêng. Dán cả hai vào trang của bạn.

  5. 5

    Thêm thao tác chuyển tab

    Trình tạo chỉ tạo phần hiển thị. Hãy kết nối các nút với JavaScript hoặc thư viện UI của riêng bạn để hiện và ẩn bảng nội dung.

Đánh dấu (markup) dễ truy cập đúng cách

<div class="tabs">
  <div role="tablist" aria-label="Product info">
    <button role="tab" id="tab-1" aria-selected="true"  aria-controls="panel-1" tabindex="0">Overview</button>
    <button role="tab" id="tab-2" aria-selected="false" aria-controls="panel-2" tabindex="-1">Specs</button>
    <button role="tab" id="tab-3" aria-selected="false" aria-controls="panel-3" tabindex="-1">Reviews</button>
  </div>
  <section role="tabpanel" id="panel-1" aria-labelledby="tab-1">...</section>
  <section role="tabpanel" id="panel-2" aria-labelledby="tab-2" hidden>...</section>
  <section role="tabpanel" id="panel-3" aria-labelledby="tab-3" hidden>...</section>
</div>

Các thuộc tính then chốt:

  • role="tablist" bao quanh các nút bấm.
  • Mỗi nút có role="tab", kèm aria-selectedaria-controls.
  • tabindex dùng mẫu roving tabindex: chỉ tab đang hoạt động là 0, các tab khác là -1. Phím mũi tên di chuyển tiêu điểm giữa chúng.
  • Mỗi panel có role="tabpanel", với aria-labelledby trỏ về tab của nó.
  • hidden đặt trên các panel không hoạt động (không chỉ display: none, công nghệ hỗ trợ dựa vào chính thuộc tính này).

Quy ước bàn phím

Phím Hành động
Tab Di chuyển vào / ra khỏi danh sách tab
ArrowLeft Tab trước (vòng về tab cuối)
ArrowRight Tab tiếp theo (vòng về tab đầu)
Home Tab đầu tiên
End Tab cuối cùng
Enter / Space Kích hoạt tab đang có tiêu điểm (khi kích hoạt thủ công)

Kích hoạt tự động (tab chuyển khi tiêu điểm di chuyển) so với thủ công (tiêu điểm di chuyển, tab kích hoạt khi nhấn Enter) – WAI-ARIA cho phép cả hai. Cách tự động dễ dùng hơn cho người dùng nhìn thấy; cách thủ công tốt hơn khi nội dung tab nặng để hiển thị.

Kiểu gạch dưới

[role="tablist"] {
  display: flex;
  border-bottom: 1px solid #e5e7eb;
}
[role="tab"] {
  padding: 0.75rem 1rem;
  background: transparent;
  border: 0;
  color: #6b7280;
  position: relative;
  cursor: pointer;
}
[role="tab"][aria-selected="true"] {
  color: #111827;
}
[role="tab"][aria-selected="true"]::after {
  content: "";
  position: absolute;
  left: 1rem; right: 1rem; bottom: -1px;
  height: 2px;
  background: #2563eb;
}

Kiểu viên thuốc

[role="tab"] {
  padding: 0.5rem 0.9rem;
  border-radius: 9999px;
  border: 0;
  background: transparent;
}
[role="tab"][aria-selected="true"] {
  background: #2563eb;
  color: #fff;
}

Tiêu điểm hiển thị rõ

Hãy luôn vẽ vòng tiêu điểm khi tiêu điểm đến từ bàn phím:

[role="tab"]:focus-visible {
  outline: 2px solid #60a5fa;
  outline-offset: 2px;
}

JavaScript

Gần đúng như:

const tabs = document.querySelectorAll('[role="tab"]');
tabs.forEach(tab => {
  tab.addEventListener('click', () => activate(tab));
  tab.addEventListener('keydown', e => {
    const i = [...tabs].indexOf(tab);
    if (e.key === 'ArrowRight') tabs[(i + 1) % tabs.length].focus();
    if (e.key === 'ArrowLeft')  tabs[(i - 1 + tabs.length) % tabs.length].focus();
    if (e.key === 'Home') tabs[0].focus();
    if (e.key === 'End')  tabs[tabs.length - 1].focus();
  });
});

function activate(tab) {
  tabs.forEach(t => {
    const panel = document.getElementById(t.getAttribute('aria-controls'));
    const active = t === tab;
    t.setAttribute('aria-selected', active);
    t.setAttribute('tabindex', active ? '0' : '-1');
    panel.hidden = !active;
  });
  tab.focus();
}

Tổng cộng ba mươi dòng, không phụ thuộc thư viện nào.

Tab và accordion

Trên màn hình hẹp, các hàng tab trở nên chật chội. Mẫu phổ biến: tab trên máy tính để bàn, accordion trên di động. Hãy dùng container query hoặc media query để đổi cách trình bày trực quan mà không thay đổi các vai trò ARIA.

Câu hỏi thường gặp

Với tab dễ truy cập thì có. Nếu thiếu role="tablist"role="tab", trình đọc màn hình sẽ coi các nút như nút thông thường và người dùng mất đi quy ước điều hướng tab. Phương án thay thế là một accordion <details> / <summary> đơn giản, vốn có sẵn ngữ nghĩa.

Chế độ tự động (tab kích hoạt khi tiêu điểm di chuyển) phù hợp khi nội dung mỗi tab nhẹ nhàng để hiển thị. Chế độ thủ công (tiêu điểm di chuyển, nhấn Enter để kích hoạt) tốt hơn khi việc chuyển tab kích hoạt tác vụ nặng như tải hoặc dựng một biểu mẫu lớn.

Với các tab mang nội dung (tài liệu, tab sản phẩm) thì nên: dùng một hash (#specs) hoặc tham số truy vấn để liên kết có thể dẫn thẳng đến một tab cụ thể và tab đang hoạt động được giữ nguyên sau mỗi lần tải lại. Với tab giao diện (khung cài đặt), URL là tùy chọn.

Chỉ với thủ thuật checkbox/radio, vốn thiếu điều hướng bằng phím mũi tên và không có trạng thái ARIA. Để có một triển khai thực sự dễ truy cập, đoạn JS nhỏ này rất đáng dùng. Nếu bạn cần phương án dự phòng dựng từ máy chủ, hãy liên kết mỗi tab với một URL riêng và dựng panel tương ứng ở phía máy chủ.

Công cụ liên quan

Công cụ này có phiên bản bằng các ngôn ngữ khác