پیمایش scrollspy یک الگوی رایج میانای کاربری است که بهطور خودکار پیوند پیمایش مربوط به بخشی از صفحه را که درحالحاضر در نمای دید است برجسته میکند. این کار به کاربران حس واضحی از جایی که در سند طولانی هستند هنگام پیمایش میدهد.
این الگو در دو سناریو رایج است:
- وبسایتهای تکصفحهای: جایی که پیمایش سایت اصلی بهجای نشانیهای وب جداگانه به بخشهای مختلف یک صفحه پیوند میدهد.
- محتوای طولانی: جایی که فهرست مطالب یا ناوشهای نوار کناری پیشرفت کاربر را در مقاله، راهنما، یا سند ردیابی میکند.
نحوه پیادهسازی
scrollspy بهطور سنتی به جاوا اسکریپت و میانای برنامهسازی کاربردی IntersectionObserver نیاز داشت. CSS مدرن روشی بومی برای دستیابی به این هدف بااستفاده از ویژگی scroll-target-group و شبهکلاس :target-current ارائه میدهد.
- مطمئن شوید پیوندهای پیمایش از شناسههای قطعه استفاده میکنند: پیمایش شما باید شامل پیوندهای ثابت (
<a>) باشد که بااستفاده از شناسههای قطعه (مثلاً<a href="#section-1">) که باidبخشهای محتوای شما مطابقت دارند، به بخشهایی در همان صفحه اشاره میکنند. - فعال کردن Scroll Target Grouping: ویژگی
scroll-target-group: autoرا به محفظه پیوندهای پیمایش خود اعمال کنید. این کار به مرورگر میگوید که این پیوندها را بهعنوان نشانگرهایی درنظر بگیرد که اهداف مربوطه را ردیابی میکنند. - سبکدهی به پیوند فعال: از کلاس کاذب
:target-currentدر پیوندهای پیمایش خود استفاده کنید تا سبکها را زمانی که بخش هدف آنها در محفظه پیمایش قابلمشاهده است، اعمال کنید. - وضعیت معنایی: از یک اسکریپت برای بهروزرسانی
aria-current="true"در پیوند فعال هنگام توقف پیمایش استفاده کنید تا مطمئن شوید که وضعیت بهدرستی به فناوریهای کمکی منتقل میشود.
کد نمونه
این مثال پیوند فعال را در منوی پیمایش ثابت برجسته میکند، درحالیکه کاربر در بخشها پیمایش میکند.
/* 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>
روالهای مطلوب
- باید از
scroll-target-group: autoدر محفظه اختصاصی برای پیوندهای پیمایش استفاده کنید: این کار باعث میشود مرورگر بداند کدام پیوندها باید ردیابی شوند. - باید مطمئن شوید که هدفها دارای مشخصههای
idمنحصربهفردی هستند که با مشخصههایhrefپیوندها مطابقت دارند. - باید فضای عمودی کافی برای بخشها فراهم کنید:
scroll-target-groupزمانی هدف قابلمشاهده را بهوضوح شناسایی میکند که بخشها بهاندازه کافی بزرگ باشند تا فقط یک یا دو بخش در یک زمان قابلمشاهده باشد. - اجباری: برای دسترسپذیری، وضعیت دیداری باید با
aria-currentمنعکس شود. درحالیکه:target-currentجنبه بصری را مدیریت میکند، این مورد برای صفحهخوانها آشکار نمیشود. - از تکیه کردن صرف به رنگ برای حالت فعال AVOID: از نشانههای دیداری دیگر مانند وزن قلم، خط زیرین، یا نقطه نشانگر استفاده کنید، یا مطمئن شوید که تضاد کافی بین رنگها وجود دارد تا تفاوت برای کاربران دارای نقص بینایی رنگ قابلدسترس باشد.
راهبردهای جایگزین
برای مرورگرهایی که از scroll-target-group پشتیبانی نمیکنند، باید از یک جایگزین مبتنی بر میانای برنامهسازی کاربردی 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>