Thanh điều hướng theo dõi cuộn là một mẫu giao diện người dùng phổ biến, tự động làm nổi bật đường liên kết điều hướng tương ứng với phần của trang hiện đang nằm trong khung nhìn. Điều này giúp người dùng biết rõ vị trí của họ trong một tài liệu dài khi họ di chuyển.
Mẫu này thường gặp trong hai trường hợp:
- Trang web một trang: Trang web có trình đơn điều hướng chính liên kết đến các phần khác nhau của một trang duy nhất thay vì các URL riêng biệt.
- Nội dung dài: Trong đó mục lục hoặc điều hướng bằng thanh bên theo dõi tiến trình của người dùng thông qua một bài viết, hướng dẫn hoặc tài liệu.
Cách triển khai
Thông thường, mẫu scrollspy yêu cầu JavaScript và API IntersectionObserver. CSS hiện đại cung cấp một cách gốc để đạt được điều này bằng cách sử dụng thuộc tính scroll-target-group và lớp giả :target-current.
- Đảm bảo đường liên kết điều hướng sử dụng giá trị nhận dạng mảnh: Hoạt động điều hướng phải bao gồm các đường liên kết neo (
<a>) trỏ đến các phần trên cùng một trang bằng cách sử dụng giá trị nhận dạng mảnh (ví dụ:<a href="#section-1">) khớp vớiidcủa các phần nội dung. - Bật tính năng Nhóm mục tiêu cuộn: Áp dụng thuộc tính
scroll-target-group: autocho vùng chứa của các đường liên kết điều hướng. Điều này cho trình duyệt biết rằng các đường liên kết này là điểm đánh dấu theo dõi mục tiêu tương ứng. - Tạo kiểu cho đường liên kết đang hoạt động: Sử dụng lớp giả
:target-currenttrên các đường liên kết điều hướng để áp dụng kiểu khi phần mục tiêu của các đường liên kết đó xuất hiện trong vùng chứa cuộn. - Trạng thái ngữ nghĩa: Sử dụng tập lệnh để cập nhật
aria-current="true"trên đường liên kết đang hoạt động khi thao tác cuộn dừng lại để đảm bảo trạng thái được truyền đạt chính xác đến các công nghệ hỗ trợ.
Mã mẫu
Ví dụ này làm nổi bật đường liên kết đang hoạt động trong trình đơn điều hướng cố định khi người dùng di chuyển qua các mục.
/* MANDATORY: The container of markers must have scroll-target-group: auto */
nav {
/* Enables automatic tracking of fragment links */
scroll-target-group: auto;
}
/* MANDATORY: Use :target-current to style the link whose target is in view. */
nav a:target-current {
color: var(--accent, #007bff);
border-bottom-color: var(--accent, #007bff);
}
<nav>
<a href="#intro">Introduction</a>
<a href="#features">Features</a>
<a href="#pricing">Pricing</a>
</nav>
<main>
<!-- MANDATORY: Each section must have a unique ID matching a link fragment in the <nav>. -->
<section id="intro">
<h2>Introduction</h2>
<!-- content -->
</section>
<section id="features">
<h2>Features</h2>
<!-- content -->
</section>
<section id="pricing">
<h2>Pricing</h2>
<!-- content -->
</section>
</main>
<script type="module">
if (CSS.supports('scroll-target-group: auto')) {
const syncAriaCurrent = () => {
const currentLink = document.querySelector('nav a:target-current');
document.querySelectorAll('nav a').forEach(link => {
link.setAttribute('aria-current', link === currentLink ? 'true' : 'false');
});
};
// Update the aria on initial page load. Ensure the DOM content is loaded, either by using `<script type="module">` or an event listener for `DOMContentLoaded`.
syncAriaCurrent();
// Update the aria after scroll ends
document.addEventListener('scrollend', syncAriaCurrent);
}
</script>
Các phương pháp hay nhất
- NÊN sử dụng
scroll-target-group: autotrên một vùng chứa riêng cho các đường liên kết điều hướng: Việc này giúp trình duyệt biết được những đường liên kết nào cần theo dõi. - NÊN đảm bảo các mục tiêu có thuộc tính
idriêng biệt khớp với thuộc tínhhrefcủa đường liên kết. - NÊN cung cấp đủ không gian dọc cho các phần:
scroll-target-groupxác định rõ nhất mục tiêu hiển thị khi các phần đủ lớn để chỉ hiển thị một hoặc hai phần cùng một lúc. - BẮT BUỘC: Để hỗ trợ tiếp cận, trạng thái hình ảnh phải được phản ánh bằng
aria-current. Mặc dù:target-currentxử lý khía cạnh hình ảnh, nhưng trình đọc màn hình không hiển thị thông tin này. - AVOID chỉ dựa vào màu sắc cho trạng thái đang hoạt động: Thêm các dấu hiệu hình ảnh khác như độ đậm phông chữ, dấu gạch dưới hoặc dấu chấm chỉ báo, hoặc đảm bảo có đủ độ tương phản giữa các màu để người dùng bị mù màu có thể nhận ra sự khác biệt.
Chiến lược dự phòng
Đối với những trình duyệt không hỗ trợ scroll-target-group, bạn nên sử dụng phương án dự phòng dựa trên API IntersectionObserver.
<script>
// Feature detection for scroll-target-group
const supportsScrollTargetGroup = CSS.supports('scroll-target-group: auto');
if (!supportsScrollTargetGroup) {
const navLinks = document.querySelectorAll('nav a');
const sections = document.querySelectorAll('main section');
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const id = entry.target.getAttribute('id');
navLinks.forEach(link => {
const isActive = link.getAttribute('href') === `#${id}`;
// Use the escaped colon class for consistent styling
link.classList.toggle('\:target-current', isActive);
link.setAttribute('aria-current', isActive);
});
}
});
}, { rootMargin: '-50% 0px -50% 0px', threshold: 0 });
sections.forEach(section => observer.observe(section));
}
</script>
<style>
/* Fallback style if :target-current is not supported.
Use :is() to combine the native pseudo-class with a fallback class for older browsers. DO NOT use `nav a:target-current, nav a.\:target-current, as the unrecognized pseudoselector invalidates the entire rule in older browsers. */
nav a:is(:target-current, .\:target-current) {
color: var(--accent, #007bff);
border-bottom-color: var(--accent, #007bff);
font-weight: bold;
}
</style>