در گذشته، ساخت یک اسلایدر با CSS تقریباً غیرممکن بود و توسعه‌دهندگان مجبور بودند از جاوااسکریپت و کتابخانه‌های جانبی استفاده کنند؛ رویکردی که معمولاً با چالش‌هایی مثل کاهش عملکرد، محدودیت در سفارشی‌سازی و مشکلات دسترسی‌پذیری همراه بود. حتی با وجود بهترین پلاگین‌ها، همچنان مدیریت فوکوس، پشتیبانی از فناوری‌های کمکی و کنترل رفتار پیمایش (اسنپ) نیازمند کدنویسی دستی بود.

در این مقاله، به بررسی ویژگی‌های مدرن CSS می‌پردازیم که امکان ساخت اسلایدرهای کاملاً کاربردی تنها با CSS را فراهم کرده‌اند، بدون نیاز به جاوااسکریپت و با حفظ دسترسی‌پذیری بالا.

چه قابلیت‌های جدیدی در CSS برای ساخت اسلایدر ارائه شده‌اند؟

CSS پیش‌تر هم قابلیت‌هایی برای ایجاد ناحیه قابل اسکرول داشت؛ مثلاً با استفاده از overflow و ویژگی‌های اسنپ مانند scroll-snap-type و scroll-snap-align. اما این ویژگی‌ها راهکاری برای پیمایش فعال توسط کاربر فراهم نمی‌کردند.

نسخه ۱۳۵ مرورگر Chrome دو pseudo-element جدید به نام‌های ::scroll-button و ::scroll-marker() و همچنین یک pseudo-class جدید به نام :target-current را معرفی کرده که به‌طور خاص برای المنت‌های مرتبط با اسکرول طراحی شده‌اند.

pseudo-element ::scroll-button()

::scroll-button امکان ساخت دکمه‌های قابل تعامل برای اسکرول را به عنوان pseudo-element فراهم می‌کند. این دکمه‌ها فقط زمانی درون یک کانتینر اسکرول ایجاد می‌شوند که مقدار content آن‌ها چیزی غیر از none باشد. این دکمه‌ها به صورت المنت‌های <button> در کنار nodeهای child ظاهر می‌شوند.

از آنجایی که این دکمه‌ها رفتار و ویژگی‌های پیش‌فرض المنت‌های دکمه معمولی را به ارث می‌برند، می‌توان آن‌ها را به‌طور دلخواه استایل‌دهی و موقعیت‌دهی کرد.

این دکمه‌های اسکرول به کاربران اجازه می‌دهند تا در یک جهت خاص، چپ، راست، بالا یا پایین، درون ناحیه اسکرول حرکت کنند. به‌صورت پیش‌فرض، هر کلیک تقریباً ۸۵٪ از ناحیه قابل مشاهده را اسکرول می‌کند. البته می‌توانیم این رفتار را با استفاده از ویژگی‌های اسنپ کردن و اهداف مشخص شده تغییر دهیم. یک اسکرول کانتینر می‌تواند حداکثر چهار دکمه اسکرول متمایز داشته باشد که هر کدام به یک جهت خاص متصل هستند.

سینتکس بیسیک آن به صورت زیر می‌باشد:

::scroll-button(<scroll-button-direction>) {
}

مقدار <scroll-button-direction> می‌تواند یکی از موارد زیر باشد:

این pseudo-element تنها زمانی قابل مشاهده است که مقدار content آن به‌طور صریح تنظیم شده باشد. برای نمونه، در ادامه نحوه افزودن یک دکمه اسکرول برای حرکت به چپ را مشاهده می‌کنیم:

div::scroll-button(left) {
  content: "Button";
}

اگر بخواهیم دکمه‌های اسکرول برای تمام جهات نمایش داده شوند:

div::scroll-button(*) {
  content: "Button";
}

با این کار، چهار دکمه اسکرول ساخته می‌شود که هر کدام برای یک جهت متفاوت عمل می‌کنند.

برای استایل‌دهی، می‌توانیم از pseudo-classهای معمول مانند :enabled و :disabled استفاده کنیم. زمانی که به انتهای ناحیه اسکرول در یک جهت برسیم، دکمه مربوط به آن جهت به‌طور خودکار غیرفعال می‌شود. همچنین می‌توانیم این دکمه‌ها را به دلخواه استایل‌دهی کنیم، از جمله رنگ، افکت‌های hover و غیره.

