Rock 'n' Scroll

Анна Селезнёва, Evil Martians

Rock 'n' Scroll

The Rolling Scopes Conference, 10 – 11 февраля 2018, Минск

Привет!

Меня зовут Аня, и я марсианка

Я разносторонний человек

Ruby
ReactJS
HTML
JS
SVG
CSS

Вы любите скролл?

План

  1. Внешний вид
  2. Перемещение
  3. Обработка
  4. Укрощение

1. Внешний вид

Эволюция скроллбара в Windows

Эволюция скроллбара в macOS

Medium Modal Window

Значение ширины *

15px

* – в последних версиях

Вычисление ширины

			const outer = document.createElement('div');
const inner = document.createElement('div');
outer.style.overflow = 'scroll';
document.body.appendChild(outer);
outer.appendChild(inner);
const scrollbarWidth = outer.offsetWidth - inner.offsetWidth;
document.body.removeChild(outer);
			
		

Резервирование ширины

			html {
	overflow-y: scroll;
}
			
		
RDCM scrollbar

Стилизация

Анатомия скроллбара

scrollbar-button

scrollbar-track

scrollbar-thumb

scrollbar-track-piece

scrollbar-corner + resizer

Псевдоэлементы скроллбара

			::-webkit-scrollbar
::-webkit-scrollbar-track (-piece)
::-webkit-scrollbar-thumb
::-webkit-scrollbar-button
::-webkit-scrollbar-corner
::-webkit-resizer
		
			+ :horizontal :vertical :start :end :increment :decrement
		

Поддержка стилизации

Поддерживается:

Google Chrome Safari Opera UC Browser Samsung Internet

Поддержка стилизации

Запрос в Microsoft Edge был отправлен 2,5 года назад.
Задача добавлена в backlog. Приоритет средний.

Запрос в Mozilla Firefox был отправлен 17 лет назад.

Черновики спецификации: drafts.csswg.org/css-scrollbars-1
(GitHub: github.com/w3c/csswg-drafts/labels/css-scrollbars-1)

2. Перемещение

Переход к элементу

<a href="#element">Перейти</a>

<div id="element">
...
</div>

Скролл к элементу

elem.scrollIntoView(options)

Параметры:

{
	block: 'start' | 'end',
	behavior: 'auto' | 'instant' | 'smooth',
}

Плавный скролл

			html {
	scroll-behavior: smooth;
}
		

Пример: codepen.io/askd/full/WdXOYW

Плавный скролл

Поддерживается:

Google Chrome Opera Mozilla Firefox

Полифил:

github.com/iamdustan/smoothscroll

Умный скролл

Слайдер из коробки

Пример: codepen.io/askd/full/aEVyZy

Умный скролл

			.container {
  scroll-snap-type: mandatory;
  scroll-snap-points-x: repeat(100%);
}
.slide {
  scroll-snap-align: start;
}
			
		

Умный скролл

Поддерживается:

Mozilla Firefox Safari

Поддерживается частично:

Internet Explorer Microsoft Edge

Умный скролл

В процессе:

Google Chrome chromestatus.com/feature/5721832506261504


Полифил:

github.com/ckrack/scrollsnap-polyfill

3. Обработка

Классический обработчик

window.addEventListener('scroll', () => {
	const scrollTop = window.scrollY;
	/* doSomething with scrollTop */
});

Оптимизация обработчика

window.addEventListener('scroll', throttle(() => {
	const scrollTop = window.scrollY;
	/* doSomething with scrollTop */
}));

Примитивная реализация throttle

function throttle(action, wait = 1000) {
	let time = Date.now();
	return function() {
		if ((time + wait - Date.now()) < 0) {
			action();
			time = Date.now();
		}
	}
}

Throttle с requestAnimationFrame

			function throttle(action) {
  let isRunning = false;
  return function() {
    if (isRunning) return;
    isRunning = true;
    window.requestAnimationFrame(() => {
      action();
      isRunning = false;
    });
  }
}
		

Готовая реализация throttle

$ npm i --save lodash.throttle

import throttle from 'lodash/throttle';

Сравнение requestAnimationFrame и lodash.throttle:
codepen.io/askd/full/RxEYOv

Индикатор скролла

			.water {
  width: 100%;
  height: calc(100% - var(--scroll));
  background-color: aqua;
}
		

Пример: codepen.io/askd/full/PEBZJW

CSS-переменная

window.addEventListener('scroll', () => {
	const scroll = window.pageYOffset /
	(document.body.scrollHeight - window.innerHeight) * 100;
	element.style.setProperty('--scroll', `${scroll}%`);
});

Идея: alligator.io/js/progress-bar-javascript-css-variables

Прилипающий элемент

Когда доскроллили до определенного места страницы

Пример: codepen.io/askd/full/ppGQya

Прилипающий элемент

			.element {
	position: sticky;
	top: 50px;
}
		

Место прилипания задаётся с помощью:

			top, right, bottom, left
		

position: sticky

Поддерживается:

Google Chrome Safari Opera Mozilla Firefox Microsoft Edge

Пример от Реми Шарпа: css-smooth-sticky-demo.now.sh

4. Укрощение

Vengo Diagonal Scroll

Диагональный скролл

window.addEventListener('scroll', () => {
	const scrollTop = window.scrollY;
	const offset = Math.round(scrollTop * 0.533);
	wrapper.style.transform = `translateX(${offset}px)`;

	/* 0.533 = tan(28deg) */
});

Возможно, вам это не нужно

Параллакс

Evil Martians Parallax

Параллакс

.parallax {
	background-attachment: fixed;
	background-size: cover;
}
@media (max-device-width: 1024px) {
	.parallax { background-attachment: scroll; }
}

Подробнее на w3schools.com

Инерционный скролл

			.element {
	-webkit-overflow-scrolling: touch;
}
		

Только для мобильных устройств

Black Magic

Отмена цепочки скролла

elem.addEventListener('wheel', onScroll);

Пример: codepen.io/askd/full/BJMLmM

function onScroll(event) {
	const delta = -event.deltaY;
	if (delta < 0 && elemHeight - delta > elem.scrollHeight - elem.scrollTop) {
		elem.scrollTop = elem.scrollHeight;
		return prevent(event);
	}
	if (delta > elem.scrollTop) {
		elem.scrollTop = 0;
		return prevent(event);
	}
	return true;
}

Отмена скролла

const prevent = (event) => {
  event.preventDefault();
  return false;
};

Проблема

Обработчики touch и wheel событий ухудшают производительность скролла:

element.addEventListener('touchstart', e => {
	/* doSomething */
});

Решение

Пассивный обработчик:

element.addEventListener('touchstart', e => {
	/* doSomething */
}, { passive: true });

Подробнее (+полифил): github.com/WICG/EventListenerOptions

Новое свойство

.element {
	overscroll-behavior: contain;
}

Пример: codepen.io/askd/full/NXobXR

pull-to-refresh

Twitter pull-to-refresh

overscroll-behavior

Поддерживается:

Google Chrome

Подробнее: developers.google.com/.../overscroll-behavior

Идеи для скролл-анимаций

			@keyframes progress { to { width: 100%; } }
#progress {
	animation: progress 1s linear;
	animation-timeline: scroll(element(#body));
}
		

Черновик: wicg.github.io/scroll-animations

Итоги

Спасибо!

asktwi

anna.selezniova

askd.rocks


Презентация: askd.rocks/pres/scroll