Существует два основных подхода для стилизации скроллбара средствами HTML/CSS, каждый из которых имеет свои плюсы и минусы:
- Эмуляция скролла средствами JavaScript
- JavaScript обёртка над родным скроллом
Эмуляция скролла средствами JavaScript
Огромным преимуществом данного подхода является то, что это полностью JavaScript решение. Благодаря этому данное решение легче в разработке и является максимально кроссбраузерным (в том плане, что поведение скролла во всех браузерах будет одинаковым, не зависимо от особенностей реализации скролла браузера), оказывая минимальное влияние на HTML структуру и применяемые CSS стили. Подобным подходом пользуются jScrollPane, FleXcroll, Tiny Scrollbar и многие другие.
Однако сильная сторона данного подхода является одновременно и его слабой стороной:
- Сложность или невозможность эмулировать/перехватить все события
- JavaScript эмуляция работает медленнее родного скролла
JavaScript обёртка над родным скроллом
Данный подход заключается в том, что родной скролл скрывается средствами HTML/CSS, продолжая выполнять своё предназначение — прокрутку содержимого. Подобное решение является более предпочтительным по той причине, что родной скролл в любом случае работает лучше эмулированного. Многие пробовали создавать плагины на базе этого подхода, но из-за отсутствия каких-либо стандартов, кроссбраузерная реализация очень сложна, и накладывает определённые ограничения на HTML структуру и используемые стили CSS. По этой причине многие разработчики создают реализацию только вертикального скролла, который ведёт себя во всех браузерах более-менее предсказуемо.
Одна из неплохих реализаций подобного подхода была описана совсем недавно в статье Кроссбраузерная кастомизация системного скроллбара с достаточно подробным объяснением.
Изобретение трёхколёсного велосипеда
Одной из причин создания
Было решено сделать собственную реализацию, отвечающую следующим требованиям:
- Поведение скролла должно быть максимально приближённым к родному
- Вертикальный и горизонтальный скроллбар
- Минимальная нагрузка на процессор
- Полная стилизация внешнего вида средствами HTML/CSS
- Возможность применить свою HTML структуру для скроллбара, либо указать плагину использовать уже существующий элемент в качестве скроллбара
- Автоматическое изменение скролла при изменении содержимого или изменении размеров самого контейнера без необходимости переинициализации скрипта
- Ширина и высота контейнера может быть установлена как в пикселях, так и в процентах, либо ограничена средствами CSS max-height/max-width
- Скролл может находиться как в любом месте внутри контейнера, так и за его пределами
- Автоматическое вычисление размеров скроллбара, либо значение, устанавливаемое через CSS стили
- Поддержка IE7+, Firefox, Chrome, Opera, Safari
- Возможность «из коробки» отключения скролла для мобильных браузеров
В качестве подхода было выбрано решение сделать плагин в виде JavaScript обёртки над родным скроллом — т.е. оставить функциональность родного скролла, скрыть родной скролл средствами CSS и показать стилизованный скролл. Это даёт преимущество в том, что не нужно эмулировать поведение стандартного скролла, а лишь отлавливать изменения в позиционировании с помощью JavaScript.
Избежать полной эмуляции скролла всё же не получилось — необходимо эмулировать поведение скролла, когда мышь находится над стилизуемым скроллом: отлавливать скролл мыши, drag&drop, клики по самому скроллу и стрелочкам. Идеального решения «Подключил и забыл», конечно же, не получилось. Но практически всех поставленных целей удалось добиться в полной мере.
Демонстрация
Исходные файлы
Сравнение функциональности популярных скроллбаров
На заметку
Следует помнить, что для работы стилизованного скроллбара необходима определённая HTML структура, для которой исходный контейнер JavaScript-ом оборачивается в другой контейнер при инициализации. По этой причине сущестуют некоторые особенности использования, стуктуры HTML и стилей CSS:
- Исходный контейнер не должен содержать инлайновые стили
- Следует избегать использования padding/margin для контейнера. Если нужен отступ, лучше добавить внутрь ещё один контейнер с необходимым отступом
- При изменении содержимого контейнера не стоит обращаться к контейнеру по классу, т.к. эти классы будут использоваться и контейнером-обёрткой
Примечания
Из-за разности поведения скролла не только в разных браузерах, но и в разных версиях одного и того же браузера (да-да, того самого браузера), пришлось перепробовать множество комбинаций margin/padding/border/position для вычисления схожего поведения. Во время поиска решения, нашлось несколько интересных особенностей:
- В ИЕ8 — баги с использованием max-height: в некоторых случаях рендерер 8-й версии ИЕ крашится, либо пытается сделать высоту контейнера равной max-height (официальный баг релиз версии)
- WebKit-браузеры (Chrome, Safari) при выделении текста делают прокрутку внутреннего контейнера, «обнажая» скрытый скроллбар
- Если содержимое превышает размеры контейнера, то отображение правого и нижнего паддинга остаётся на усмотрение самого браузера
- При поиске плагинов, чтобы быстро узнать используется ли стандартный механизм скроллинга, достаточно нажать на скролл мыши, находясь над прокручиваемым контентом
Обновление до версии 0.1.3 (20130425):
- улучшена эмуляция скролла: теперь скролл колёсиком мыши над эмулируемым скроллом работает почти идентично натуральному скроллу; также изменено поведение при нажатии и удержании мыши на подложке скроллбара
- исправлено CSS позиционирование, при котором происходил «лишний» сдвиг контейнера при выделении текста в WebKit браузерах Google Chrome / Safari
Обновление до версии 0.1.4 (20130430):
- отслеживание горизонтального скролла мышью над горизонтальным скроллбаром
- добавлена опция disableBodyScroll для отключения скролла страницы, когда прокручивается контейнер. В данной опции пришлось отключить родное поведение браузера и эмулировать скролл через JavaScript
Обновление до версии 0.1.6 (20131018):
- добавлена опция игнорирования инициализации скролла на мобильных устройствах
- добавлена поддержка drag для скролла на тач-устройствах
Обновление до версии 0.1.7 (20140307):
- добавлен хак для исправления появления скроллбара при 1-пиксельном зазоре в ИЕ
Обновление до версии 0.1.8 (20140308):
- исправлен баг с отображением горизонтального скроллбара если высота содержимого меньше высоты контейнера (случаи с height:100%)
Обновление до версии 0.1.9 (20140310):
- исправлен баг с отображением вертикального скроллбара если контент содержит div с height:100%; overflow: hidden;, внутри которого div с высотой, превышающей высоту внешнего контейнера (спасибо за отзывы и замечания Evangeline Rei)
- добавлена опция autoUpdate отвечающая за автоматическую реинициализацию скроллбара при изменении размеров контента/контейнера
Обновление до версии 0.2.0 (20140312):
- добавлена опция onUpdate для возможности пересчёта размеров скроллбара вручную. благодаря данной опции был добавлен скроллбар в виде карты страницы
- добавлена опция stepScrolling отвечающая за пошаговую прокрутку к месту, где удерживается нажатой кнопка мыши на скроллбаре. если опция отключена, то содержимое будет прокручено сразу до местоположения мыши, в противном случае будет происходить пошаговая прокрутка с ускорением до места удерживания мыши (эмуляция поведения скролла)
- скрытие/отображение скроллбаров полностью перенесено в CSS
- изменено поведение onInit — теперь запуск функции происходит только один раз при инициализации
Обновление до версии 0.2.1 (20140323):
- исправлена ошибка с прокруткой к #anchor-элементу, когда становится видимым горизонтальный скролл
Обновление до версии 0.2.2 (20140411):
- исправлена ошибка с инициализацией нескольких скроллбаров с настройками по умолчанию
- добавлен элемент scroll-element_corner для удобной CSS настройки уголка если видны оба скроллбара
Обновление до версии 0.2.3 (20140703):
- исправлена ошибка с видимым скроллбаром при изменении zoom-а в браузере
- исправлена ошибка с неверной инициализацией размеров скроллбара для ИЕ при использовании CSS * { box-sizing: border-box; }
- добавлена callback функция onScroll, которая позволяет легче определять степень прокручивания контейнера
- скроллбар может быть использован как директива для отличного фреймворка Angular.JS
- добавлена возможность переопределять значения по-умолчанию через глобальную переменную jQueryScrollbarOptions до загрузки плагина
- оптимизирована проверка изменения размеров контейнера
Обновление до версии 0.2.4 (20140715):
- добавлена возможность стилизации скроллбара для TEXTAREA
наконец-то