pseudo-element ::scroll-marker()

pseudo-element ::scroll-marker نشان دهنده یک marker بصری است که به یک اسلاید یا آیتم قابل پیمایش درون یک کانتینر اسکرول متصل می‌شود. کاربران می‌توانند با کلیک روی این marker، به آیتم مورد نظر هدایت شوند یا از آن برای مشاهده میزان پیشرفت پیمایش استفاده کنند؛ درست مانند یک progress bar.

تمام markerها در یک کانتینر گروه‌بندی می‌شوند که توسط pseudo-element ::scroll-marker-group نمایش داده می‌شود.

اسکرول markerها تنها زمانی تولید می‌شوند که مقدار ویژگی content آن‌ها چیزی غیر از none باشد؛ دقیقاً مشابه دکمه‌های اسکرول. تعداد این markerها به تعداد المنت‌های child موجود در کانتینر بستگی دارد. موقعیت قرارگیری گروه markerها نیز با ویژگی scroll-marker-group کنترل می‌شود و می‌تواند قبل یا بعد از محتوای کانتینر قرار گیرد.

سینتکس آن به شکل زیر می‌باشد:

::scroll-marker {
  content: <marker-content>;
}

مقدار <marker-content> می‌تواند شامل متن، شمارنده یا آیکون باشد، به‌شرطی که مقدار آن برابر با none نباشد. این ویژگی انعطاف‌پذیری بالایی برای طراحی اسلایدر با CSS فراهم می‌کند؛ از جمله استفاده از تب‌ها، تصاویر کوچک پیش‌نمایش (تصاویر بندانگشتی) یا هر طرح دلخواه دیگر. به عنوان نمونه، می‌توان با استفاده از مقدار content: "" و یک پس‌زمینه تصویری، یک marker تصویری برای اسلایدر طراحی کرد.

در ادامه نمونه‌ای بیسیک با یک کانتینر اسکرول و چند marker را مشاهده می‌کنیم:

<div>
  <div class="slide">Slide 1</div>
  <div class="slide">Slide 2</div>
  <div class="slide">Slide 3</div>
</div>


div {
  display: flex;
  gap: 10px;
  padding: 10px;
  overflow-x: auto;
  scroll-marker-group: after;
}
.slide {
  background-color: #e2e2e2;
  height: 250px;
  min-width: 90%;
  padding-top: 20px;
}

.slide::scroll-marker {
  content: "";
  border: 1px solid red;
  height: 1em;
  width: 1em;
}

div::scroll-marker-group {
  display: flex;
  gap: 10px;
  margin-left: 10px;
}

خروجی در این لینک قابل مشاهده می‌باشد.

این رابط کاربری بسیار ساده‌ای است، اما کار می‌کند. می‌توانیم با افزودن ویژگی‌هایی مانند اسنپ کردن اسکرول و فعال‌سازی اسکرول smooth، ظاهر آن را تا حد زیادی بهبود دهیم؛ هرچند این موارد را در ادامه بررسی خواهیم کرد. تنها نقطه ضعف فعلی چیست؟ هیچ راهی برای تشخیص اینکه کدام marker در حال حاضر فعال است وجود ندارد. در بخش بعدی، دقیقاً همین موضوع را بررسی می‌کنیم.

pseudo-class :target-current

pseudo-class :target-current به ما این امکان را می‌دهد تا marker اسکرولی که در حال حاضر فعال است، استایل‌دهی کنیم. این کلاس فقط روی ::scroll-marker اعمال می‌شود و به نمایان سازی آیتمی که در حال حاضر در ناحیه دید قرار دارد، کمک می‌کند.

در حقیقت، این کلاس به آن ::scroll-marker اشاره دارد که در موقعیت فعلی اسکرول، هم‌تراز شده و درون گروه scroll-marker-group قرار دارد.

نمونه‌ای ساده از استفاده از این pseudo-class به شرح زیر می‌باشد:

::scroll-marker:target-current {
  background-color: red;
}

خروجی در این لینک قابل مشاهده است.

ساخت اسلایدر با CSS

