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

TL; DR

ویژگی CSS overscroll-behavior به توسعه دهندگان این امکان را می دهد تا هنگام رسیدن به بالا/پایین محتوا، رفتار پیمایش سرریز پیش فرض مرورگر را نادیده بگیرند. موارد استفاده عبارتند از غیرفعال کردن ویژگی کشش برای تازه کردن در تلفن همراه، حذف درخشش overscroll و جلوه‌های لاستیک‌بندی، و جلوگیری از پیمایش محتوای صفحه در زمانی که زیر یک مودال/پوشش قرار دارد.

پس زمینه

اسکرول مرزها و اسکرول زنجیره ای

پیمایش زنجیره‌ای در Chrome Android.

پیمایش یکی از اساسی‌ترین راه‌ها برای تعامل با یک صفحه است، اما به دلیل رفتارهای پیش‌فرض عجیب و غریب مرورگر، مقابله با برخی الگوهای UX ممکن است دشوار باشد. به عنوان مثال، یک کشوی برنامه با تعداد زیادی آیتم که کاربر ممکن است مجبور باشد در میان آنها پیمایش کند، بردارید. وقتی به پایین می‌رسند، ظرف سرریز از پیمایش باز می‌ماند زیرا محتوای بیشتری برای مصرف وجود ندارد. به عبارت دیگر، کاربر به یک "مرز اسکرول" می رسد. اما توجه کنید که اگر کاربر به پیمایش ادامه دهد چه اتفاقی می افتد. محتوای پشت کشو شروع به پیمایش می کند ! پیمایش توسط ظرف والد انجام می شود. خود صفحه اصلی در مثال.

معلوم شد که این رفتار زنجیره‌ای اسکرول نامیده می‌شود. رفتار پیش فرض مرورگر هنگام پیمایش محتوا. اغلب اوقات پیش فرض بسیار خوب است، اما گاهی اوقات مطلوب یا حتی غیرمنتظره نیست. برخی از برنامه‌ها ممکن است بخواهند زمانی که کاربر به مرز اسکرول برخورد می‌کند، تجربه کاربری متفاوتی را ارائه دهند.

اثر کشش به تازه کردن

Pull-to-refresh یک حرکت بصری است که توسط برنامه های تلفن همراه مانند فیس بوک و توییتر رایج شده است. پایین کشیدن فید اجتماعی و انتشار فضای جدیدی برای بارگیری پست های اخیر ایجاد می کند. در واقع، این UX خاص به قدری محبوب شده است که مرورگرهای تلفن همراه مانند Chrome در اندروید نیز همین اثر را به کار گرفته اند. کشیدن انگشت به پایین در بالای صفحه کل صفحه را تازه می کند:

کشش برای تازه کردن سفارشی توییتر
هنگام تازه کردن یک خوراک در PWA خود.
عمل کشش برای تازه کردن بومی Chrome Android
کل صفحه را تازه می کند.

برای موقعیت‌هایی مانند توییتر PWA ، ممکن است منطقی باشد که عمل کشش برای تازه کردن بومی را غیرفعال کنید. چرا؟ در این برنامه، احتمالاً نمی خواهید کاربر به طور تصادفی صفحه را رفرش کند. همچنین این پتانسیل وجود دارد که یک انیمیشن به‌روزرسانی دوگانه را ببینید! از طرف دیگر، ممکن است بهتر باشد که عملکرد مرورگر را سفارشی کنید و آن را بیشتر با برند سایت هماهنگ کنید. بخش تاسف بار این است که این نوع سفارشی سازی دشوار است. توسعه دهندگان در نهایت جاوا اسکریپت غیرضروری می نویسند، شنونده های لمسی غیرفعال اضافه می کنند (که پیمایش را مسدود می کند)، یا کل صفحه را در 100vw/vh <div> می چسبانند (برای جلوگیری از سرریز شدن صفحه). این راه‌حل‌ها اثرات منفی کاملاً مستندی بر عملکرد اسکرول دارند.

ما می توانیم بهتر عمل کنیم!

معرفی overscroll-behavior

ویژگی overscroll-behavior یک ویژگی جدید CSS است که رفتار اتفاقاتی که هنگام اسکرول بیش از حد یک ظرف (از جمله خود صفحه) روی می دهد را کنترل می کند. می‌توانید از آن برای لغو زنجیره‌سازی پیمایش، غیرفعال کردن/سفارشی کردن عمل کشش برای تازه‌سازی، غیرفعال کردن جلوه‌های نواربندی لاستیکی در iOS (زمانی که Safari overscroll-behavior اجرا می‌کند) و موارد دیگر استفاده کنید. بهترین بخش این است که استفاده از overscroll-behavior مانند هک های ذکر شده در مقدمه بر عملکرد صفحه تأثیر منفی نمی گذارد !

