یک نمای کلی از نحوه ساخت یک مؤلفه برگه ها مشابه آنچه در برنامه های iOS و Android یافت می شود.
در این پست میخواهم تفکری را در مورد ساخت یک جزء Tabs برای وب به اشتراک بگذارم که واکنشگرا باشد، از ورودیهای چندگانه دستگاه پشتیبانی کند و در مرورگرها کار کند. نسخه ی نمایشی را امتحان کنید.
اگر ویدیو را ترجیح می دهید، در اینجا یک نسخه YouTube از این پست وجود دارد:
نمای کلی
زبانه ها جزء رایج سیستم های طراحی هستند اما می توانند اشکال و اشکال مختلفی داشته باشند. ابتدا برگههای دسکتاپ بر روی عنصر <frame>
ساخته شده بودند، و اکنون مؤلفههای موبایل کرهای داریم که محتوا را بر اساس ویژگیهای فیزیکی متحرک میکنند. همه آنها تلاش می کنند یک کار را انجام دهند: صرفه جویی در فضا.
امروزه، ملزومات تجربه کاربر تب ها، یک ناحیه پیمایش دکمه ای است که نمایان بودن محتوا را در یک قاب نمایشگر تغییر می دهد. بسیاری از حوزههای محتوای مختلف فضای یکسانی را به اشتراک میگذارند، اما به صورت مشروط بر اساس دکمه انتخابشده در پیمایش ارائه میشوند.
تاکتیک های وب
در مجموع به لطف چند ویژگی مهم پلتفرم وب، ساخت این مؤلفه را بسیار ساده دیدم:
-
scroll-snap-points
برای تعاملات زیبا با کشیدن انگشت و صفحه کلید با موقعیت های توقف پیمایش مناسب - پیوندهای عمیق از طریق هشهای URL برای پشتیبانی از لنگر انداختن پیمایش درون صفحه و به اشتراکگذاری توسط مرورگر
- پشتیبانی از صفحهخوان با نشانهگذاری عنصر
<a>
وid="#hash"
-
prefers-reduced-motion
برای فعال کردن انتقال متقاطع و پیمایش فوری در صفحه - ویژگی وب پیش نویس
@scroll-timeline
برای خط کشی پویا و تغییر رنگ برگه انتخاب شده
HTML
اساساً، UX در اینجا این است: روی یک پیوند کلیک کنید، نشانی اینترنتی نشان دهنده وضعیت صفحه تو در تو باشد، و سپس بهروزرسانی منطقه محتوا را در حین حرکت مرورگر به عنصر منطبق ببینید.
برخی از اعضای محتوای ساختاری در آن وجود دارد: پیوندها و :target
s. ما به لیستی از پیوندها نیاز داریم که یک <nav>
برای آنها عالی است، و یک لیست از عناصر <article>
که یک <section>
برای آنها عالی است. هر هش پیوند با یک بخش مطابقت دارد و به مرورگر اجازه میدهد از طریق لنگر انداختن موارد را پیمایش کند.
برای مثال، کلیک کردن روی یک پیوند به طور خودکار مقاله :target
در Chrome 89 متمرکز می کند، بدون نیاز به JS. سپس کاربر می تواند محتوای مقاله را با دستگاه ورودی خود مانند همیشه پیمایش کند. همانطور که در نشانه گذاری نشان داده شده است، محتوای مکمل است.
من از نشانه گذاری زیر برای سازماندهی برگه ها استفاده کردم:
<snap-tabs>
<header>
<nav>
<a></a>
<a></a>
<a></a>
<a></a>
</nav>
</header>
<section>
<article></article>
<article></article>
<article></article>
<article></article>
</section>
</snap-tabs>
من می توانم بین عناصر <a>
و <article>
با ویژگی های href
و id
مانند این ارتباط برقرار کنم:
<snap-tabs>
<header>
<nav>
<a href="#responsive"></a>
<a href="#accessible"></a>
<a href="#overscroll"></a>
<a href="#more"></a>
</nav>
</header>
<section>
<article id="responsive"></article>
<article id="accessible"></article>
<article id="overscroll"></article>
<article id="more"></article>
</section>
</snap-tabs>
سپس مقالات را با مقادیر ترکیبی لورم، و پیوندها را با طول و مجموعه تصویر ترکیبی از عناوین پر کردم. با محتوا برای کار، می توانیم طرح بندی را شروع کنیم.
طرح بندی های پیمایشی
3 نوع مختلف ناحیه اسکرول در این کامپوننت وجود دارد:
- ناوبری (صورتی) به صورت افقی قابل پیمایش است
- ناحیه محتوا (آبی) به صورت افقی قابل پیمایش است
- هر مورد مقاله (سبز) به صورت عمودی قابل پیمایش است.
2 نوع عنصر مختلف در پیمایش وجود دارد:
- یک پنجره
جعبه ای با ابعاد تعریف شده که دارای سبک ویژگیoverflow
است. - یک سطح بزرگ
در این طرح، این ظروف فهرست است: پیوندهای ناوبری، مقالات بخش، و محتوای مقاله.
طرح بندی <snap-tabs>
طرح سطح بالایی که من انتخاب کردم فلکس (Flexbox) بود. من جهت را روی column
قرار دادم، بنابراین سرصفحه و بخش به صورت عمودی مرتب می شوند. این اولین پنجره اسکرول ما است و همه چیز را با سرریز پنهان پنهان می کند. سرصفحه و بخش به زودی از overscroll به عنوان مناطق جداگانه استفاده می کنند.
<snap-tabs> <header></header> <section></section> </snap-tabs>
snap-tabs { display: flex; flex-direction: column; /* establish primary containing box */ overflow: hidden; position: relative; & > section { /* be pushy about consuming all space */ block-size: 100%; } & > header { /* defend againstneeding 100% */ flex-shrink: 0; /* fixes cross browser quarks */ min-block-size: fit-content; } }
اشاره به نمودار رنگارنگ 3 پیمایشی:
-
<header>
اکنون آماده است تا محفظه اسکرول (صورتی) باشد. -
<section>
آماده شده است تا محفظه اسکرول (آبی) باشد.
فریم هایی که در زیر با VisBug هایلایت کرده ام به ما کمک می کنند پنجره هایی را که محفظه های اسکرول ایجاد کرده اند ببینیم.
طرح بندی برگه ها <header>
طرح بعدی تقریباً یکسان است: من از flex برای ایجاد نظم عمودی استفاده می کنم.
<snap-tabs> <header> <nav></nav> <span class="snap-indicator"></span> </header> <section></section> </snap-tabs>
header { display: flex; flex-direction: column; }
.snap-indicator
باید به صورت افقی همراه با گروه پیوندها حرکت کند و این طرح هدر به تنظیم آن مرحله کمک می کند. هیچ عنصری مطلقاً در اینجا وجود ندارد!
بعد، سبک های اسکرول. به نظر می رسد که ما می توانیم سبک های اسکرول را بین 2 ناحیه اسکرول افقی خود (سرصفحه و بخش) به اشتراک بگذاریم، بنابراین من یک کلاس کاربردی ساختم، .scroll-snap-x
.
.scroll-snap-x {
/* browser decide if x is ok to scroll and show bars on, y hidden */
overflow: auto hidden;
/* prevent scroll chaining on x scroll */
overscroll-behavior-x: contain;
/* scrolling should snap children on x */
scroll-snap-type: x mandatory;
@media (hover: none) {
scrollbar-width: none;
&::-webkit-scrollbar {
width: 0;
height: 0;
}
}
}
هرکدام به سرریز در محور x، محفظه اسکرول برای به دام انداختن اسکرول، نوارهای اسکرول پنهان برای دستگاه های لمسی و در نهایت اسکرول برای قفل کردن مناطق ارائه محتوا نیاز دارند. ترتیب برگه صفحهکلید ما در دسترس است و هر گونه تعاملی به طور طبیعی تمرکز میکند. ظروف اسکرول اسنپ نیز تعامل خوبی با سبک چرخ فلکی از صفحه کلید خود دارند.
طرح بندی سربرگ برگه ها <nav>
پیوندهای پیمایش باید در یک خط، بدون شکستگی خط، به صورت عمودی در مرکز قرار گیرند، و هر مورد پیوند باید به محفظه اسکرول اسنپ بچسبد. کار سریع برای CSS 2021!
<nav> <a></a> <a></a> <a></a> <a></a> </nav>
nav { display: flex; & a { scroll-snap-align: start; display: inline-flex; align-items: center; white-space: nowrap; } }
هر پیوند سبک و اندازه خود را دارد، بنابراین طرح ناو فقط باید جهت و جریان را مشخص کند. عرض های منحصر به فرد در موارد ناوبری، انتقال بین برگه ها را سرگرم کننده می کند زیرا نشانگر عرض خود را با هدف جدید تنظیم می کند. بسته به تعداد عناصر موجود در اینجا، مرورگر یک اسکرول بار را نمایش می دهد یا خیر.
طرح بندی برگه ها <section>
این بخش یک آیتم انعطاف پذیر است و باید مصرف کننده غالب فضا باشد. همچنین نیاز به ایجاد ستون هایی برای قرار دادن مقالات دارد. باز هم، کار سریع برای CSS 2021! block-size: 100%
این عنصر را کشیده تا والد تا حد امکان پر شود، سپس برای طرح بندی خود، یک سری ستون ایجاد می کند که 100%
عرض والد است. درصدها در اینجا عالی عمل میکنند، زیرا ما محدودیتهای قوی روی والد نوشتهایم.
<section> <article></article> <article></article> <article></article> <article></article> </section>
section { block-size: 100%; display: grid; grid-auto-flow: column; grid-auto-columns: 100%; }
مثل این است که می گوییم "تا حد امکان به صورت عمودی گسترش یابد، به روشی فشاری" (هدری را که روی flex-shrink: 0
به یاد داشته باشید: این یک دفاع در برابر این فشار انبساط است) که ارتفاع ردیف را برای یک تنظیم می کند. مجموعه ای از ستون های تمام ارتفاع سبک auto-flow
به شبکه می گوید که همیشه کودکان را در یک خط افقی، بدون بسته بندی، دقیقاً همان چیزی که ما می خواهیم قرار دهد. برای سرریز کردن پنجره والد.
برای من سخت است که گاهی اوقات سرم را به اطراف بپیچم! این عنصر بخش در یک جعبه قرار می گیرد، اما مجموعه ای از جعبه ها را نیز ایجاد می کند. امیدوارم تصاویر و توضیحات کمک کننده باشد.
طرح بندی برگه ها <article>
کاربر باید بتواند محتوای مقاله را پیمایش کند و نوارهای پیمایش فقط در صورت سرریز شدن باید نمایش داده شوند. این عناصر مقاله در موقعیت منظمی قرار دارند. آنها به طور همزمان والد طومار و فرزند طومار هستند. مرورگر واقعاً در اینجا برخی از تعاملات لمسی، ماوس و صفحه کلید را برای ما انجام می دهد.
<article> <h2></h2> <p></p> <p></p> <h2></h2> <p></p> <p></p> ... </article>
article { scroll-snap-align: start; overflow-y: auto; overscroll-behavior-y: contain; }
من تصمیم گرفتم که مقالات در اسکرول والد خود بچسبند. من واقعاً دوست دارم که چگونه آیتمهای پیوند پیمایش و عناصر مقاله به شروع درونی محفظههای اسکرول مربوطه خود میچسبند. به نظر می رسد و احساس می کند که یک رابطه هماهنگ است.
این مقاله یک فرزند شبکه است و اندازه آن از پیش تعیین شده است که میخواهیم UX اسکرول را ارائه دهیم. این به این معنی است که من در اینجا به هیچ سبک ارتفاع یا عرض نیاز ندارم، فقط باید نحوه سرریز شدن آن را تعریف کنم. من overflow-y را روی خودکار تنظیم کردم و سپس تعاملات اسکرول را با ویژگی overscroll-behavior مفید به دام انداختم.
خلاصه 3 ناحیه اسکرول
در زیر من در تنظیمات سیستم خود "همیشه نوارهای پیمایش نشان داده شود" را انتخاب کرده ام. فکر میکنم کار با این تنظیم برای چیدمان دو چندان مهم است، زیرا برای من این است که طرحبندی و هماهنگسازی اسکرول را بررسی کنم.
من فکر می کنم دیدن ناودان اسکرول در این مؤلفه کمک می کند تا به وضوح نشان دهیم که مناطق اسکرول کجا هستند، جهتی که پشتیبانی می کنند و نحوه تعامل آنها با یکدیگر. در نظر بگیرید که چگونه هر یک از این قابهای پنجره پیمایشی برای یک چیدمان منعطف یا مشبک هستند.
DevTools می تواند به ما در تجسم این موضوع کمک کند:
طرحبندیهای پیمایش کامل هستند: snapping، عمیق قابل پیوند، و صفحه کلید قابل دسترسی. پایه ای قوی برای بهبود UX، سبک و لذت.
برجسته ویژگی
کودکان اسکرول شده در هنگام تغییر اندازه موقعیت قفل خود را حفظ می کنند. این بدان معناست که جاوا اسکریپت در چرخش دستگاه یا تغییر اندازه مرورگر نیازی به نمایش چیزی ندارد. آن را در حالت دستگاه Chromium DevTools با انتخاب هر حالتی غیر از Responsive و سپس تغییر اندازه قاب دستگاه امتحان کنید. توجه داشته باشید که عنصر در نمای باقی می ماند و با محتوای خود قفل می شود. از زمانی که Chromium اجرای خود را برای مطابقت با مشخصات بهروزرسانی کرد، این مورد در دسترس است. در اینجا یک پست وبلاگ در مورد آن است.
انیمیشن
هدف کار انیمیشن در اینجا این است که به وضوح تعاملات را با بازخورد UI پیوند دهد. این کمک می کند تا کاربر را برای کشف یکپارچه (امیدواریم) همه محتوا راهنمایی یا کمک کند. من حرکت را با هدف و مشروط اضافه خواهم کرد. کاربران اکنون می توانند تنظیمات برگزیده حرکت خود را در سیستم عامل خود مشخص کنند و من کاملاً از پاسخ دادن به ترجیحات آنها در رابط های خود لذت می برم.
من یک زیر خط برگه را با موقعیت اسکرول مقاله پیوند خواهم داد. Snapping نه تنها یک تراز زیبا است، بلکه شروع و پایان یک انیمیشن را نیز ثابت می کند. این کار <nav>
را که مانند یک نقشه کوچک عمل می کند، به محتوا متصل نگه می دارد. ما اولویت حرکت کاربر را از CSS و JS بررسی خواهیم کرد. چند مکان عالی وجود دارد که باید مورد توجه قرار گیرد!
رفتار اسکرول
فرصتی برای بهبود رفتار حرکتی :target
و element.scrollIntoView()
وجود دارد. به طور پیش فرض، آنی است. مرورگر فقط موقعیت اسکرول را تنظیم می کند. خوب، اگر بخواهیم به جای پلک زدن در آنجا به آن موقعیت اسکرول منتقل شویم، چه؟
@media (prefers-reduced-motion: no-preference) {
.scroll-snap-x {
scroll-behavior: smooth;
}
}
از آنجایی که ما در اینجا حرکت را معرفی می کنیم، و حرکتی را که کاربر کنترل نمی کند (مانند پیمایش)، فقط در صورتی این سبک را اعمال می کنیم که کاربر در سیستم عامل خود ترجیحی در مورد حرکت کاهش یافته نداشته باشد. به این ترتیب، ما فقط حرکت اسکرول را برای افرادی که با آن موافق هستند معرفی می کنیم.
نشانگر زبانه ها
هدف این انیمیشن کمک به مرتبط کردن شاخص با وضعیت محتوا است. من تصمیم گرفتم برای کاربرانی که حرکت کاهشیافته را ترجیح میدهند، سبکهای متقاطع border-bottom
را رنگآمیزی کنم، و برای کاربرانی که با حرکت خوب هستند، یک انیمیشن اسلاید + محو رنگی پیوند خورده را رنگ آمیزی کنم.
در Chromium Devtools، میتوانم اولویت را تغییر دهم و 2 سبک انتقال مختلف را نشان دهم. من از ساختن این بسیار لذت بردم.
@media (prefers-reduced-motion: reduce) {
snap-tabs > header a {
border-block-end: var(--indicator-size) solid hsl(var(--accent) / 0%);
transition: color .7s ease, border-color .5s ease;
&:is(:target,:active,[active]) {
color: var(--text-active-color);
border-block-end-color: hsl(var(--accent));
}
}
snap-tabs .snap-indicator {
visibility: hidden;
}
}
هنگامی که کاربر حرکت کاهش یافته را ترجیح می دهد .snap-indicator
را پنهان می کنم زیرا من دیگر به آن نیاز ندارم. سپس آن را با سبکهای border-block-end
و یک transition
جایگزین میکنم. همچنین در تعامل برگهها توجه کنید که آیتم navver فعال نه تنها دارای برجستهسازی زیر نام تجاری است، بلکه رنگ متن آن نیز تیرهتر است. عنصر فعال دارای کنتراست رنگ متن بالاتر و لهجه زیر نور روشن است.
فقط چند خط اضافی از CSS باعث می شود کسی احساس کند دیده می شود (به این معنا که ما با دقت به اولویت های حرکتی آنها احترام می گذاریم). من آن را دوست دارم.
@scroll-timeline
در بخش بالا به شما نشان دادم که چگونه سبکهای متقاطع حرکت کاهشیافته را مدیریت میکنم، و در این بخش به شما نشان میدهم که چگونه نشانگر و یک ناحیه اسکرول را به هم مرتبط کردم. این چند چیز تجربی سرگرم کننده در ادامه است. امیدوارم شما هم مثل من هیجان زده باشید.
const { matches:motionOK } = window.matchMedia(
'(prefers-reduced-motion: no-preference)'
);
من ابتدا اولویت حرکت کاربر را از جاوا اسکریپت بررسی می کنم. اگر نتیجه این false
باشد، به این معنی که کاربر حرکت کاهشیافته را ترجیح میدهد، هیچ یک از افکتهای حرکتی پیوند اسکرول را اجرا نمیکنیم.
if (motionOK) {
// motion based animation code
}
در زمان نوشتن این مطلب، پشتیبانی مرورگر برای @scroll-timeline
وجود ندارد. این یک پیش نویس مشخصات با پیاده سازی های آزمایشی است. این یک پلی فیل دارد که من در این نسخه نمایشی از آن استفاده می کنم.
ScrollTimeline
در حالی که CSS و جاوا اسکریپت می توانند هر دو جدول زمانی اسکرول ایجاد کنند، من جاوا اسکریپت را انتخاب کردم تا بتوانم از اندازه گیری عناصر زنده در انیمیشن استفاده کنم.
const sectionScrollTimeline = new ScrollTimeline({
scrollSource: tabsection, // snap-tabs > section
orientation: 'inline', // scroll in the direction letters flow
fill: 'both', // bi-directional linking
});
من میخواهم یک چیز از موقعیت اسکرول دیگری پیروی کند، و با ایجاد یک ScrollTimeline
درایور پیوند اسکرول، scrollSource
تعریف میکنم. به طور معمول یک انیمیشن در وب با یک تیک فریم زمانی جهانی اجرا می شود، اما با یک بخش سفارشی sectionScrollTimeline
در حافظه، می توانم همه آن را تغییر دهم.
tabindicator.animate({
transform: ...,
width: ...,
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
قبل از اینکه وارد فریمهای کلیدی انیمیشن بشوم، فکر میکنم مهم است که به دنبال کننده پیمایش اشاره کنیم، tabindicator
، بر اساس یک جدول زمانی سفارشی، اسکرول بخش ما، متحرک خواهد شد. این پیوند را کامل میکند، اما عنصر نهایی، نقاط حالتی برای متحرک کردن، که به عنوان فریمهای کلیدی نیز شناخته میشوند را از دست میدهد.
فریم های کلیدی پویا
یک روش CSS کاملاً قدرتمند برای متحرک سازی با @scroll-timeline
وجود دارد، اما انیمیشنی که من انتخاب کردم بسیار پویا بود. هیچ راهی برای انتقال بین عرض auto
وجود ندارد، و هیچ راهی برای ایجاد پویا تعدادی فریم کلیدی بر اساس طول کودکان وجود ندارد.
با این حال، جاوا اسکریپت می داند که چگونه این اطلاعات را به دست آورد، بنابراین ما خودمان روی بچه ها تکرار می کنیم و مقادیر محاسبه شده را در زمان اجرا می گیریم:
tabindicator.animate({
transform: [...tabnavitems].map(({offsetLeft}) =>
`translateX(${offsetLeft}px)`),
width: [...tabnavitems].map(({offsetWidth}) =>
`${offsetWidth}px`)
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
برای هر tabnavitem
، موقعیت offsetLeft
تخریب کنید و رشته ای را برگردانید که از آن به عنوان مقدار translateX
استفاده می کند. این 4 فریم کلیدی تبدیل برای انیمیشن ایجاد می کند. همین کار برای عرض انجام می شود، از هر کدام پرسیده می شود که عرض پویا چقدر است و سپس به عنوان یک مقدار فریم کلیدی استفاده می شود.
در اینجا نمونه خروجی، بر اساس فونت ها و ترجیحات مرورگر من است:
فریم های کلیدی TranslateX:
[...tabnavitems].map(({offsetLeft}) =>
`translateX(${offsetLeft}px)`)
// results in 4 array items, which represent 4 keyframe states
// ["translateX(0px)", "translateX(121px)", "translateX(238px)", "translateX(464px)"]
فریم های کلیدی عرض:
[...tabnavitems].map(({offsetWidth}) =>
`${offsetWidth}px`)
// results in 4 array items, which represent 4 keyframe states
// ["121px", "117px", "226px", "67px"]
برای خلاصه کردن استراتژی، اکنون نشانگر برگه بسته به موقعیت اسکرول اسکرول بخش در 4 فریم کلیدی متحرک می شود. نقاط ضربهگیر، خطوط مشخصی را بین فریمهای کلیدی ما ایجاد میکنند و واقعاً به حس همگامسازی انیمیشن میافزایند.
کاربر انیمیشن را با تعامل خود هدایت می کند، مشاهده می کند که عرض و موقعیت نشانگر از یک بخش به بخش دیگر تغییر می کند و با اسکرول کاملاً ردیابی می کند.
شاید متوجه نشده باشید، اما من به تغییر رنگ با انتخاب آیتم پیمایش برجسته شده افتخار می کنم.
زمانی که مورد برجسته شده کنتراست بیشتری داشته باشد، خاکستری روشنتر انتخابنشده حتی بیشتر به عقب رانده میشود. انتقال رنگ برای متن معمول است، مانند روی شناور و زمانی که انتخاب شده است، اما انتقال آن رنگ در اسکرول، همگام با نشانگر زیرخط، سطح بعدی است.
در اینجا نحوه انجام من این است:
tabnavitems.forEach(navitem => {
navitem.animate({
color: [...tabnavitems].map(item =>
item === navitem
? `var(--text-active-color)`
: `var(--text-color)`)
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
});
هر پیوند ناوبری برگه به این انیمیشن رنگی جدید نیاز دارد، که همان جدول زمانی اسکرول را به عنوان نشانگر زیرخط ردیابی می کند. من از همان تایم لاین قبلی استفاده می کنم: از آنجایی که نقش آن انتشار یک تیک در اسکرول است، می توانیم از آن تیک در هر نوع انیمیشنی که می خواهیم استفاده کنیم. همانطور که قبلاً انجام دادم، 4 فریم کلیدی در حلقه ایجاد می کنم و رنگ ها را برمی گردم.
[...tabnavitems].map(item =>
item === navitem
? `var(--text-active-color)`
: `var(--text-color)`)
// results in 4 array items, which represent 4 keyframe states
// [
"var(--text-active-color)",
"var(--text-color)",
"var(--text-color)",
"var(--text-color)",
]
فریم کلیدی با رنگ var(--text-active-color)
پیوند را برجسته می کند و در غیر این صورت یک رنگ متن استاندارد است. حلقه تودرتو در آنجا آن را نسبتاً ساده می کند، زیرا حلقه بیرونی هر مورد ناوبری است و حلقه داخلی فریم های کلیدی شخصی هر یک از موارد ناوبری است. بررسی میکنم که آیا عنصر حلقه بیرونی مشابه حلقه داخلی است یا نه، و از آن برای اطلاع از انتخاب آن استفاده میکنم.
از نوشتن این مطلب خیلی لذت بردم. خیلی
حتی پیشرفت های بیشتر جاوا اسکریپت
شایان ذکر است که هسته چیزی که در اینجا به شما نشان می دهم بدون جاوا اسکریپت کار می کند. با این اوصاف، بیایید ببینیم چگونه میتوانیم آن را هنگامی که JS در دسترس است، تقویت کنیم.
پیوندهای عمیق
پیوندهای عمیق بیشتر یک اصطلاح تلفن همراه هستند، اما من فکر میکنم هدف از پیوند عمیق در اینجا با برگهها برآورده میشود که میتوانید URL را مستقیماً با محتوای یک برگه به اشتراک بگذارید. مرورگر درون صفحه به شناسه ای که در هش URL مطابقت دارد پیمایش می کند. من متوجه شدم که این کنترل کننده onload
اثر را در سراسر پلتفرم ها ایجاد می کند.
window.onload = () => {
if (location.hash) {
tabsection.scrollLeft = document
.querySelector(location.hash)
.offsetLeft;
}
}
همگام سازی پایان پیمایش
کاربران ما همیشه روی صفحهکلید کلیک نمیکنند یا از صفحهکلید استفاده نمیکنند، گاهی اوقات آنطور که باید بتوانند به صورت رایگان پیمایش میکنند. وقتی پیمایش بخش پیمایش را متوقف میکند، هر کجا که فرود میآید باید در نوار پیمایش بالا مطابقت داده شود.
در اینجا چگونه منتظر پایان اسکرول هستم: js tabsection.addEventListener('scroll', () => { clearTimeout(tabsection.scrollEndTimer); tabsection.scrollEndTimer = setTimeout(determineActiveTabSection, 100); });
هر زمان که بخشها در حال پیمایش هستند، در صورت وجود زمانبندی بخش را پاک کنید و قسمت جدیدی را شروع کنید. وقتی بخشها دیگر پیمایش نمیشوند، مهلت زمانی را پاک نکنید و 100 میلیثانیه پس از استراحت شلیک کنید. هنگامی که فعال می شود، تابعی را فراخوانی کنید که به دنبال تشخیص مکان توقف کاربر است.
const determineActiveTabSection = () => {
const i = tabsection.scrollLeft / tabsection.clientWidth;
const matchingNavItem = tabnavitems[i];
matchingNavItem && setActiveTab(matchingNavItem);
};
با فرض قطع شدن اسکرول، تقسیم موقعیت اسکرول فعلی از عرض ناحیه اسکرول باید به یک عدد صحیح و نه اعشاری منجر شود. سپس سعی میکنم از طریق این شاخص محاسبهشده، یک navitem از حافظه پنهان خود بگیرم و اگر چیزی پیدا کرد، مسابقه را برای فعال شدن ارسال میکنم.
const setActiveTab = tabbtn => {
tabnav
.querySelector(':scope a[active]')
.removeAttribute('active');
tabbtn.setAttribute('active', '');
tabbtn.scrollIntoView();
};
تنظیم برگه فعال با پاک کردن هر برگه فعال در حال حاضر شروع می شود، سپس به آیتم ناوبری ورودی ویژگی حالت فعال می دهد. فراخوانی scrollIntoView()
تعامل جالبی با CSS دارد که شایان ذکر است.
.scroll-snap-x {
overflow: auto hidden;
overscroll-behavior-x: contain;
scroll-snap-type: x mandatory;
@media (prefers-reduced-motion: no-preference) {
scroll-behavior: smooth;
}
}
در CSS ابزار اسکرول افقی، ما یک درخواست رسانه تو در تو قرار داده ایم که در صورتی که کاربر تحمل حرکت را داشته باشد، پیمایش smooth
را اعمال می کند. جاوا اسکریپت میتواند آزادانه برای اسکرول عناصر تماس برقرار کند، و CSS میتواند UX را بهطور آشکار مدیریت کند. کبریت کوچک بسیار لذت بخشی که گاهی اوقات درست می کنند.
نتیجه گیری
حالا که می دانی من چگونه این کار را انجام دادم، شما چطور؟! این باعث می شود معماری اجزای سرگرم کننده ای ایجاد شود! چه کسی می خواهد نسخه اول را با اسلات در چارچوب مورد علاقه خود بسازد؟ 🙂
بیایید رویکردهای خود را متنوع کنیم و همه راههای ساخت در وب را بیاموزیم. یک اشکال ایجاد کنید، نسخه خود را برای من توییت کنید ، و من آن را به بخش ریمیکس های انجمن در زیر اضافه می کنم.
ریمیکس های انجمن
- @devnook ، @rob_dodson ، و @DasSurma با اجزای وب: مقاله .
- @jhvanderschee با دکمه ها: Codepen .
یک نمای کلی از نحوه ساخت یک مؤلفه برگه ها مشابه آنچه در برنامه های iOS و Android یافت می شود.
در این پست میخواهم تفکری را در مورد ساخت یک جزء Tabs برای وب به اشتراک بگذارم که واکنشگرا باشد، از ورودیهای چندگانه دستگاه پشتیبانی کند و در مرورگرها کار کند. نسخه ی نمایشی را امتحان کنید.
اگر ویدیو را ترجیح می دهید، در اینجا یک نسخه YouTube از این پست وجود دارد:
نمای کلی
زبانه ها جزء رایج سیستم های طراحی هستند اما می توانند اشکال و اشکال مختلفی داشته باشند. ابتدا برگههای دسکتاپ بر روی عنصر <frame>
ساخته شده بودند، و اکنون مؤلفههای موبایل کرهای داریم که محتوا را بر اساس ویژگیهای فیزیکی متحرک میکنند. همه آنها تلاش می کنند یک کار را انجام دهند: صرفه جویی در فضا.
امروزه، ملزومات تجربه کاربر تب ها، یک ناحیه پیمایش دکمه ای است که نمایان بودن محتوا را در یک قاب نمایشگر تغییر می دهد. بسیاری از حوزههای محتوای مختلف فضای یکسانی را به اشتراک میگذارند، اما به صورت مشروط بر اساس دکمه انتخابشده در پیمایش ارائه میشوند.
تاکتیک های وب
در مجموع به لطف چند ویژگی مهم پلتفرم وب، ساخت این مؤلفه را بسیار ساده دیدم:
-
scroll-snap-points
برای تعاملات زیبا با کشیدن انگشت و صفحه کلید با موقعیت های توقف پیمایش مناسب - پیوندهای عمیق از طریق هشهای URL برای پشتیبانی از لنگر انداختن پیمایش درون صفحه و به اشتراکگذاری توسط مرورگر
- پشتیبانی از صفحهخوان با نشانهگذاری عنصر
<a>
وid="#hash"
-
prefers-reduced-motion
برای فعال کردن انتقال متقاطع و پیمایش فوری در صفحه - ویژگی وب پیش نویس
@scroll-timeline
برای خط کشی پویا و تغییر رنگ برگه انتخاب شده
HTML
اساساً، UX در اینجا این است: روی یک پیوند کلیک کنید، نشانی اینترنتی نشان دهنده وضعیت صفحه تو در تو باشد، و سپس بهروزرسانی منطقه محتوا را در حین حرکت مرورگر به عنصر منطبق ببینید.
برخی از اعضای محتوای ساختاری در آن وجود دارد: پیوندها و :target
s. ما به لیستی از پیوندها نیاز داریم که یک <nav>
برای آنها عالی است، و یک لیست از عناصر <article>
که یک <section>
برای آنها عالی است. هر هش پیوند با یک بخش مطابقت دارد و به مرورگر اجازه میدهد از طریق لنگر انداختن موارد را پیمایش کند.
برای مثال، کلیک کردن روی یک پیوند به طور خودکار مقاله :target
در Chrome 89 متمرکز می کند، بدون نیاز به JS. سپس کاربر می تواند محتوای مقاله را با دستگاه ورودی خود مانند همیشه پیمایش کند. همانطور که در نشانه گذاری نشان داده شده است، محتوای مکمل است.
من از نشانه گذاری زیر برای سازماندهی برگه ها استفاده کردم:
<snap-tabs>
<header>
<nav>
<a></a>
<a></a>
<a></a>
<a></a>
</nav>
</header>
<section>
<article></article>
<article></article>
<article></article>
<article></article>
</section>
</snap-tabs>
من می توانم بین عناصر <a>
و <article>
با ویژگی های href
و id
مانند این ارتباط برقرار کنم:
<snap-tabs>
<header>
<nav>
<a href="#responsive"></a>
<a href="#accessible"></a>
<a href="#overscroll"></a>
<a href="#more"></a>
</nav>
</header>
<section>
<article id="responsive"></article>
<article id="accessible"></article>
<article id="overscroll"></article>
<article id="more"></article>
</section>
</snap-tabs>
سپس مقالات را با مقادیر ترکیبی لورم، و پیوندها را با طول و مجموعه تصویر ترکیبی از عناوین پر کردم. با محتوا برای کار، می توانیم طرح بندی را شروع کنیم.
طرح بندی های پیمایشی
3 نوع مختلف ناحیه اسکرول در این کامپوننت وجود دارد:
- ناوبری (صورتی) به صورت افقی قابل پیمایش است
- ناحیه محتوا (آبی) به صورت افقی قابل پیمایش است
- هر مورد مقاله (سبز) به صورت عمودی قابل پیمایش است.
2 نوع عنصر مختلف در پیمایش وجود دارد:
- یک پنجره
جعبه ای با ابعاد تعریف شده که دارای سبک ویژگیoverflow
است. - یک سطح بزرگ
در این طرح، این ظروف فهرست است: پیوندهای ناوبری، مقالات بخش، و محتوای مقاله.
طرح بندی <snap-tabs>
طرح سطح بالایی که من انتخاب کردم فلکس (Flexbox) بود. من جهت را روی column
قرار دادم، بنابراین سرصفحه و بخش به صورت عمودی مرتب می شوند. این اولین پنجره اسکرول ما است و همه چیز را با سرریز پنهان پنهان می کند. سرصفحه و بخش به زودی از overscroll به عنوان مناطق جداگانه استفاده می کنند.
<snap-tabs> <header></header> <section></section> </snap-tabs>
snap-tabs { display: flex; flex-direction: column; /* establish primary containing box */ overflow: hidden; position: relative; & > section { /* be pushy about consuming all space */ block-size: 100%; } & > header { /* defend againstneeding 100% */ flex-shrink: 0; /* fixes cross browser quarks */ min-block-size: fit-content; } }
اشاره به نمودار رنگارنگ 3 پیمایشی:
-
<header>
اکنون آماده است تا محفظه اسکرول (صورتی) باشد. -
<section>
آماده شده است تا محفظه اسکرول (آبی) باشد.
فریم هایی که در زیر با VisBug هایلایت کرده ام به ما کمک می کنند پنجره هایی را که محفظه های اسکرول ایجاد کرده اند ببینیم.
طرح بندی برگه ها <header>
طرح بعدی تقریباً یکسان است: من از flex برای ایجاد نظم عمودی استفاده می کنم.
<snap-tabs> <header> <nav></nav> <span class="snap-indicator"></span> </header> <section></section> </snap-tabs>
header { display: flex; flex-direction: column; }
.snap-indicator
باید به صورت افقی همراه با گروه پیوندها حرکت کند و این طرح هدر به تنظیم آن مرحله کمک می کند. هیچ عنصری مطلقاً در اینجا وجود ندارد!
بعد، سبک های اسکرول. به نظر می رسد که ما می توانیم سبک های اسکرول را بین 2 ناحیه اسکرول افقی خود (سرصفحه و بخش) به اشتراک بگذاریم، بنابراین من یک کلاس کاربردی ساختم، .scroll-snap-x
.
.scroll-snap-x {
/* browser decide if x is ok to scroll and show bars on, y hidden */
overflow: auto hidden;
/* prevent scroll chaining on x scroll */
overscroll-behavior-x: contain;
/* scrolling should snap children on x */
scroll-snap-type: x mandatory;
@media (hover: none) {
scrollbar-width: none;
&::-webkit-scrollbar {
width: 0;
height: 0;
}
}
}
هرکدام به سرریز در محور x، محفظه اسکرول برای به دام انداختن اسکرول، نوارهای اسکرول پنهان برای دستگاه های لمسی و در نهایت اسکرول برای قفل کردن مناطق ارائه محتوا نیاز دارند. ترتیب برگه صفحهکلید ما در دسترس است و هر گونه تعاملی به طور طبیعی تمرکز میکند. ظروف اسکرول اسنپ نیز تعامل خوبی با سبک چرخ فلکی از صفحه کلید خود دارند.
طرح بندی سربرگ برگه ها <nav>
پیوندهای پیمایش باید در یک خط، بدون شکستگی خط، به صورت عمودی در مرکز قرار گیرند، و هر مورد پیوند باید به محفظه اسکرول اسنپ بچسبد. کار سریع برای CSS 2021!
<nav> <a></a> <a></a> <a></a> <a></a> </nav>
nav { display: flex; & a { scroll-snap-align: start; display: inline-flex; align-items: center; white-space: nowrap; } }
هر پیوند سبک و اندازه خود را دارد، بنابراین طرح ناو فقط باید جهت و جریان را مشخص کند. عرض های منحصر به فرد در موارد ناوبری، انتقال بین برگه ها را سرگرم کننده می کند زیرا نشانگر عرض خود را با هدف جدید تنظیم می کند. بسته به تعداد عناصر موجود در اینجا، مرورگر یک اسکرول بار را نمایش می دهد یا خیر.
طرح بندی برگه ها <section>
این بخش یک آیتم انعطاف پذیر است و باید مصرف کننده غالب فضا باشد. همچنین نیاز به ایجاد ستون هایی برای قرار دادن مقالات دارد. باز هم، کار سریع برای CSS 2021! block-size: 100%
این عنصر را کشیده تا والد تا حد امکان پر شود، سپس برای طرح بندی خود، یک سری ستون ایجاد می کند که 100%
عرض والد است. درصدها در اینجا عالی عمل میکنند، زیرا ما محدودیتهای قوی روی والد نوشتهایم.
<section> <article></article> <article></article> <article></article> <article></article> </section>
section { block-size: 100%; display: grid; grid-auto-flow: column; grid-auto-columns: 100%; }
مثل این است که می گوییم "تا حد امکان به صورت عمودی گسترش یابد، به روشی فشاری" (هدری را که روی flex-shrink: 0
به یاد داشته باشید: این یک دفاع در برابر این فشار انبساط است) که ارتفاع ردیف را برای یک تنظیم می کند. مجموعه ای از ستون های تمام ارتفاع سبک auto-flow
به شبکه می گوید که همیشه کودکان را در یک خط افقی، بدون بسته بندی، دقیقاً همان چیزی که ما می خواهیم قرار دهد. برای سرریز کردن پنجره والد.
برای من سخت است که گاهی اوقات سرم را به اطراف بپیچم! این عنصر بخش در یک جعبه قرار می گیرد، اما مجموعه ای از جعبه ها را نیز ایجاد می کند. امیدوارم تصاویر و توضیحات کمک کننده باشد.
طرح بندی برگه ها <article>
کاربر باید بتواند محتوای مقاله را پیمایش کند و نوارهای پیمایش فقط در صورت سرریز شدن باید نمایش داده شوند. این عناصر مقاله در موقعیت منظمی قرار دارند. آنها به طور همزمان والد طومار و فرزند طومار هستند. مرورگر واقعاً در اینجا برخی از تعاملات لمسی، ماوس و صفحه کلید را برای ما انجام می دهد.
<article> <h2></h2> <p></p> <p></p> <h2></h2> <p></p> <p></p> ... </article>
article { scroll-snap-align: start; overflow-y: auto; overscroll-behavior-y: contain; }
من تصمیم گرفتم که مقالات در اسکرول والد خود بچسبند. من واقعاً دوست دارم که چگونه آیتمهای پیوند پیمایش و عناصر مقاله به شروع درونی محفظههای اسکرول مربوطه خود میچسبند. به نظر می رسد و احساس می کند که یک رابطه هماهنگ است.
این مقاله یک فرزند شبکه است و اندازه آن از پیش تعیین شده است که میخواهیم UX اسکرول را ارائه دهیم. این به این معنی است که من در اینجا به هیچ سبک ارتفاع یا عرض نیاز ندارم، فقط باید نحوه سرریز شدن آن را تعریف کنم. من overflow-y را روی خودکار تنظیم کردم و سپس تعاملات اسکرول را با ویژگی overscroll-behavior مفید به دام انداختم.
خلاصه 3 ناحیه اسکرول
در زیر من در تنظیمات سیستم خود "همیشه نوارهای پیمایش نشان داده شود" را انتخاب کرده ام. فکر میکنم کار با این تنظیم برای چیدمان دو چندان مهم است، زیرا برای من این است که طرحبندی و هماهنگسازی اسکرول را بررسی کنم.
من فکر می کنم دیدن ناودان اسکرول در این مؤلفه کمک می کند تا به وضوح نشان دهیم که مناطق اسکرول کجا هستند، جهتی که پشتیبانی می کنند و نحوه تعامل آنها با یکدیگر. در نظر بگیرید که چگونه هر یک از این قابهای پنجره پیمایشی برای یک چیدمان منعطف یا مشبک هستند.
DevTools می تواند به ما در تجسم این موضوع کمک کند:
طرحبندیهای پیمایش کامل هستند: snapping، عمیق قابل پیوند، و صفحه کلید قابل دسترسی. پایه ای قوی برای بهبود UX، سبک و لذت.
برجسته ویژگی
کودکان اسکرول شده در هنگام تغییر اندازه موقعیت قفل خود را حفظ می کنند. این بدان معناست که جاوا اسکریپت در چرخش دستگاه یا تغییر اندازه مرورگر نیازی به نمایش چیزی ندارد. آن را در حالت دستگاه Chromium DevTools با انتخاب هر حالتی غیر از Responsive و سپس تغییر اندازه قاب دستگاه امتحان کنید. توجه داشته باشید که عنصر در نمای باقی می ماند و با محتوای خود قفل می شود. از زمانی که Chromium اجرای خود را برای مطابقت با مشخصات بهروزرسانی کرد، این مورد در دسترس است. در اینجا یک پست وبلاگ در مورد آن است.
انیمیشن
هدف کار انیمیشن در اینجا این است که به وضوح تعاملات را با بازخورد UI پیوند دهد. این کمک می کند تا کاربر را برای کشف یکپارچه (امیدواریم) همه محتوا راهنمایی یا کمک کند. من حرکت را با هدف و مشروط اضافه خواهم کرد. کاربران اکنون می توانند تنظیمات برگزیده حرکت خود را در سیستم عامل خود مشخص کنند و من کاملاً از پاسخ دادن به ترجیحات آنها در رابط های خود لذت می برم.
من یک زیر خط برگه را با موقعیت اسکرول مقاله پیوند خواهم داد. Snapping نه تنها یک تراز زیبا است، بلکه شروع و پایان یک انیمیشن را نیز ثابت می کند. این کار <nav>
را که مانند یک نقشه کوچک عمل می کند، به محتوا متصل نگه می دارد. ما اولویت حرکت کاربر را از CSS و JS بررسی خواهیم کرد. چند مکان عالی وجود دارد که باید مورد توجه قرار گیرد!
رفتار اسکرول
فرصتی برای بهبود رفتار حرکتی :target
و element.scrollIntoView()
وجود دارد. به طور پیش فرض، آنی است. مرورگر فقط موقعیت اسکرول را تنظیم می کند. خوب، اگر بخواهیم به جای پلک زدن در آنجا به آن موقعیت اسکرول منتقل شویم، چه؟
@media (prefers-reduced-motion: no-preference) {
.scroll-snap-x {
scroll-behavior: smooth;
}
}
از آنجایی که ما در اینجا حرکت را معرفی می کنیم، و حرکتی را که کاربر کنترل نمی کند (مانند پیمایش)، فقط در صورتی این سبک را اعمال می کنیم که کاربر در سیستم عامل خود ترجیحی در مورد حرکت کاهش یافته نداشته باشد. به این ترتیب، ما فقط حرکت اسکرول را برای افرادی که با آن موافق هستند معرفی می کنیم.
نشانگر زبانه ها
هدف این انیمیشن کمک به مرتبط کردن شاخص با وضعیت محتوا است. من تصمیم گرفتم برای کاربرانی که حرکت کاهشیافته را ترجیح میدهند، سبکهای متقاطع border-bottom
را رنگآمیزی کنم، و برای کاربرانی که با حرکت خوب هستند، یک انیمیشن اسلاید + محو رنگی پیوند خورده را رنگ آمیزی کنم.
در Chromium Devtools، میتوانم اولویت را تغییر دهم و 2 سبک انتقال مختلف را نشان دهم. من از ساختن این بسیار لذت بردم.
@media (prefers-reduced-motion: reduce) {
snap-tabs > header a {
border-block-end: var(--indicator-size) solid hsl(var(--accent) / 0%);
transition: color .7s ease, border-color .5s ease;
&:is(:target,:active,[active]) {
color: var(--text-active-color);
border-block-end-color: hsl(var(--accent));
}
}
snap-tabs .snap-indicator {
visibility: hidden;
}
}
هنگامی که کاربر حرکت کاهش یافته را ترجیح می دهد .snap-indicator
را پنهان می کنم زیرا من دیگر به آن نیاز ندارم. سپس آن را با سبکهای border-block-end
و یک transition
جایگزین میکنم. همچنین در تعامل برگهها توجه کنید که آیتم navver فعال نه تنها دارای برجستهسازی زیر نام تجاری است، بلکه رنگ متن آن نیز تیرهتر است. عنصر فعال دارای کنتراست رنگ متن بالاتر و لهجه زیر نور روشن است.
فقط چند خط اضافی از CSS باعث می شود کسی احساس کند دیده می شود (به این معنا که ما با دقت به اولویت های حرکتی آنها احترام می گذاریم). من آن را دوست دارم.
@scroll-timeline
در بخش بالا به شما نشان دادم که چگونه سبکهای متقاطع حرکت کاهشیافته را مدیریت میکنم، و در این بخش به شما نشان میدهم که چگونه نشانگر و یک ناحیه اسکرول را به هم مرتبط کردم. این چند چیز تجربی سرگرم کننده در ادامه است. امیدوارم شما هم مثل من هیجان زده باشید.
const { matches:motionOK } = window.matchMedia(
'(prefers-reduced-motion: no-preference)'
);
من ابتدا اولویت حرکت کاربر را از جاوا اسکریپت بررسی می کنم. اگر نتیجه این false
باشد، به این معنی که کاربر حرکت کاهشیافته را ترجیح میدهد، هیچ یک از افکتهای حرکتی پیوند اسکرول را اجرا نمیکنیم.
if (motionOK) {
// motion based animation code
}
در زمان نوشتن این مطلب، پشتیبانی مرورگر برای @scroll-timeline
وجود ندارد. این یک پیش نویس مشخصات با پیاده سازی های آزمایشی است. این یک پلی فیل دارد که من در این نسخه نمایشی از آن استفاده می کنم.
ScrollTimeline
در حالی که CSS و جاوا اسکریپت می توانند هر دو جدول زمانی اسکرول ایجاد کنند، من جاوا اسکریپت را انتخاب کردم تا بتوانم از اندازه گیری عناصر زنده در انیمیشن استفاده کنم.
const sectionScrollTimeline = new ScrollTimeline({
scrollSource: tabsection, // snap-tabs > section
orientation: 'inline', // scroll in the direction letters flow
fill: 'both', // bi-directional linking
});
من میخواهم یک چیز از موقعیت اسکرول دیگری پیروی کند، و با ایجاد یک ScrollTimeline
درایور پیوند اسکرول، scrollSource
تعریف میکنم. به طور معمول یک انیمیشن در وب با یک تیک فریم زمانی جهانی اجرا می شود، اما با یک بخش سفارشی sectionScrollTimeline
در حافظه، می توانم همه آن را تغییر دهم.
tabindicator.animate({
transform: ...,
width: ...,
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
قبل از اینکه وارد فریمهای کلیدی انیمیشن بشوم، فکر میکنم مهم است که به دنبال کننده پیمایش اشاره کنیم، tabindicator
، بر اساس یک جدول زمانی سفارشی، اسکرول بخش ما، متحرک خواهد شد. این پیوند را کامل میکند، اما عنصر نهایی، نقاط حالتی برای متحرک کردن، که به عنوان فریمهای کلیدی نیز شناخته میشوند را از دست میدهد.
فریم های کلیدی پویا
یک روش CSS کاملاً قدرتمند برای متحرک سازی با @scroll-timeline
وجود دارد، اما انیمیشنی که من انتخاب کردم بسیار پویا بود. هیچ راهی برای انتقال بین عرض auto
وجود ندارد، و هیچ راهی برای ایجاد پویا تعدادی فریم کلیدی بر اساس طول کودکان وجود ندارد.
با این حال، جاوا اسکریپت می داند که چگونه این اطلاعات را به دست آورد، بنابراین ما خودمان روی بچه ها تکرار می کنیم و مقادیر محاسبه شده را در زمان اجرا می گیریم:
tabindicator.animate({
transform: [...tabnavitems].map(({offsetLeft}) =>
`translateX(${offsetLeft}px)`),
width: [...tabnavitems].map(({offsetWidth}) =>
`${offsetWidth}px`)
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
برای هر tabnavitem
، موقعیت offsetLeft
تخریب کنید و رشته ای را برگردانید که از آن به عنوان مقدار translateX
استفاده می کند. این 4 فریم کلیدی تبدیل برای انیمیشن ایجاد می کند. همین کار برای عرض انجام می شود، از هر کدام پرسیده می شود که عرض پویا چقدر است و سپس به عنوان یک مقدار فریم کلیدی استفاده می شود.
در اینجا نمونه خروجی، بر اساس فونت ها و ترجیحات مرورگر من است:
فریم های کلیدی TranslateX:
[...tabnavitems].map(({offsetLeft}) =>
`translateX(${offsetLeft}px)`)
// results in 4 array items, which represent 4 keyframe states
// ["translateX(0px)", "translateX(121px)", "translateX(238px)", "translateX(464px)"]
فریم های کلیدی عرض:
[...tabnavitems].map(({offsetWidth}) =>
`${offsetWidth}px`)
// results in 4 array items, which represent 4 keyframe states
// ["121px", "117px", "226px", "67px"]
برای خلاصه کردن استراتژی، اکنون نشانگر برگه بسته به موقعیت اسکرول اسکرول بخش در 4 فریم کلیدی متحرک می شود. نقاط ضربهگیر، خطوط مشخصی را بین فریمهای کلیدی ما ایجاد میکنند و واقعاً به حس همگامسازی انیمیشن میافزایند.
کاربر انیمیشن را با تعامل خود هدایت می کند، مشاهده می کند که عرض و موقعیت نشانگر از یک بخش به بخش دیگر تغییر می کند و با اسکرول کاملاً ردیابی می کند.
شاید متوجه نشده باشید، اما من به تغییر رنگ با انتخاب آیتم پیمایش برجسته شده افتخار می کنم.
زمانی که مورد برجسته شده کنتراست بیشتری داشته باشد، خاکستری روشنتر انتخابنشده حتی بیشتر به عقب رانده میشود. انتقال رنگ برای متن معمول است، مانند روی شناور و زمانی که انتخاب شده است، اما انتقال آن رنگ در اسکرول، همگام با نشانگر زیرخط، سطح بعدی است.
در اینجا نحوه انجام من این است:
tabnavitems.forEach(navitem => {
navitem.animate({
color: [...tabnavitems].map(item =>
item === navitem
? `var(--text-active-color)`
: `var(--text-color)`)
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
});
هر پیوند ناوبری برگه به این انیمیشن رنگی جدید نیاز دارد، که همان جدول زمانی اسکرول را به عنوان نشانگر زیرخط ردیابی می کند. من از همان تایم لاین قبلی استفاده می کنم: از آنجایی که نقش آن انتشار یک تیک در اسکرول است، می توانیم از آن تیک در هر نوع انیمیشنی که می خواهیم استفاده کنیم. همانطور که قبلاً انجام دادم، 4 فریم کلیدی در حلقه ایجاد می کنم و رنگ ها را برمی گردم.
[...tabnavitems].map(item =>
item === navitem
? `var(--text-active-color)`
: `var(--text-color)`)
// results in 4 array items, which represent 4 keyframe states
// [
"var(--text-active-color)",
"var(--text-color)",
"var(--text-color)",
"var(--text-color)",
]
فریم کلیدی با رنگ var(--text-active-color)
پیوند را برجسته می کند و در غیر این صورت یک رنگ متن استاندارد است. حلقه تودرتو در آنجا آن را نسبتاً ساده می کند، زیرا حلقه بیرونی هر مورد ناوبری است و حلقه داخلی فریم های کلیدی شخصی هر یک از موارد ناوبری است. بررسی میکنم که آیا عنصر حلقه بیرونی مشابه حلقه داخلی است یا نه، و از آن برای اطلاع از انتخاب آن استفاده میکنم.
از نوشتن این مطلب خیلی لذت بردم. خیلی
حتی پیشرفت های بیشتر جاوا اسکریپت
شایان ذکر است که هسته چیزی که در اینجا به شما نشان می دهم بدون جاوا اسکریپت کار می کند. با این اوصاف، بیایید ببینیم چگونه میتوانیم آن را هنگامی که JS در دسترس است، تقویت کنیم.
پیوندهای عمیق
پیوندهای عمیق بیشتر یک اصطلاح تلفن همراه هستند، اما من فکر میکنم هدف از پیوند عمیق در اینجا با برگهها برآورده میشود که میتوانید URL را مستقیماً با محتوای یک برگه به اشتراک بگذارید. مرورگر درون صفحه به شناسه ای که در هش URL مطابقت دارد پیمایش می کند. من متوجه شدم که این کنترل کننده onload
اثر را در سراسر پلتفرم ها ایجاد می کند.
window.onload = () => {
if (location.hash) {
tabsection.scrollLeft = document
.querySelector(location.hash)
.offsetLeft;
}
}
همگام سازی پایان پیمایش
کاربران ما همیشه روی صفحهکلید کلیک نمیکنند یا از صفحهکلید استفاده نمیکنند، گاهی اوقات آنطور که باید بتوانند به صورت رایگان پیمایش میکنند. وقتی پیمایش بخش پیمایش را متوقف میکند، هر کجا که فرود میآید باید در نوار پیمایش بالا مطابقت داده شود.
در اینجا چگونه منتظر پایان اسکرول هستم: js tabsection.addEventListener('scroll', () => { clearTimeout(tabsection.scrollEndTimer); tabsection.scrollEndTimer = setTimeout(determineActiveTabSection, 100); });
هر زمان که بخشها در حال پیمایش هستند، در صورت وجود زمانبندی بخش را پاک کنید و قسمت جدیدی را شروع کنید. وقتی بخشها دیگر پیمایش نمیشوند، مهلت زمانی را پاک نکنید و 100 میلیثانیه پس از استراحت شلیک کنید. هنگامی که فعال می شود، تابعی را فراخوانی کنید که به دنبال تشخیص مکان توقف کاربر است.
const determineActiveTabSection = () => {
const i = tabsection.scrollLeft / tabsection.clientWidth;
const matchingNavItem = tabnavitems[i];
matchingNavItem && setActiveTab(matchingNavItem);
};
با فرض قطع شدن اسکرول، تقسیم موقعیت اسکرول فعلی از عرض ناحیه اسکرول باید به یک عدد صحیح و نه اعشاری منجر شود. سپس سعی میکنم از طریق این شاخص محاسبهشده، یک navitem از حافظه پنهان خود بگیرم و اگر چیزی پیدا کرد، مسابقه را برای فعال شدن ارسال میکنم.
const setActiveTab = tabbtn => {
tabnav
.querySelector(':scope a[active]')
.removeAttribute('active');
tabbtn.setAttribute('active', '');
tabbtn.scrollIntoView();
};
تنظیم برگه فعال با پاک کردن هر برگه فعال در حال حاضر شروع می شود، سپس به آیتم ناوبری ورودی ویژگی حالت فعال می دهد. فراخوانی scrollIntoView()
تعامل جالبی با CSS دارد که شایان ذکر است.
.scroll-snap-x {
overflow: auto hidden;
overscroll-behavior-x: contain;
scroll-snap-type: x mandatory;
@media (prefers-reduced-motion: no-preference) {
scroll-behavior: smooth;
}
}
در CSS ابزار اسکرول افقی، ما یک درخواست رسانه تو در تو قرار داده ایم که در صورتی که کاربر تحمل حرکت را داشته باشد، پیمایش smooth
را اعمال می کند. جاوا اسکریپت میتواند آزادانه برای اسکرول عناصر تماس برقرار کند، و CSS میتواند UX را بهطور آشکار مدیریت کند. کبریت کوچک بسیار لذت بخشی که گاهی اوقات درست می کنند.
نتیجه گیری
حالا که می دانی من چگونه این کار را انجام دادم، شما چطور؟! این باعث می شود معماری اجزای سرگرم کننده ای ایجاد شود! چه کسی می خواهد نسخه اول را با اسلات در چارچوب مورد علاقه خود بسازد؟ 🙂
بیایید رویکردهای خود را متنوع کنیم و همه راههای ساخت در وب را بیاموزیم. یک اشکال ایجاد کنید، نسخه خود را برای من توییت کنید ، و من آن را به بخش ریمیکس های انجمن در زیر اضافه می کنم.
ریمیکس های انجمن
- @devnook ، @rob_dodson ، و @DasSurma با اجزای وب: مقاله .
- @jhvanderschee با دکمه ها: Codepen .
یک نمای کلی از نحوه ساخت یک مؤلفه برگه ها مشابه آنچه در برنامه های iOS و Android یافت می شود.
در این پست میخواهم تفکری را در مورد ساخت یک جزء Tabs برای وب به اشتراک بگذارم که واکنشگرا باشد، از ورودیهای چندگانه دستگاه پشتیبانی کند و در مرورگرها کار کند. نسخه ی نمایشی را امتحان کنید.
اگر ویدیو را ترجیح می دهید، در اینجا یک نسخه YouTube از این پست وجود دارد:
نمای کلی
زبانه ها جزء رایج سیستم های طراحی هستند اما می توانند اشکال و اشکال مختلفی داشته باشند. ابتدا برگههای دسکتاپ بر روی عنصر <frame>
ساخته شده بودند، و اکنون مؤلفههای موبایل کرهای داریم که محتوا را بر اساس ویژگیهای فیزیکی متحرک میکنند. همه آنها تلاش می کنند یک کار را انجام دهند: صرفه جویی در فضا.
امروزه، ملزومات تجربه کاربر تب ها، یک ناحیه پیمایش دکمه ای است که نمایان بودن محتوا را در یک قاب نمایشگر تغییر می دهد. بسیاری از حوزههای محتوای مختلف فضای یکسانی را به اشتراک میگذارند، اما به صورت مشروط بر اساس دکمه انتخابشده در پیمایش ارائه میشوند.
تاکتیک های وب
در مجموع به لطف چند ویژگی مهم پلتفرم وب، ساخت این مؤلفه را بسیار ساده دیدم:
-
scroll-snap-points
برای تعاملات زیبا با کشیدن انگشت و صفحه کلید با موقعیت های توقف پیمایش مناسب - پیوندهای عمیق از طریق هشهای URL برای پشتیبانی از لنگر انداختن پیمایش درون صفحه و به اشتراکگذاری توسط مرورگر
- پشتیبانی از صفحهخوان با نشانهگذاری عنصر
<a>
وid="#hash"
-
prefers-reduced-motion
برای فعال کردن انتقال متقاطع و پیمایش فوری در صفحه - ویژگی وب پیش نویس
@scroll-timeline
برای خط کشی پویا و تغییر رنگ برگه انتخاب شده
HTML
اساساً، UX در اینجا این است: روی یک پیوند کلیک کنید، نشانی اینترنتی نشان دهنده وضعیت صفحه تو در تو باشد، و سپس بهروزرسانی منطقه محتوا را در حین حرکت مرورگر به عنصر منطبق ببینید.
برخی از اعضای محتوای ساختاری در آن وجود دارد: پیوندها و :target
s. ما به لیستی از پیوندها نیاز داریم که یک <nav>
برای آنها عالی است، و یک لیست از عناصر <article>
که یک <section>
برای آنها عالی است. هر هش پیوند با یک بخش مطابقت دارد و به مرورگر اجازه میدهد از طریق لنگر انداختن موارد را پیمایش کند.
برای مثال، کلیک کردن روی یک پیوند به طور خودکار مقاله :target
در Chrome 89 متمرکز می کند، بدون نیاز به JS. سپس کاربر می تواند محتوای مقاله را با دستگاه ورودی خود مانند همیشه پیمایش کند. همانطور که در نشانه گذاری نشان داده شده است، محتوای مکمل است.
من از نشانه گذاری زیر برای سازماندهی برگه ها استفاده کردم:
<snap-tabs>
<header>
<nav>
<a></a>
<a></a>
<a></a>
<a></a>
</nav>
</header>
<section>
<article></article>
<article></article>
<article></article>
<article></article>
</section>
</snap-tabs>
من می توانم بین عناصر <a>
و <article>
با ویژگی های href
و id
مانند این ارتباط برقرار کنم:
<snap-tabs>
<header>
<nav>
<a href="#responsive"></a>
<a href="#accessible"></a>
<a href="#overscroll"></a>
<a href="#more"></a>
</nav>
</header>
<section>
<article id="responsive"></article>
<article id="accessible"></article>
<article id="overscroll"></article>
<article id="more"></article>
</section>
</snap-tabs>
سپس مقالات را با مقادیر ترکیبی لورم، و پیوندها را با طول و مجموعه تصویر ترکیبی از عناوین پر کردم. با محتوا برای کار، می توانیم طرح بندی را شروع کنیم.
طرح بندی های پیمایشی
3 نوع مختلف ناحیه اسکرول در این کامپوننت وجود دارد:
- ناوبری (صورتی) به صورت افقی قابل پیمایش است
- ناحیه محتوا (آبی) به صورت افقی قابل پیمایش است
- هر مورد مقاله (سبز) به صورت عمودی قابل پیمایش است.
2 نوع عنصر مختلف در پیمایش وجود دارد:
- یک پنجره
جعبه ای با ابعاد تعریف شده که دارای سبک ویژگیoverflow
است. - یک سطح بزرگ
در این طرح، این ظروف فهرست است: پیوندهای ناوبری، مقالات بخش، و محتوای مقاله.
طرح بندی <snap-tabs>
طرح سطح بالایی که من انتخاب کردم فلکس (Flexbox) بود. من جهت را روی column
قرار دادم، بنابراین سرصفحه و بخش به صورت عمودی مرتب می شوند. این اولین پنجره اسکرول ما است و همه چیز را با سرریز پنهان پنهان می کند. سرصفحه و بخش به زودی از overscroll به عنوان مناطق جداگانه استفاده می کنند.
<snap-tabs> <header></header> <section></section> </snap-tabs>
snap-tabs { display: flex; flex-direction: column; /* establish primary containing box */ overflow: hidden; position: relative; & > section { /* be pushy about consuming all space */ block-size: 100%; } & > header { /* defend againstneeding 100% */ flex-shrink: 0; /* fixes cross browser quarks */ min-block-size: fit-content; } }
اشاره به نمودار رنگارنگ 3 پیمایشی:
-
<header>
اکنون آماده است تا محفظه اسکرول (صورتی) باشد. -
<section>
آماده شده است تا محفظه اسکرول (آبی) باشد.
فریم هایی که در زیر با VisBug هایلایت کرده ام به ما کمک می کنند پنجره هایی را که محفظه های اسکرول ایجاد کرده اند ببینیم.
طرح بندی برگه ها <header>
طرح بعدی تقریباً یکسان است: من از flex برای ایجاد نظم عمودی استفاده می کنم.
<snap-tabs> <header> <nav></nav> <span class="snap-indicator"></span> </header> <section></section> </snap-tabs>
header { display: flex; flex-direction: column; }
.snap-indicator
باید به صورت افقی همراه با گروه پیوندها حرکت کند و این طرح هدر به تنظیم آن مرحله کمک می کند. هیچ عنصری مطلقاً در اینجا وجود ندارد!
بعد، سبک های اسکرول. به نظر می رسد که ما می توانیم سبک های اسکرول را بین 2 ناحیه اسکرول افقی خود (سرصفحه و بخش) به اشتراک بگذاریم، بنابراین من یک کلاس کاربردی ساختم، .scroll-snap-x
.
.scroll-snap-x {
/* browser decide if x is ok to scroll and show bars on, y hidden */
overflow: auto hidden;
/* prevent scroll chaining on x scroll */
overscroll-behavior-x: contain;
/* scrolling should snap children on x */
scroll-snap-type: x mandatory;
@media (hover: none) {
scrollbar-width: none;
&::-webkit-scrollbar {
width: 0;
height: 0;
}
}
}
هرکدام به سرریز در محور x، محفظه اسکرول برای به دام انداختن اسکرول، نوارهای اسکرول پنهان برای دستگاه های لمسی و در نهایت اسکرول برای قفل کردن مناطق ارائه محتوا نیاز دارند. ترتیب برگه صفحهکلید ما در دسترس است و هر گونه تعاملی به طور طبیعی تمرکز میکند. ظروف اسکرول اسنپ نیز تعامل خوبی با سبک چرخ فلکی از صفحه کلید خود دارند.
طرح بندی سربرگ برگه ها <nav>
پیوندهای پیمایش باید در یک خط، بدون شکستگی خط، به صورت عمودی در مرکز قرار گیرند، و هر مورد پیوند باید به محفظه اسکرول اسنپ بچسبد. کار سریع برای CSS 2021!
<nav> <a></a> <a></a> <a></a> <a></a> </nav>
nav { display: flex; & a { scroll-snap-align: start; display: inline-flex; align-items: center; white-space: nowrap; } }
هر پیوند سبک و اندازه خود را دارد، بنابراین طرح ناو فقط باید جهت و جریان را مشخص کند. عرض های منحصر به فرد در موارد ناوبری، انتقال بین برگه ها را سرگرم کننده می کند زیرا نشانگر عرض خود را با هدف جدید تنظیم می کند. بسته به تعداد عناصر موجود در اینجا، مرورگر یک اسکرول بار را نمایش می دهد یا خیر.
طرح بندی برگه ها <section>
این بخش یک آیتم انعطاف پذیر است و باید مصرف کننده غالب فضا باشد. همچنین نیاز به ایجاد ستون هایی برای قرار دادن مقالات دارد. باز هم، کار سریع برای CSS 2021! block-size: 100%
این عنصر را کشیده تا والد تا حد امکان پر شود، سپس برای طرح بندی خود، یک سری ستون ایجاد می کند که 100%
عرض والد است. درصدها در اینجا عالی عمل میکنند، زیرا ما محدودیتهای قوی روی والد نوشتهایم.
<section> <article></article> <article></article> <article></article> <article></article> </section>
section { block-size: 100%; display: grid; grid-auto-flow: column; grid-auto-columns: 100%; }
مثل این است که می گوییم "تا حد امکان به صورت عمودی گسترش یابد، به روشی فشاری" (هدری را که روی flex-shrink: 0
به یاد داشته باشید: این یک دفاع در برابر این فشار انبساط است) که ارتفاع ردیف را برای یک تنظیم می کند. مجموعه ای از ستون های تمام ارتفاع سبک auto-flow
به شبکه می گوید که همیشه کودکان را در یک خط افقی، بدون بسته بندی، دقیقاً همان چیزی که ما می خواهیم قرار دهد. برای سرریز کردن پنجره والد.
برای من سخت است که گاهی اوقات سرم را به اطراف بپیچم! این عنصر بخش در یک جعبه قرار می گیرد، اما مجموعه ای از جعبه ها را نیز ایجاد می کند. امیدوارم تصاویر و توضیحات کمک کننده باشد.
طرح بندی برگه ها <article>
کاربر باید بتواند محتوای مقاله را پیمایش کند و نوارهای پیمایش فقط در صورت سرریز شدن باید نمایش داده شوند. این عناصر مقاله در موقعیت منظمی قرار دارند. آنها به طور همزمان والد طومار و فرزند طومار هستند. مرورگر واقعاً در اینجا برخی از تعاملات لمسی، ماوس و صفحه کلید را برای ما انجام می دهد.
<article> <h2></h2> <p></p> <p></p> <h2></h2> <p></p> <p></p> ... </article>
article { scroll-snap-align: start; overflow-y: auto; overscroll-behavior-y: contain; }
من تصمیم گرفتم که مقالات در اسکرول والد خود بچسبند. من واقعاً دوست دارم که چگونه آیتمهای پیوند پیمایش و عناصر مقاله به شروع درونی محفظههای اسکرول مربوطه خود میچسبند. به نظر می رسد و احساس می کند که یک رابطه هماهنگ است.
این مقاله یک فرزند شبکه است و اندازه آن از پیش تعیین شده است که میخواهیم UX اسکرول را ارائه دهیم. این به این معنی است که من در اینجا به هیچ سبک ارتفاع یا عرض نیاز ندارم، فقط باید نحوه سرریز شدن آن را تعریف کنم. من overflow-y را روی خودکار تنظیم کردم و سپس تعاملات اسکرول را با ویژگی overscroll-behavior مفید به دام انداختم.
خلاصه 3 ناحیه اسکرول
در زیر من در تنظیمات سیستم خود "همیشه نوارهای پیمایش نشان داده شود" را انتخاب کرده ام. فکر میکنم کار با این تنظیم برای چیدمان دو چندان مهم است، زیرا برای من این است که طرحبندی و هماهنگسازی اسکرول را بررسی کنم.
من فکر می کنم دیدن ناودان اسکرول در این مؤلفه کمک می کند تا به وضوح نشان دهیم که مناطق اسکرول کجا هستند، جهتی که پشتیبانی می کنند و نحوه تعامل آنها با یکدیگر. در نظر بگیرید که چگونه هر یک از این قابهای پنجره پیمایشی برای یک چیدمان منعطف یا مشبک هستند.
DevTools می تواند به ما در تجسم این موضوع کمک کند:
طرحبندیهای پیمایش کامل هستند: snapping، عمیق قابل پیوند، و صفحه کلید قابل دسترسی. پایه ای قوی برای بهبود UX، سبک و لذت.
برجسته ویژگی
کودکان اسکرول شده در هنگام تغییر اندازه موقعیت قفل خود را حفظ می کنند. این بدان معناست که جاوا اسکریپت در چرخش دستگاه یا تغییر اندازه مرورگر نیازی به نمایش چیزی ندارد. آن را در حالت دستگاه Chromium DevTools با انتخاب هر حالتی غیر از Responsive و سپس تغییر اندازه قاب دستگاه امتحان کنید. توجه داشته باشید که عنصر در نمای باقی می ماند و با محتوای خود قفل می شود. از زمانی که Chromium اجرای خود را برای مطابقت با مشخصات بهروزرسانی کرد، این مورد در دسترس است. در اینجا یک پست وبلاگ در مورد آن است.
انیمیشن
هدف کار انیمیشن در اینجا این است که به وضوح تعاملات را با بازخورد UI پیوند دهد. این کمک می کند تا کاربر را برای کشف یکپارچه (امیدواریم) همه محتوا راهنمایی یا کمک کند. من حرکت را با هدف و مشروط اضافه خواهم کرد. کاربران اکنون می توانند تنظیمات برگزیده حرکت خود را در سیستم عامل خود مشخص کنند و من کاملاً از پاسخ دادن به ترجیحات آنها در رابط های خود لذت می برم.
من یک زیر خط برگه را با موقعیت اسکرول مقاله پیوند خواهم داد. Snapping نه تنها یک تراز زیبا است، بلکه شروع و پایان یک انیمیشن را نیز ثابت می کند. این کار <nav>
را که مانند یک نقشه کوچک عمل می کند، به محتوا متصل نگه می دارد. ما اولویت حرکت کاربر را از CSS و JS بررسی خواهیم کرد. چند مکان عالی وجود دارد که باید مورد توجه قرار گیرد!
رفتار اسکرول
فرصتی برای بهبود رفتار حرکتی :target
و element.scrollIntoView()
وجود دارد. به طور پیش فرض، آنی است. مرورگر فقط موقعیت اسکرول را تنظیم می کند. خوب، اگر بخواهیم به جای پلک زدن در آنجا به آن موقعیت اسکرول منتقل شویم، چه؟
@media (prefers-reduced-motion: no-preference) {
.scroll-snap-x {
scroll-behavior: smooth;
}
}
از آنجایی که ما در اینجا حرکت را معرفی می کنیم، و حرکتی را که کاربر کنترل نمی کند (مانند پیمایش)، فقط در صورتی این سبک را اعمال می کنیم که کاربر در سیستم عامل خود ترجیحی در مورد حرکت کاهش یافته نداشته باشد. به این ترتیب، ما فقط حرکت اسکرول را برای افرادی که با آن موافق هستند معرفی می کنیم.
نشانگر زبانه ها
هدف این انیمیشن کمک به مرتبط کردن شاخص با وضعیت محتوا است. من تصمیم گرفتم برای کاربرانی که حرکت کاهشیافته را ترجیح میدهند، سبکهای متقاطع border-bottom
را رنگآمیزی کنم، و برای کاربرانی که با حرکت خوب هستند، یک انیمیشن اسلاید + محو رنگی پیوند خورده را رنگ آمیزی کنم.
در Chromium Devtools، میتوانم اولویت را تغییر دهم و 2 سبک انتقال مختلف را نشان دهم. من از ساختن این بسیار لذت بردم.
@media (prefers-reduced-motion: reduce) {
snap-tabs > header a {
border-block-end: var(--indicator-size) solid hsl(var(--accent) / 0%);
transition: color .7s ease, border-color .5s ease;
&:is(:target,:active,[active]) {
color: var(--text-active-color);
border-block-end-color: hsl(var(--accent));
}
}
snap-tabs .snap-indicator {
visibility: hidden;
}
}
هنگامی که کاربر حرکت کاهش یافته را ترجیح می دهد .snap-indicator
را پنهان می کنم زیرا من دیگر به آن نیاز ندارم. سپس آن را با سبکهای border-block-end
و یک transition
جایگزین میکنم. همچنین در تعامل برگهها توجه کنید که آیتم navver فعال نه تنها دارای برجستهسازی زیر نام تجاری است، بلکه رنگ متن آن نیز تیرهتر است. عنصر فعال دارای کنتراست رنگ متن بالاتر و لهجه زیر نور روشن است.
فقط چند خط اضافی از CSS باعث می شود کسی احساس کند دیده می شود (به این معنا که ما با دقت به اولویت های حرکتی آنها احترام می گذاریم). من آن را دوست دارم.
@scroll-timeline
در بخش بالا به شما نشان دادم که چگونه سبکهای متقاطع حرکت کاهشیافته را مدیریت میکنم، و در این بخش به شما نشان میدهم که چگونه نشانگر و یک ناحیه اسکرول را به هم مرتبط کردم. این چند چیز تجربی سرگرم کننده در ادامه است. امیدوارم شما هم مثل من هیجان زده باشید.
const { matches:motionOK } = window.matchMedia(
'(prefers-reduced-motion: no-preference)'
);
من ابتدا اولویت حرکت کاربر را از جاوا اسکریپت بررسی می کنم. اگر نتیجه این false
باشد، به این معنی که کاربر حرکت کاهشیافته را ترجیح میدهد، هیچ یک از افکتهای حرکتی پیوند اسکرول را اجرا نمیکنیم.
if (motionOK) {
// motion based animation code
}
در زمان نوشتن این مطلب، پشتیبانی مرورگر برای @scroll-timeline
وجود ندارد. این یک پیش نویس مشخصات با پیاده سازی های آزمایشی است. این یک پلی فیل دارد که من در این نسخه نمایشی از آن استفاده می کنم.
ScrollTimeline
در حالی که CSS و جاوا اسکریپت می توانند هر دو جدول زمانی اسکرول ایجاد کنند، من جاوا اسکریپت را انتخاب کردم تا بتوانم از اندازه گیری عناصر زنده در انیمیشن استفاده کنم.
const sectionScrollTimeline = new ScrollTimeline({
scrollSource: tabsection, // snap-tabs > section
orientation: 'inline', // scroll in the direction letters flow
fill: 'both', // bi-directional linking
});
من میخواهم یک چیز از موقعیت اسکرول دیگری پیروی کند، و با ایجاد یک ScrollTimeline
درایور پیوند اسکرول، scrollSource
تعریف میکنم. به طور معمول یک انیمیشن در وب با یک تیک فریم زمانی جهانی اجرا می شود، اما با یک بخش سفارشی sectionScrollTimeline
در حافظه، می توانم همه آن را تغییر دهم.
tabindicator.animate({
transform: ...,
width: ...,
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
قبل از اینکه وارد فریمهای کلیدی انیمیشن بشوم، فکر میکنم مهم است که به دنبال کننده پیمایش اشاره کنیم، tabindicator
، بر اساس یک جدول زمانی سفارشی، اسکرول بخش ما، متحرک خواهد شد. این پیوند را کامل میکند، اما عنصر نهایی، نقاط حالتی برای متحرک کردن، که به عنوان فریمهای کلیدی نیز شناخته میشوند را از دست میدهد.
فریم های کلیدی پویا
یک روش CSS کاملاً قدرتمند برای متحرک سازی با @scroll-timeline
وجود دارد، اما انیمیشنی که من انتخاب کردم بسیار پویا بود. هیچ راهی برای انتقال بین عرض auto
وجود ندارد، و هیچ راهی برای ایجاد پویا تعدادی فریم کلیدی بر اساس طول کودکان وجود ندارد.
با این حال، جاوا اسکریپت می داند که چگونه این اطلاعات را به دست آورد، بنابراین ما خودمان روی بچه ها تکرار می کنیم و مقادیر محاسبه شده را در زمان اجرا می گیریم:
tabindicator.animate({
transform: [...tabnavitems].map(({offsetLeft}) =>
`translateX(${offsetLeft}px)`),
width: [...tabnavitems].map(({offsetWidth}) =>
`${offsetWidth}px`)
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
برای هر tabnavitem
، موقعیت offsetLeft
تخریب کنید و رشته ای را برگردانید که از آن به عنوان مقدار translateX
استفاده می کند. این 4 فریم کلیدی تبدیل برای انیمیشن ایجاد می کند. همین کار برای عرض انجام می شود، از هر کدام پرسیده می شود که عرض پویا چقدر است و سپس به عنوان یک مقدار فریم کلیدی استفاده می شود.
در اینجا نمونه خروجی، بر اساس فونت ها و ترجیحات مرورگر من است:
فریم های کلیدی TranslateX:
[...tabnavitems].map(({offsetLeft}) =>
`translateX(${offsetLeft}px)`)
// results in 4 array items, which represent 4 keyframe states
// ["translateX(0px)", "translateX(121px)", "translateX(238px)", "translateX(464px)"]
فریم های کلیدی عرض:
[...tabnavitems].map(({offsetWidth}) =>
`${offsetWidth}px`)
// results in 4 array items, which represent 4 keyframe states
// ["121px", "117px", "226px", "67px"]
برای خلاصه کردن استراتژی، اکنون نشانگر برگه بسته به موقعیت اسکرول اسکرول بخش در 4 فریم کلیدی متحرک می شود. نقاط ضربهگیر، خطوط مشخصی را بین فریمهای کلیدی ما ایجاد میکنند و واقعاً به حس همگامسازی انیمیشن میافزایند.
کاربر انیمیشن را با تعامل خود هدایت می کند، مشاهده می کند که عرض و موقعیت نشانگر از یک بخش به بخش دیگر تغییر می کند و با اسکرول کاملاً ردیابی می کند.
شاید متوجه نشده باشید، اما من به تغییر رنگ با انتخاب آیتم پیمایش برجسته شده افتخار می کنم.
زمانی که مورد برجسته شده کنتراست بیشتری داشته باشد، خاکستری روشنتر انتخابنشده حتی بیشتر به عقب رانده میشود. انتقال رنگ برای متن معمول است، مانند روی شناور و زمانی که انتخاب شده است، اما انتقال آن رنگ در اسکرول، همگام با نشانگر زیرخط، سطح بعدی است.
در اینجا نحوه انجام من این است:
tabnavitems.forEach(navitem => {
navitem.animate({
color: [...tabnavitems].map(item =>
item === navitem
? `var(--text-active-color)`
: `var(--text-color)`)
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
});
هر پیوند ناوبری برگه به این انیمیشن رنگی جدید نیاز دارد، که همان جدول زمانی اسکرول را به عنوان نشانگر زیرخط ردیابی می کند. من از همان تایم لاین قبلی استفاده می کنم: از آنجایی که نقش آن انتشار یک تیک در اسکرول است، می توانیم از آن تیک در هر نوع انیمیشنی که می خواهیم استفاده کنیم. همانطور که قبلاً انجام دادم، 4 فریم کلیدی در حلقه ایجاد می کنم و رنگ ها را برمی گردم.
[...tabnavitems].map(item =>
item === navitem
? `var(--text-active-color)`
: `var(--text-color)`)
// results in 4 array items, which represent 4 keyframe states
// [
"var(--text-active-color)",
"var(--text-color)",
"var(--text-color)",
"var(--text-color)",
]
فریم کلیدی با رنگ var(--text-active-color)
پیوند را برجسته می کند و در غیر این صورت یک رنگ متن استاندارد است. حلقه تودرتو در آنجا آن را نسبتاً ساده می کند، زیرا حلقه بیرونی هر مورد ناوبری است و حلقه داخلی فریم های کلیدی شخصی هر یک از موارد ناوبری است. بررسی میکنم که آیا عنصر حلقه بیرونی مشابه حلقه داخلی است یا نه، و از آن برای اطلاع از انتخاب آن استفاده میکنم.
از نوشتن این مطلب خیلی لذت بردم. خیلی
حتی پیشرفت های بیشتر جاوا اسکریپت
شایان ذکر است که هسته چیزی که در اینجا به شما نشان می دهم بدون جاوا اسکریپت کار می کند. با این اوصاف، بیایید ببینیم چگونه میتوانیم آن را هنگامی که JS در دسترس است، تقویت کنیم.
پیوندهای عمیق
پیوندهای عمیق بیشتر یک اصطلاح تلفن همراه هستند، اما من فکر میکنم هدف از پیوند عمیق در اینجا با برگهها برآورده میشود که میتوانید URL را مستقیماً با محتوای یک برگه به اشتراک بگذارید. مرورگر درون صفحه به شناسه ای که در هش URL مطابقت دارد پیمایش می کند. من متوجه شدم که این کنترل کننده onload
اثر را در سراسر پلتفرم ها ایجاد می کند.
window.onload = () => {
if (location.hash) {
tabsection.scrollLeft = document
.querySelector(location.hash)
.offsetLeft;
}
}
همگام سازی پایان پیمایش
کاربران ما همیشه روی صفحهکلید کلیک نمیکنند یا از صفحهکلید استفاده نمیکنند، گاهی اوقات آنطور که باید بتوانند به صورت رایگان پیمایش میکنند. وقتی پیمایش بخش پیمایش را متوقف میکند، هر کجا که فرود میآید باید در نوار پیمایش بالا مطابقت داده شود.
در اینجا چگونه منتظر پایان اسکرول هستم: js tabsection.addEventListener('scroll', () => { clearTimeout(tabsection.scrollEndTimer); tabsection.scrollEndTimer = setTimeout(determineActiveTabSection, 100); });
هر زمان که بخشها در حال پیمایش هستند، در صورت وجود زمانبندی بخش را پاک کنید و قسمت جدیدی را شروع کنید. وقتی بخشها دیگر پیمایش نمیشوند، مهلت زمانی را پاک نکنید و 100 میلیثانیه پس از استراحت شلیک کنید. هنگامی که فعال می شود، تابعی را فراخوانی کنید که به دنبال تشخیص مکان توقف کاربر است.
const determineActiveTabSection = () => {
const i = tabsection.scrollLeft / tabsection.clientWidth;
const matchingNavItem = tabnavitems[i];
matchingNavItem && setActiveTab(matchingNavItem);
};
با فرض قطع شدن اسکرول، تقسیم موقعیت اسکرول فعلی از عرض ناحیه اسکرول باید به یک عدد صحیح و نه اعشاری منجر شود. سپس سعی میکنم از طریق این شاخص محاسبهشده، یک navitem از حافظه پنهان خود بگیرم و اگر چیزی پیدا کرد، مسابقه را برای فعال شدن ارسال میکنم.
const setActiveTab = tabbtn => {
tabnav
.querySelector(':scope a[active]')
.removeAttribute('active');
tabbtn.setAttribute('active', '');
tabbtn.scrollIntoView();
};
تنظیم برگه فعال با پاک کردن هر برگه فعال در حال حاضر شروع می شود، سپس به آیتم ناوبری ورودی ویژگی حالت فعال می دهد. فراخوانی scrollIntoView()
تعامل جالبی با CSS دارد که شایان ذکر است.
.scroll-snap-x {
overflow: auto hidden;
overscroll-behavior-x: contain;
scroll-snap-type: x mandatory;
@media (prefers-reduced-motion: no-preference) {
scroll-behavior: smooth;
}
}
در CSS ابزار اسکرول افقی، ما یک درخواست رسانه تو در تو قرار داده ایم که در صورتی که کاربر تحمل حرکت را داشته باشد، پیمایش smooth
را اعمال می کند. جاوا اسکریپت میتواند آزادانه برای اسکرول عناصر تماس برقرار کند، و CSS میتواند UX را بهطور آشکار مدیریت کند. کبریت کوچک بسیار لذت بخشی که گاهی اوقات درست می کنند.
نتیجه گیری
حالا که می دانی من چگونه این کار را انجام دادم، شما چطور؟! این باعث می شود معماری اجزای سرگرم کننده ای ایجاد شود! چه کسی می خواهد نسخه اول را با اسلات در چارچوب مورد علاقه خود بسازد؟ 🙂
بیایید رویکردهای خود را متنوع کنیم و همه راههای ساخت در وب را بیاموزیم. یک اشکال ایجاد کنید، نسخه خود را برای من توییت کنید ، و من آن را به بخش ریمیکس های انجمن در زیر اضافه می کنم.
ریمیکس های انجمن
- @devnook ، @rob_dodson ، و @DasSurma با اجزای وب: مقاله .
- @jhvanderschee با دکمه ها: Codepen .
یک نمای کلی از نحوه ساخت یک مؤلفه برگه ها مشابه آنچه در برنامه های iOS و Android یافت می شود.
در این پست میخواهم تفکری را در مورد ساخت یک جزء Tabs برای وب به اشتراک بگذارم که واکنشگرا باشد، از ورودیهای چندگانه دستگاه پشتیبانی کند و در مرورگرها کار کند. نسخه ی نمایشی را امتحان کنید.
اگر ویدیو را ترجیح می دهید، در اینجا یک نسخه YouTube از این پست وجود دارد:
نمای کلی
زبانه ها جزء رایج سیستم های طراحی هستند اما می توانند اشکال و اشکال مختلفی داشته باشند. ابتدا برگههای دسکتاپ بر روی عنصر <frame>
ساخته شده بودند، و اکنون مؤلفههای موبایل کرهای داریم که محتوا را بر اساس ویژگیهای فیزیکی متحرک میکنند. همه آنها تلاش می کنند یک کار را انجام دهند: صرفه جویی در فضا.
امروزه، ملزومات تجربه کاربر تب ها، یک ناحیه پیمایش دکمه ای است که نمایان بودن محتوا را در یک قاب نمایشگر تغییر می دهد. بسیاری از حوزههای محتوای مختلف فضای یکسانی را به اشتراک میگذارند، اما به صورت مشروط بر اساس دکمه انتخابشده در پیمایش ارائه میشوند.
تاکتیک های وب
در مجموع به لطف چند ویژگی مهم پلتفرم وب، ساخت این مؤلفه را بسیار ساده دیدم:
-
scroll-snap-points
برای تعاملات زیبا با کشیدن انگشت و صفحه کلید با موقعیت های توقف پیمایش مناسب - پیوندهای عمیق از طریق هشهای URL برای پشتیبانی از لنگر انداختن پیمایش درون صفحه و به اشتراکگذاری توسط مرورگر
- پشتیبانی از صفحهخوان با نشانهگذاری عنصر
<a>
وid="#hash"
-
prefers-reduced-motion
برای فعال کردن انتقال متقاطع و پیمایش فوری در صفحه - ویژگی وب پیش نویس
@scroll-timeline
برای خط کشی پویا و تغییر رنگ برگه انتخاب شده
HTML
اساساً، UX در اینجا این است: روی یک پیوند کلیک کنید، نشانی اینترنتی نشان دهنده وضعیت صفحه تو در تو باشد، و سپس بهروزرسانی منطقه محتوا را در حین حرکت مرورگر به عنصر منطبق ببینید.
برخی از اعضای محتوای ساختاری در آن وجود دارد: پیوندها و :target
s. ما به لیستی از پیوندها نیاز داریم که یک <nav>
برای آنها عالی است، و یک لیست از عناصر <article>
که یک <section>
برای آنها عالی است. هر هش پیوند با یک بخش مطابقت دارد و به مرورگر اجازه میدهد از طریق لنگر انداختن موارد را پیمایش کند.
برای مثال، کلیک کردن روی یک پیوند به طور خودکار مقاله :target
در Chrome 89 متمرکز می کند، بدون نیاز به JS. سپس کاربر می تواند محتوای مقاله را با دستگاه ورودی خود مانند همیشه پیمایش کند. همانطور که در نشانه گذاری نشان داده شده است، محتوای مکمل است.
من از نشانه گذاری زیر برای سازماندهی برگه ها استفاده کردم:
<snap-tabs>
<header>
<nav>
<a></a>
<a></a>
<a></a>
<a></a>
</nav>
</header>
<section>
<article></article>
<article></article>
<article></article>
<article></article>
</section>
</snap-tabs>
من می توانم بین عناصر <a>
و <article>
با ویژگی های href
و id
مانند این ارتباط برقرار کنم:
<snap-tabs>
<header>
<nav>
<a href="#responsive"></a>
<a href="#accessible"></a>
<a href="#overscroll"></a>
<a href="#more"></a>
</nav>
</header>
<section>
<article id="responsive"></article>
<article id="accessible"></article>
<article id="overscroll"></article>
<article id="more"></article>
</section>
</snap-tabs>
سپس مقالات را با مقادیر ترکیبی لورم، و پیوندها را با طول و مجموعه تصویر ترکیبی از عناوین پر کردم. با محتوا برای کار، می توانیم طرح بندی را شروع کنیم.
طرح بندی های پیمایشی
3 نوع مختلف ناحیه اسکرول در این کامپوننت وجود دارد:
- ناوبری (صورتی) به صورت افقی قابل پیمایش است
- ناحیه محتوا (آبی) به صورت افقی قابل پیمایش است
- هر مورد مقاله (سبز) به صورت عمودی قابل پیمایش است.
2 نوع عنصر مختلف در پیمایش وجود دارد:
- یک پنجره
جعبه ای با ابعاد تعریف شده که دارای سبک ویژگیoverflow
است. - یک سطح بزرگ
در این طرح، این ظروف فهرست است: پیوندهای ناوبری، مقالات بخش، و محتوای مقاله.
طرح بندی <snap-tabs>
طرح سطح بالایی که من انتخاب کردم فلکس (Flexbox) بود. من جهت را روی column
قرار دادم، بنابراین سرصفحه و بخش به صورت عمودی مرتب می شوند. این اولین پنجره اسکرول ما است و همه چیز را با سرریز پنهان پنهان می کند. سرصفحه و بخش به زودی از overscroll به عنوان مناطق جداگانه استفاده می کنند.
<snap-tabs> <header></header> <section></section> </snap-tabs>
snap-tabs { display: flex; flex-direction: column; /* establish primary containing box */ overflow: hidden; position: relative; & > section { /* be pushy about consuming all space */ block-size: 100%; } & > header { /* defend againstneeding 100% */ flex-shrink: 0; /* fixes cross browser quarks */ min-block-size: fit-content; } }
اشاره به نمودار رنگارنگ 3 پیمایشی:
-
<header>
اکنون آماده است تا محفظه اسکرول (صورتی) باشد. -
<section>
آماده شده است تا محفظه اسکرول (آبی) باشد.
فریم هایی که در زیر با VisBug هایلایت کرده ام به ما کمک می کنند پنجره هایی را که محفظه های اسکرول ایجاد کرده اند ببینیم.
طرح بندی برگه ها <header>
طرح بعدی تقریباً یکسان است: من از flex برای ایجاد نظم عمودی استفاده می کنم.
<snap-tabs> <header> <nav></nav> <span class="snap-indicator"></span> </header> <section></section> </snap-tabs>
header { display: flex; flex-direction: column; }
.snap-indicator
باید به صورت افقی همراه با گروه پیوندها حرکت کند و این طرح هدر به تنظیم آن مرحله کمک می کند. هیچ عنصری مطلقاً در اینجا وجود ندارد!
بعد، سبک های اسکرول. به نظر می رسد که ما می توانیم سبک های اسکرول را بین 2 ناحیه اسکرول افقی خود (سرصفحه و بخش) به اشتراک بگذاریم، بنابراین من یک کلاس کاربردی ساختم، .scroll-snap-x
.
.scroll-snap-x {
/* browser decide if x is ok to scroll and show bars on, y hidden */
overflow: auto hidden;
/* prevent scroll chaining on x scroll */
overscroll-behavior-x: contain;
/* scrolling should snap children on x */
scroll-snap-type: x mandatory;
@media (hover: none) {
scrollbar-width: none;
&::-webkit-scrollbar {
width: 0;
height: 0;
}
}
}
هرکدام به سرریز در محور x، محفظه اسکرول برای به دام انداختن اسکرول، نوارهای اسکرول پنهان برای دستگاه های لمسی و در نهایت اسکرول برای قفل کردن مناطق ارائه محتوا نیاز دارند. ترتیب برگه صفحهکلید ما در دسترس است و هر گونه تعاملی به طور طبیعی تمرکز میکند. ظروف اسکرول اسنپ نیز تعامل خوبی با سبک چرخ فلکی از صفحه کلید خود دارند.
طرح بندی سربرگ برگه ها <nav>
پیوندهای پیمایش باید در یک خط، بدون شکستگی خط، به صورت عمودی در مرکز قرار گیرند، و هر مورد پیوند باید به محفظه اسکرول اسنپ بچسبد. کار سریع برای CSS 2021!
<nav> <a></a> <a></a> <a></a> <a></a> </nav>
nav { display: flex; & a { scroll-snap-align: start; display: inline-flex; align-items: center; white-space: nowrap; } }
هر پیوند سبک و اندازه خود را دارد، بنابراین طرح ناو فقط باید جهت و جریان را مشخص کند. عرض های منحصر به فرد در موارد ناوبری، انتقال بین برگه ها را سرگرم کننده می کند زیرا نشانگر عرض خود را با هدف جدید تنظیم می کند. بسته به تعداد عناصر موجود در اینجا، مرورگر یک اسکرول بار را نمایش می دهد یا خیر.
طرح بندی برگه ها <section>
این بخش یک آیتم انعطاف پذیر است و باید مصرف کننده غالب فضا باشد. همچنین نیاز به ایجاد ستون هایی برای قرار دادن مقالات دارد. باز هم، کار سریع برای CSS 2021! block-size: 100%
این عنصر را کشیده تا والد تا حد امکان پر شود، سپس برای طرح بندی خود، یک سری ستون ایجاد می کند که 100%
عرض والد است. درصدها در اینجا عالی عمل میکنند، زیرا ما محدودیتهای قوی روی والد نوشتهایم.
<section> <article></article> <article></article> <article></article> <article></article> </section>
section { block-size: 100%; display: grid; grid-auto-flow: column; grid-auto-columns: 100%; }
مثل این است که می گوییم "تا حد امکان به صورت عمودی گسترش یابد، به روشی فشاری" (هدری را که روی flex-shrink: 0
به یاد داشته باشید: این یک دفاع در برابر این فشار انبساط است) که ارتفاع ردیف را برای یک تنظیم می کند. مجموعه ای از ستون های تمام ارتفاع سبک auto-flow
به شبکه می گوید که همیشه کودکان را در یک خط افقی، بدون بسته بندی، دقیقاً همان چیزی که ما می خواهیم قرار دهد. برای سرریز کردن پنجره والد.
برای من سخت است که گاهی اوقات سرم را به اطراف بپیچم! این عنصر بخش در یک جعبه قرار می گیرد، اما مجموعه ای از جعبه ها را نیز ایجاد می کند. امیدوارم تصاویر و توضیحات کمک کننده باشد.
طرح بندی برگه ها <article>
کاربر باید بتواند محتوای مقاله را پیمایش کند و نوارهای پیمایش فقط در صورت سرریز شدن باید نمایش داده شوند. این عناصر مقاله در موقعیت منظمی قرار دارند. آنها به طور همزمان والد طومار و فرزند طومار هستند. مرورگر واقعاً در اینجا برخی از تعاملات لمسی، ماوس و صفحه کلید را برای ما انجام می دهد.
<article> <h2></h2> <p></p> <p></p> <h2></h2> <p></p> <p></p> ... </article>
article { scroll-snap-align: start; overflow-y: auto; overscroll-behavior-y: contain; }
من تصمیم گرفتم که مقالات در اسکرول والد خود بچسبند. من واقعاً دوست دارم که چگونه آیتمهای پیوند پیمایش و عناصر مقاله به شروع درونی محفظههای اسکرول مربوطه خود میچسبند. به نظر می رسد و احساس می کند که یک رابطه هماهنگ است.
این مقاله یک فرزند شبکه است و اندازه آن از پیش تعیین شده است که میخواهیم UX اسکرول را ارائه دهیم. این به این معنی است که من در اینجا به هیچ سبک ارتفاع یا عرض نیاز ندارم، فقط باید نحوه سرریز شدن آن را تعریف کنم. من overflow-y را روی خودکار تنظیم کردم و سپس تعاملات اسکرول را با ویژگی overscroll-behavior مفید به دام انداختم.
خلاصه 3 ناحیه اسکرول
در زیر من در تنظیمات سیستم خود "همیشه نوارهای پیمایش نشان داده شود" را انتخاب کرده ام. فکر میکنم کار با این تنظیم برای چیدمان دو چندان مهم است، زیرا برای من این است که طرحبندی و هماهنگسازی اسکرول را بررسی کنم.
من فکر می کنم دیدن ناودان اسکرول در این مؤلفه کمک می کند تا به وضوح نشان دهیم که مناطق اسکرول کجا هستند، جهتی که پشتیبانی می کنند و نحوه تعامل آنها با یکدیگر. در نظر بگیرید که چگونه هر یک از این قابهای پنجره پیمایشی برای یک چیدمان منعطف یا مشبک هستند.
DevTools می تواند به ما در تجسم این موضوع کمک کند:
طرحبندیهای پیمایش کامل هستند: snapping، عمیق قابل پیوند، و صفحه کلید قابل دسترسی. پایه ای قوی برای بهبود UX، سبک و لذت.
برجسته ویژگی
کودکان اسکرول شده در هنگام تغییر اندازه موقعیت قفل خود را حفظ می کنند. این بدان معناست که جاوا اسکریپت در چرخش دستگاه یا تغییر اندازه مرورگر نیازی به نمایش چیزی ندارد. آن را در حالت دستگاه Chromium DevTools با انتخاب هر حالتی غیر از Responsive و سپس تغییر اندازه قاب دستگاه امتحان کنید. توجه داشته باشید که عنصر در نمای باقی می ماند و با محتوای خود قفل می شود. از زمانی که Chromium اجرای خود را برای مطابقت با مشخصات بهروزرسانی کرد، این مورد در دسترس است. در اینجا یک پست وبلاگ در مورد آن است.
انیمیشن
هدف کار انیمیشن در اینجا این است که به وضوح تعاملات را با بازخورد UI پیوند دهد. این کمک می کند تا کاربر را برای کشف یکپارچه (امیدواریم) همه محتوا راهنمایی یا کمک کند. من حرکت را با هدف و مشروط اضافه خواهم کرد. کاربران اکنون می توانند تنظیمات برگزیده حرکت خود را در سیستم عامل خود مشخص کنند و من کاملاً از پاسخ دادن به ترجیحات آنها در رابط های خود لذت می برم.
من یک زیر خط برگه را با موقعیت اسکرول مقاله پیوند خواهم داد. Snapping نه تنها یک تراز زیبا است، بلکه شروع و پایان یک انیمیشن را نیز ثابت می کند. این کار <nav>
را که مانند یک نقشه کوچک عمل می کند، به محتوا متصل نگه می دارد. ما اولویت حرکت کاربر را از CSS و JS بررسی خواهیم کرد. چند مکان عالی وجود دارد که باید مورد توجه قرار گیرد!
رفتار اسکرول
فرصتی برای بهبود رفتار حرکتی :target
و element.scrollIntoView()
وجود دارد. به طور پیش فرض، آنی است. مرورگر فقط موقعیت اسکرول را تنظیم می کند. خوب، اگر بخواهیم به جای پلک زدن در آنجا به آن موقعیت اسکرول منتقل شویم، چه؟
@media (prefers-reduced-motion: no-preference) {
.scroll-snap-x {
scroll-behavior: smooth;
}
}
از آنجایی که ما در اینجا حرکت را معرفی می کنیم، و حرکتی را که کاربر کنترل نمی کند (مانند پیمایش)، فقط در صورتی این سبک را اعمال می کنیم که کاربر در سیستم عامل خود ترجیحی در مورد حرکت کاهش یافته نداشته باشد. به این ترتیب، ما فقط حرکت اسکرول را برای افرادی که با آن موافق هستند معرفی می کنیم.
نشانگر زبانه ها
هدف این انیمیشن کمک به مرتبط کردن شاخص با وضعیت محتوا است. من تصمیم گرفتم برای کاربرانی که حرکت کاهشیافته را ترجیح میدهند، سبکهای متقاطع border-bottom
را رنگآمیزی کنم، و برای کاربرانی که با حرکت خوب هستند، یک انیمیشن اسلاید + محو رنگی پیوند خورده را رنگ آمیزی کنم.
در Chromium Devtools، میتوانم اولویت را تغییر دهم و 2 سبک انتقال مختلف را نشان دهم. من از ساختن این بسیار لذت بردم.
@media (prefers-reduced-motion: reduce) {
snap-tabs > header a {
border-block-end: var(--indicator-size) solid hsl(var(--accent) / 0%);
transition: color .7s ease, border-color .5s ease;
&:is(:target,:active,[active]) {
color: var(--text-active-color);
border-block-end-color: hsl(var(--accent));
}
}
snap-tabs .snap-indicator {
visibility: hidden;
}
}
هنگامی که کاربر حرکت کاهش یافته را ترجیح می دهد .snap-indicator
را پنهان می کنم زیرا من دیگر به آن نیاز ندارم. سپس آن را با سبکهای border-block-end
و یک transition
جایگزین میکنم. همچنین در تعامل برگهها توجه کنید که آیتم navver فعال نه تنها دارای برجستهسازی زیر نام تجاری است، بلکه رنگ متن آن نیز تیرهتر است. عنصر فعال دارای کنتراست رنگ متن بالاتر و لهجه زیر نور روشن است.
فقط چند خط اضافی از CSS باعث می شود کسی احساس کند دیده می شود (به این معنا که ما با دقت به اولویت های حرکتی آنها احترام می گذاریم). من آن را دوست دارم.
@scroll-timeline
در بخش بالا به شما نشان دادم که چگونه سبکهای متقاطع حرکت کاهشیافته را مدیریت میکنم، و در این بخش به شما نشان میدهم که چگونه نشانگر و یک ناحیه اسکرول را به هم مرتبط کردم. این چند چیز تجربی سرگرم کننده در ادامه است. امیدوارم شما هم مثل من هیجان زده باشید.
const { matches:motionOK } = window.matchMedia(
'(prefers-reduced-motion: no-preference)'
);
من ابتدا اولویت حرکت کاربر را از جاوا اسکریپت بررسی می کنم. اگر نتیجه این false
باشد، به این معنی که کاربر حرکت کاهشیافته را ترجیح میدهد، هیچ یک از افکتهای حرکتی پیوند اسکرول را اجرا نمیکنیم.
if (motionOK) {
// motion based animation code
}
در زمان نوشتن این مطلب، پشتیبانی مرورگر برای @scroll-timeline
وجود ندارد. این یک پیش نویس مشخصات با پیاده سازی های آزمایشی است. این یک پلی فیل دارد که من در این نسخه نمایشی از آن استفاده می کنم.
ScrollTimeline
در حالی که CSS و جاوا اسکریپت می توانند هر دو جدول زمانی اسکرول ایجاد کنند، من جاوا اسکریپت را انتخاب کردم تا بتوانم از اندازه گیری عناصر زنده در انیمیشن استفاده کنم.
const sectionScrollTimeline = new ScrollTimeline({
scrollSource: tabsection, // snap-tabs > section
orientation: 'inline', // scroll in the direction letters flow
fill: 'both', // bi-directional linking
});
من میخواهم یک چیز از موقعیت اسکرول دیگری پیروی کند، و با ایجاد یک ScrollTimeline
درایور پیوند اسکرول، scrollSource
تعریف میکنم. به طور معمول یک انیمیشن در وب با یک تیک فریم زمانی جهانی اجرا می شود، اما با یک بخش سفارشی sectionScrollTimeline
در حافظه، می توانم همه آن را تغییر دهم.
tabindicator.animate({
transform: ...,
width: ...,
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
قبل از اینکه وارد فریمهای کلیدی انیمیشن بشوم، فکر میکنم مهم است که به دنبال کننده پیمایش اشاره کنیم، tabindicator
، بر اساس یک جدول زمانی سفارشی، اسکرول بخش ما، متحرک خواهد شد. این پیوند را کامل میکند، اما عنصر نهایی، نقاط حالتی برای متحرک کردن، که به عنوان فریمهای کلیدی نیز شناخته میشوند را از دست میدهد.
فریم های کلیدی پویا
یک روش CSS کاملاً قدرتمند برای متحرک سازی با @scroll-timeline
وجود دارد، اما انیمیشنی که من انتخاب کردم بسیار پویا بود. هیچ راهی برای انتقال بین عرض auto
وجود ندارد، و هیچ راهی برای ایجاد پویا تعدادی فریم کلیدی بر اساس طول کودکان وجود ندارد.
با این حال، جاوا اسکریپت می داند که چگونه این اطلاعات را به دست آورد، بنابراین ما خودمان روی بچه ها تکرار می کنیم و مقادیر محاسبه شده را در زمان اجرا می گیریم:
tabindicator.animate({
transform: [...tabnavitems].map(({offsetLeft}) =>
`translateX(${offsetLeft}px)`),
width: [...tabnavitems].map(({offsetWidth}) =>
`${offsetWidth}px`)
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
برای هر tabnavitem
، موقعیت offsetLeft
تخریب کنید و رشته ای را برگردانید که از آن به عنوان مقدار translateX
استفاده می کند. این 4 فریم کلیدی تبدیل برای انیمیشن ایجاد می کند. همین کار برای عرض انجام می شود، از هر کدام پرسیده می شود که عرض پویا چقدر است و سپس به عنوان یک مقدار فریم کلیدی استفاده می شود.
در اینجا نمونه خروجی، بر اساس فونت ها و ترجیحات مرورگر من است:
فریم های کلیدی TranslateX:
[...tabnavitems].map(({offsetLeft}) =>
`translateX(${offsetLeft}px)`)
// results in 4 array items, which represent 4 keyframe states
// ["translateX(0px)", "translateX(121px)", "translateX(238px)", "translateX(464px)"]
فریم های کلیدی عرض:
[...tabnavitems].map(({offsetWidth}) =>
`${offsetWidth}px`)
// results in 4 array items, which represent 4 keyframe states
// ["121px", "117px", "226px", "67px"]
برای خلاصه کردن استراتژی، اکنون نشانگر برگه بسته به موقعیت اسکرول اسکرول بخش در 4 فریم کلیدی متحرک می شود. نقاط ضربهگیر، خطوط مشخصی را بین فریمهای کلیدی ما ایجاد میکنند و واقعاً به حس همگامسازی انیمیشن میافزایند.
کاربر انیمیشن را با تعامل خود هدایت می کند، مشاهده می کند که عرض و موقعیت نشانگر از یک بخش به بخش دیگر تغییر می کند و با اسکرول کاملاً ردیابی می کند.
شاید متوجه نشده باشید، اما من به تغییر رنگ با انتخاب آیتم پیمایش برجسته شده افتخار می کنم.
زمانی که مورد برجسته شده کنتراست بیشتری داشته باشد، خاکستری روشنتر انتخابنشده حتی بیشتر به عقب رانده میشود. انتقال رنگ برای متن معمول است، مانند روی شناور و زمانی که انتخاب شده است، اما انتقال آن رنگ در اسکرول، همگام با نشانگر زیرخط، سطح بعدی است.
در اینجا نحوه انجام من این است:
tabnavitems.forEach(navitem => {
navitem.animate({
color: [...tabnavitems].map(item =>
item === navitem
? `var(--text-active-color)`
: `var(--text-color)`)
}, {
duration: 1000,
fill: 'both',
timeline: sectionScrollTimeline,
}
);
});
هر پیوند ناوبری برگه به این انیمیشن رنگی جدید نیاز دارد، که همان جدول زمانی اسکرول را به عنوان نشانگر زیرخط ردیابی می کند. من از همان تایم لاین قبلی استفاده می کنم: از آنجایی که نقش آن انتشار یک تیک در اسکرول است، می توانیم از آن تیک در هر نوع انیمیشنی که می خواهیم استفاده کنیم. همانطور که قبلاً انجام دادم، 4 فریم کلیدی در حلقه ایجاد می کنم و رنگ ها را برمی گردم.
[...tabnavitems].map(item =>
item === navitem
? `var(--text-active-color)`
: `var(--text-color)`)
// results in 4 array items, which represent 4 keyframe states
// [
"var(--text-active-color)",
"var(--text-color)",
"var(--text-color)",
"var(--text-color)",
]
فریم کلیدی با رنگ var(--text-active-color)
پیوند را برجسته می کند و در غیر این صورت یک رنگ متن استاندارد است. حلقه تودرتو در آنجا آن را نسبتاً ساده می کند، زیرا حلقه بیرونی هر مورد ناوبری است و حلقه داخلی فریم های کلیدی شخصی هر یک از موارد ناوبری است. بررسی میکنم که آیا عنصر حلقه بیرونی مشابه حلقه داخلی است یا نه، و از آن برای اطلاع از انتخاب آن استفاده میکنم.
از نوشتن این مطلب خیلی لذت بردم. خیلی
حتی پیشرفت های بیشتر جاوا اسکریپت
شایان ذکر است که هسته چیزی که در اینجا به شما نشان می دهم بدون جاوا اسکریپت کار می کند. با این اوصاف، بیایید ببینیم چگونه میتوانیم آن را هنگامی که JS در دسترس است، تقویت کنیم.
پیوندهای عمیق
پیوندهای عمیق بیشتر یک اصطلاح تلفن همراه هستند، اما من فکر میکنم هدف از پیوند عمیق در اینجا با برگهها برآورده میشود که میتوانید URL را مستقیماً با محتوای یک برگه به اشتراک بگذارید. مرورگر درون صفحه به شناسه ای که در هش URL مطابقت دارد پیمایش می کند. من متوجه شدم که این کنترل کننده onload
اثر را در سراسر پلتفرم ها ایجاد می کند.
window.onload = () => {
if (location.hash) {
tabsection.scrollLeft = document
.querySelector(location.hash)
.offsetLeft;
}
}
همگام سازی پایان پیمایش
کاربران ما همیشه روی صفحهکلید کلیک نمیکنند یا از صفحهکلید استفاده نمیکنند، گاهی اوقات آنطور که باید بتوانند به صورت رایگان پیمایش میکنند. وقتی پیمایش بخش پیمایش را متوقف میکند، هر کجا که فرود میآید باید در نوار پیمایش بالا مطابقت داده شود.
در اینجا چگونه منتظر پایان اسکرول هستم: js tabsection.addEventListener('scroll', () => { clearTimeout(tabsection.scrollEndTimer); tabsection.scrollEndTimer = setTimeout(determineActiveTabSection, 100); });
هر زمان که بخشها در حال پیمایش هستند، در صورت وجود زمانبندی بخش را پاک کنید و قسمت جدیدی را شروع کنید. وقتی بخشها دیگر پیمایش نمیشوند، مهلت زمانی را پاک نکنید و 100 میلیثانیه پس از استراحت شلیک کنید. هنگامی که فعال می شود، تابعی را فراخوانی کنید که به دنبال تشخیص مکان توقف کاربر است.
const determineActiveTabSection = () => {
const i = tabsection.scrollLeft / tabsection.clientWidth;
const matchingNavItem = tabnavitems[i];
matchingNavItem && setActiveTab(matchingNavItem);
};
با فرض قطع شدن اسکرول، تقسیم موقعیت اسکرول فعلی از عرض ناحیه اسکرول باید به یک عدد صحیح و نه اعشاری منجر شود. سپس سعی میکنم از طریق این شاخص محاسبهشده، یک navitem از حافظه پنهان خود بگیرم و اگر چیزی پیدا کرد، مسابقه را برای فعال شدن ارسال میکنم.
const setActiveTab = tabbtn => {
tabnav
.querySelector(':scope a[active]')
.removeAttribute('active');
tabbtn.setAttribute('active', '');
tabbtn.scrollIntoView();
};
تنظیم برگه فعال با پاک کردن هر برگه فعال در حال حاضر شروع می شود، سپس به آیتم ناوبری ورودی ویژگی حالت فعال می دهد. فراخوانی scrollIntoView()
تعامل جالبی با CSS دارد که شایان ذکر است.
.scroll-snap-x {
overflow: auto hidden;
overscroll-behavior-x: contain;
scroll-snap-type: x mandatory;
@media (prefers-reduced-motion: no-preference) {
scroll-behavior: smooth;
}
}
در CSS ابزار اسکرول افقی، ما یک درخواست رسانه تو در تو قرار داده ایم که در صورتی که کاربر تحمل حرکت را داشته باشد، پیمایش smooth
را اعمال می کند. جاوا اسکریپت میتواند آزادانه برای اسکرول عناصر تماس برقرار کند، و CSS میتواند UX را بهطور آشکار مدیریت کند. کبریت کوچک بسیار لذت بخشی که گاهی اوقات درست می کنند.
نتیجه گیری
حالا که می دانی من چگونه این کار را انجام دادم، شما چطور؟! این باعث می شود معماری اجزای سرگرم کننده ای ایجاد شود! چه کسی می خواهد نسخه اول را با اسلات در چارچوب مورد علاقه خود بسازد؟ 🙂
بیایید رویکردهای خود را متنوع کنیم و همه راههای ساخت در وب را بیاموزیم. یک اشکال ایجاد کنید، نسخه خود را برای من توییت کنید ، و من آن را به بخش ریمیکس های انجمن در زیر اضافه می کنم.
ریمیکس های انجمن
- @devnook ، @rob_dodson ، و @DasSurma با اجزای وب: مقاله .
- @jhvanderschee با دکمه ها: Codepen .