اکنون که با قابلیت‌های جدید آشنا شدیم، وقت آن است که تمام این ویژگی‌ها را با هم ترکیب کرده و یک اسلایدر کامل با CSS بسازیم. در این مرحله، تمرکز اصلی ما بر استایل‌دهی و بهبود تجربه کاربری خواهد بود؛ چراکه عملکرد اصلی دکمه‌ها و markerها پیش‌تر بررسی شده است.

تعریف کانتینر اسکرول برای نمایش اسلایدها

در ابتدا یک کانتینر اسکرول‌پذیر با اسکرول افقی ایجاد می‌کنیم. برای اطمینان از اینکه هر اسلاید در جای مناسب خود قرار می‌گیرد، از ویژگی scroll-snap-type استفاده می‌شود. همچنین برای ساده‌تر و حرفه‌ای‌تر شدن رابط کاربری، نوار اسکرول را مخفی می‌کنیم. این یکی از مراحل کلیدی در طراحی یک اسلایدر با CSS بدون جاوااسکریپت است.

.carousel {
  width: 80%;
  display: flex;
  gap: 10px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-marker-group: after; 
  position: relative;
}

.carousel::-webkit-scrollbar { 
   display: none;  
   scrollbar-width: none;  
}

همچنین می‌توانیم اسکرول smooth را روی این کانتینر فعال کنیم، اما توجه به ترجیحات کاربر در این زمینه اهمیت دارد:

@media (prefers-reduced-motion: no-preference) {
  .carousel {
    scroll-behavior: smooth;
  }
}

سپس، المان‌های اسلاید را تعریف می‌کنیم. استفاده از ویژگی scroll-snap-align: center باعث می‌شود هر اسلاید هنگام اسکرول، در مرکز ناحیه دید قرار گیرد.

نکته: اگر می‌خواهیم دکمه‌های اسکرول، هر بار فقط یک اسلاید را جابه‌جا کنند، باید علاوه بر scroll-snap-type: x mandatory (که از قبل در مثال اعمال شده)، ویژگی scroll-snap-stop: always را هم باید به اسلاید اضافه کنیم:

.slide {
  scroll-snap-align: center;
  height: 250px;
  min-width: 400px;
}

افزودن دکمه‌های اسکرول بدون جاوااسکریپت

اکنون نوبت آن است که دکمه‌هایی برای پیمایش اسلایدر اضافه کنیم. این بار از آیکون‌ها به‌عنوان content دکمه‌ها استفاده کرده و آن‌ها را در لبه‌های افقی قرار می‌دهیم. اگرچه ویژگی «anchor positioning» در CSS ابزار مفیدی برای این نوع جای‌گذاری است، اما به دلیل پشتیبانی محدود مرورگرها، در این مقاله از موقعیت‌دهی relative و absolute بهره می‌گیریم تا سازگاری بیشتری با مرورگرها داشته باشیم.

.carousel::scroll-button(left) {
  content: "<" / "Prev";
  left: 5%;
}

.carousel::scroll-button(right) {
  content: "˃" / "Next";
  right: 5%;
}

.carousel::scroll-button(*){
  position: absolute;
  top: 160px;
  cursor: pointer;
}

همچنین می‌توانیم وضعیت‌های مختلف دکمه‌ها مانند hover و disabled را سفارشی کنیم. pseudo-class :disabled به‌صورت خودکار زمانی که به ابتدای یا انتهای کانتینر اسکرول می‌رسیم، دکمه مربوطه را غیرفعال می‌کند:

.carousel::scroll-button(*):hover{
  background-color: #e1e1e1;
}
.carousel::scroll-button(*):disabled{
  opacity: 0.2;
  color: #000;
}

نشانه‌گذاری اسلایدها با استفاده از اسکرول markerها

در نهایت، نوبت به اضافه کردن markerها می‌رسد. با فعال‌سازی گروه markerها و استایل‌دهی به markerهای تکی، این بخش را کامل می‌کنیم. برای مرکز قرار دادن گروه markerها از موقعیت‌دهی absolute استفاده می‌کنیم. البته ویژگی anchor positioning نیز گزینه‌ای جذاب است که در آینده می‌توان به آن پرداخت.

.carousel::scroll-marker-group {
  display: flex;
  gap: 10px;
  position: absolute;
  left: 50%;
  margin-top: 25px;
  transform: translateX(-50%);
}