این ویژگی سه مقدار ممکن را می گیرد:

  1. خودکار - پیش فرض طومارهایی که از عنصر منشا می گیرند ممکن است به عناصر اجدادی انتشار یابند.
  2. حاوی - از زنجیر شدن اسکرول جلوگیری می کند. طومارها به اجداد انتشار نمی یابند اما اثرات محلی درون گره نشان داده می شوند. به عنوان مثال، افکت درخشش overscroll در اندروید یا افکت لاستیک در iOS که کاربر را در صورت برخورد به مرز اسکرول مطلع می کند. توجه : استفاده از overscroll-behavior: contain در عنصر html از اقدامات پیمایش overscroll جلوگیری می کند.
  3. هیچکدام - همان contain ، اما از اثرات overscroll درون خود گره نیز جلوگیری می کند (مثلاً درخشش Overscroll Android یا rubberbanding iOS).

بیایید چند مثال را بررسی کنیم تا نحوه استفاده از overscroll-behavior ببینیم.

از فرار اسکرول ها از عنصر موقعیت ثابت جلوگیری کنید

سناریوی چت باکس

محتوای زیر پنجره چت نیز اسکرول می شود :(

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

برای این برنامه، مناسب تر است که اسکرول هایی که در جعبه گفتگو ایجاد می شوند در چت باقی بمانند. می‌توانیم با اضافه کردن overscroll-behavior: contain به عنصری که پیام‌های چت را نگه می‌دارد، این اتفاق بیفتد:

#chat .msgs {
  overflow: auto;
  overscroll-behavior: contain;
  height: 300px;
}

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

سناریوی همپوشانی صفحه

یکی دیگر از تغییرات سناریوی "Undercroll" زمانی است که می بینید محتوا در پشت یک همپوشانی با موقعیت ثابت اسکرول می شود. یک هدایای مرده overscroll-behavior درست است! مرورگر سعی می کند مفید باشد، اما در نهایت باعث می شود سایت باگ به نظر برسد.

مثال - معین با و بدون overscroll-behavior: contain :

قبل : محتوای صفحه در زیر همپوشانی اسکرول می شود.
بعد از : محتوای صفحه در زیر همپوشانی پیمایش نمی کند.

غیرفعال کردن pull-to-refresh

خاموش کردن عمل کشش برای تازه کردن یک خط از CSS است . فقط از زنجیره اسکرول در کل عنصر تعریف کننده viewport جلوگیری کنید. در بیشتر موارد، این <html> یا <body> است:

body {
  /* Disables pull-to-refresh but allows overscroll glow effects. */
  overscroll-behavior-y: contain;
}

با این افزوده ساده، انیمیشن‌های دوبار کشش برای تازه‌سازی را در نسخه نمایشی چت باکس اصلاح می‌کنیم و در عوض می‌توانیم یک افکت سفارشی را پیاده‌سازی کنیم که از یک انیمیشن بارگیری دقیق‌تر استفاده می‌کند. کل صندوق ورودی نیز با تازه شدن صندوق ورودی محو می شود:

قبل از
بعد از

در اینجا یک قطعه از کد کامل است:

<style>
  body.refreshing #inbox {
    filter: blur(1px);
    touch-action: none; /* prevent scrolling */
  }
  body.refreshing .refresher {
    transform: translate3d(0,150%,0) scale(1);
    z-index: 1;
  }
  .refresher {
    --refresh-width: 55px;
    pointer-events: none;
    width: var(--refresh-width);
    height: var(--refresh-width);
    border-radius: 50%;
    position: absolute;
    transition: all 300ms cubic-bezier(0,0,0.2,1);
    will-change: transform, opacity;
    ...
  }
</style>

<div class="refresher">
  <div class="loading-bar"></div>
  <div class="loading-bar"></div>
  <div class="loading-bar"></div>
  <div class="loading-bar"></div>
</div>

<section id="inbox"><!-- msgs --></section>

<script>
  let _startY;
  const inbox = document.querySelector('#inbox');

  inbox.addEventListener('touchstart', e => {
    _startY = e.touches[0].pageY;
  }, {passive: true});

  inbox.addEventListener('touchmove', e => {
    const y = e.touches[0].pageY;
    // Activate custom pull-to-refresh effects when at the top of the container
    // and user is scrolling up.
    if (document.scrollingElement.scrollTop === 0 && y > _startY &&
        !document.body.classList.contains('refreshing')) {
      // refresh inbox.
    }
  }, {passive: true});
</script>

غیرفعال کردن درخشش overscroll و جلوه های لاستیک

برای غیرفعال کردن افکت پرش هنگام ضربه زدن به مرز اسکرول، از overscroll-behavior-y: none استفاده کنید:

body {
  /* Disables pull-to-refresh and overscroll glow effect.
     Still keeps swipe navigations. */
  overscroll-behavior-y: none;
}
قبل از : ضربه زدن به مرز اسکرول یک درخشش را نشان می دهد.
بعد از : درخشش غیرفعال شد.

نسخه ی نمایشی کامل

با کنار هم گذاشتن همه اینها، نسخه ی نمایشی کامل چت باکس overscroll-behavior برای ایجاد یک انیمیشن سفارشی کشش برای تازه کردن و غیرفعال کردن اسکرول ها برای فرار از ویجت چت باکس استفاده می کند. این یک تجربه کاربری بهینه را فراهم می‌کند که دستیابی به آن بدون استفاده از CSS overscroll-behavior دشوار بود.

نمایش دمو | منبع