Nawigacja scrollspy to popularny wzorzec interfejsu, który automatycznie wyróżnia link nawigacyjny odpowiadający sekcji strony aktualnie widocznej w obszarze widoku. Dzięki temu użytkownicy mogą łatwo sprawdzić, w którym miejscu długiego dokumentu się znajdują, gdy go przewijają.
Ten wzorzec jest typowy w 2 przypadkach:
- Witryny z pojedynczą stroną: w których główna nawigacja prowadzi do różnych sekcji pojedynczej strony, a nie do osobnych adresów URL.
- Długie treści: gdy spis treści lub pasek boczny śledzi postępy użytkownika w artykule, przewodniku lub dokumentacji.
Jak to zrobić?
Tradycyjnie wzorzec scrollspy wymagał JavaScriptu i interfejsu API IntersectionObserver. Nowoczesny CSS zapewnia natywny sposób osiągnięcia tego celu za pomocą właściwości scroll-target-group i pseudoklasy :target-current.
- Upewnij się, że linki nawigacyjne używają identyfikatorów fragmentów: nawigacja musi składać się z linków do kotwic (
<a>), które wskazują sekcje na tej samej stronie za pomocą identyfikatorów fragmentów (np.<a href="#section-1">) odpowiadających atrybutowiidsekcji treści. - Włącz grupowanie elementów docelowych przewijania: zastosuj właściwość
scroll-target-group: autodo kontenera linków nawigacyjnych. Dzięki temu przeglądarka traktuje te linki jako znaczniki, które śledzą odpowiednie cele. - Styl aktywnego linku: użyj pseudoklasy
:target-currentw linkach nawigacyjnych, aby zastosować style, gdy ich sekcja docelowa jest widoczna w kontenerze przewijania. - Stan semantyczny: użyj skryptu, aby zaktualizować
aria-current="true"w aktywnym linku, gdy przewijanie się zatrzyma, aby stan był prawidłowo przekazywany do technologii wspomagających osoby z niepełnosprawnością.
Przykładowy kod
W tym przykładzie aktywny link w stałym menu nawigacyjnym jest podświetlany, gdy użytkownik przewija sekcje.
/* 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>
Sprawdzone metody
- UŻYWAJ atrybutu
scroll-target-group: autow dedykowanym kontenerze linków nawigacyjnych: dzięki temu przeglądarka będzie wiedzieć, które linki powinny być śledzone. - UPEWNIJ SIĘ, że cele mają unikalne atrybuty
idpasujące do atrybutówhreflinków. - ZAPEWNIJ wystarczającą ilość miejsca w pionie na sekcje:
scroll-target-groupnajdokładniej identyfikuje widoczny cel, gdy sekcje są na tyle duże, że jednocześnie widoczne są tylko 1 lub 2 z nich. - OBOWIĄZKOWE: ze względu na ułatwienia dostępu stan wizualny musi być odzwierciedlony za pomocą
aria-current.:target-currentobsługuje aspekt wizualny, ale nie jest on widoczny dla czytników ekranu. - AVOID polegania wyłącznie na kolorze w przypadku stanu aktywnego: dodaj inne wskazówki wizualne, takie jak grubość czcionki, podkreślenie lub kropka, albo upewnij się, że kontrast między kolorami jest wystarczający, aby różnica była widoczna dla użytkowników z zaburzeniami rozpoznawania barw.
Strategie zastępcze
W przypadku przeglądarek, które nie obsługują scroll-target-group, należy użyć kreacji zastępczej opartej na interfejsie 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>