.slide::scroll-marker {
  content: "";
  border: 1px solid #424242;
  border-radius: 50%;
  height: 20px;
  width: 20px;
  transition: 0.1s all ease-in-out;
}

در ادامه می‌توانیم marker فعال و حالت‌هایی مثل hover را نیز استایل‌دهی کنیم:

.slide::scroll-marker:hover {
  background-color: #e3e3e3;
}
.slide::scroll-marker:target-current {
  background-color: #424242;
}

نتیجه نهایی را می‌توانیم در این لینک مشاهده کنیم.

بررسی دسترس‌پذیری در اسلایدرهای CSS

یکی از نکات فوق‌العاده در مورد این قابلیت‌ها این است که نه‌تنها نیاز به جاوااسکریپت را کاهش می‌دهند، بلکه به‌صورت ذاتی با ویژگی‌های مربوط به دسترسی‌پذیری نیز همراه هستند.

بهینه‌سازی دکمه‌های اسکرول

دکمه‌های اسکرول دقیقاً مانند المنت‌های معمولی <button> عمل می‌کنند، با این تفاوت که به‌صورت pseudo-element رندر می‌شوند. این بدان معناست که قابل فوکوس هستند و نیازی نیست که به‌صورت دستی برای آن‌ها نام‌های قابل دسترسی تعریف کنیم، این نام‌ها به‌طور خودکار تولید می‌شوند.

به‌عنوان مثال، قطعه کدی مشابه زیر، فارغ از محتوای بصری دکمه، توسط فناوری‌های کمکی مانند صفحه‌خوان‌ها با عنوان «Scroll right» اعلام می‌شود.

.scroll-container::scroll-button(right) {
  content: "Button"; /* Announces "Scroll right" */
}

با این حال، اگر بخواهیم این ابزارها عبارتی خاص را اعلام کنند، باید آن را به‌صورت متن جایگزین (alt text) تعریف کنیم؛ حتی اگر همان محتوای تصویری باشد:

.scroll-container::scroll-button(right) {
  content: "⮕" / "Scrolls to the right"; /* Announces the text we have given*/
}

نقش اسکرول markerها در تجربه کاربری بهتر

اسکرول markerها نیز به‌صورت پیش‌فرض قابل دسترسی هستند. اگر برای محتوای آن‌ها متن جایگزین تعریف نشده باشد، صفحه‌خوان‌ها عباراتی مانند «selected, tab, 1 of 5» را اعلام می‌کنند. البته می‌توان این پیام پیش‌فرض را با تعریف مقدار دوم برای ویژگی content شخصی‌سازی کرد:

::scroll-marker {
  content: "" / "Slide 1 thumbnail";
}

گروه markerها نیز به‌عنوان یک مجموعه قابل فوکوس با ساختار معنایی tablist و tabindex: -1 در نظر گرفته می‌شود. کاربران می‌توانند با کلید Tab وارد گروه شده و با کلیدهای جهت‌نما بین markerها جابه‌جا شوند.

میزان پشتیبانی مرورگرها از اسلایدر با CSS

در حال حاضر، pseudo-elementهای ::scroll-button() و ::scroll-marker تنها در مرورگر Chrome نسخه ۱۳۵ و بالاتر و مرورگر Edge نسخه ۱۳۵ و بالاتر پشتیبانی می‌شوند. بنابراین این ویژگی‌ها هنوز در مرحله‌ای آزمایشی قرار دارند، اما انتظار می‌رود در آینده پشتیبانی گسترده‌تری پیدا کنند.

برای مشاهده وضعیت سازگاری دقیق، می‌توانیم به منابع زیر مراجعه کنیم:

به‌جز این موارد، سایر ویژگی‌های بررسی‌شده در این مقاله به‌طور گسترده در بیشتر مرورگرها قابل استفاده هستند.

جمع‌بندی

CSS روز‌به‌روز در حال ارائه قابلیت‌های پیشرفته‌تری است. ابزارهایی مانند ::scroll-button و ::scroll-marker به‌خوبی نشان می‌دهند که چقدر امکان طراحی رابط‌های کاربری پویا و تعاملی با CSS افزایش یافته است. اکنون، بدون حتی یک خط کد جاوااسکریپت، می‌توانیم یک اسلایدر با استفاده از CSS طراحی کنیم که هم زیبا و سبک باشد و هم در دسترس همه کاربران قرار بگیرد.