Нестандартная полоса прокрутки с помощью JavaScript

There is an English version of this article available.

О чём эта статья?

В этой статье я расскажу о том, как буквально за 10 минут с помощью jScrollPane - библиотеки для jQuery - вы сможете сделать нестандартную полосу прокрутки для своего сайта, а также как её стилизовать и настроить.

Базовые сведения

Рано или поздно веб-дизайнер сталкивается с тем, что полосы прокрутки на сайте, который он создаёт, смотрятся неорганично (и каждый браузер отображает их по-своему). Во многих случаях это не является проблемой, однако попадаются заказчики, которые обращают на этот момент пристальное внимание и требуют, чтобы полосы прокрутки были покрашены в определённый цвет, имели, скажем, скруглённые края и чтобы стрелки (вверх-вниз, влево-вправо) не отображались. Возникает простой вопрос: как это сделать? Сможет ли нам помочь в этом случае CSS? В принципе, много лет назад на некоторых сайтах я встречал инструкции CSS, которые действительно перекрашивали полосы прокрутки, но работало это только во всеми любимом браузере IE начиная с версии 6, и в нашем случае такой вариант не подходит. Всё же, если кому-то интересно, то реализовывалось это примерно так:

body {
   scrollbar-face-color: green;
   scrollbar-highlight-color: blue;
   scrollbar-3dlight-color: red; 
   scrollbar-darkshadow-color: yellow; 
   scrollbar-shadow-color: grey; 
   scrollbar-arrow-color: purple; 
   scrollbar-track-color: pink;
}

Итак, предположим, что на нашем сайте имеется некий блок, который должен иметь нестандартную полосу прокрутки, например блок с комментариями. Разметка будет крайне проста:

<div id="comments_block">Здесь будет наш текст</div>

Стили CSS:

#comments_block {
   overflow: auto;
   width: 700px;
   height: 200px;
}

Достаточно задать ширину и высоту, которая подходит под ваш случай. Получится что-то в этом роде:

Теперь осталось добавить немного магии и превратить обычную полосу прокрутки в необычную. Для этого нам потребуется плагин для jQuery, который называется jScrollPane, его автор - Келвин Люк; официальный сайт - http://jscrollpane.kelvinluck.com. Взять последнюю версию данного плагина можно с этой страницы; код уже был минифицирован заботливым автором. Предварительно не забудьте подключить на своём сайте саму библиотеку jQuery (плагин корректно работает со всеми новыми версиями jQuery). Помимо кода JavaScript, нам потребуются базовые стили, которые мы берём здесь; в дальнейшем вы сможете модифицировать их, чтобы стилизовать полосу прокрутки для своего сайта. Помимо этих файлов, рекомендуется также подключить плагин для корректной работы с колёсиком мыши - он называется MouseWheel и его автор Брэндон Аарон. Последнюю версию данной библиотеки можно найти на GitHub (этот скрипт также лежит на сайте jScrollPane). Последний файл, который мы можем подключить - это библиотека MouseWheelIntent, которая позволяет использовать колёсико мышки даже в случае, если наши контейнеры с полосами прокрутки вложены один в другой. Использование этой библиотеки необязательно, но может повысить удобство использования вашего сайта.

Внимание! На сайте jScrollPane есть ссылка на эту библиотеку, но данная версия не будет работать с новыми версиями jQuery, так как в коде используются недокументированные функции, которые jQuery 1.9+ не поддерживает. Я модифицировал данную библиотеку, обновлённую версию можно найти здесь (я хотел связаться с автором и сообщить об этом обновлении, но его сайт недоступен и найти его в Интернете по нику я тоже не смог; того, кто сможет предоставить информацию о местонахождении этого человека, ждёт вознаграждение :)).

На официальном сайте jScrollPane представлено достаточно много разнообразных примеров использования данной библиотеки, поэтому я рассмотрю только некоторые из них. Сначала попробуем просто превратить полосу прокрутки нашего контейнера (разметку и стили для которого я привёл выше) в нестандартную. Для этого напишем очень простой код JavaScript:

$(document).ready(function() {
   $('#comments_block').jScrollPane();
});

Всё, что мы здесь делаем - ожидаем, пока страница будет полностью загружена, а затем применяем метод jScrollPane() к нашему контейнеру с идентификатором #comments_block.

Хочу обратить внимание на одну очень важную вещь: предварительно нам необходимо немного модифицировать разметку. Дело в том, что если контейнер #comments_block оставить в том же виде, то jScrollPane будет применена некорректно - обычные полосы прокрутки исчезнут, но нестандартные не появятся. Это баг данной библиотеки, который, увы, пока не исправлен. Для разрешения этой проблемы нам необходимо заключить весь текст внутри блока #comments_block в любой блочный тэг, например в p, div или ul (если вы планируете выводить контент в виде маркированного списка) вот таким образом:

<div id="comments_block"><p>Здесь будет наш текст</p></div>

Вот что получилось в результате:

Ура, сработало. Теперь осталось лишь применить необходимые стили к нашей полосе прокрутки. Сделаем её в серых тонах и более узкой (кстати, для jScrollPane существует преопределённая тема оформления):

.jspVerticalBar {
   width: 8px;
}
.jspTrack {
   width: 8px;
   background-color: #ededed;
}
.jspDrag {
   width: 8px;
   background-color: #ccc;
}

Настройка jScrollPane

Вы можете заметить, что прокрутка с помощью колёсика мышки слишком медленная. Что ж, исправить это несложно - jScrollPane позволяет передавать множество параметров для настройки (их полный перечень можно найти здесь):

$('#comments_block').jScrollPane({mouseWheelSpeed: 70});

Скорость прокрутки 70, на мой взгляд, является оптимальной, но вы можете поэкспериментировать самостоятельно (значение по умолчанию - 10).

Ещё один важный параметр отвечает за то, будет ли наш блок с полосой прокрутки обновляться автоматически. В каком случае это полезно? Например, тогда, когда блок с прокруткой имеет не фиксированную ширину, а относительную (заданную в процентах, em или rem). В этом случае если пользователь будет изменять размер окна, то наш блок будет изменять ширину и потребуется правильно изменить полосу прокрутки. Это можно делать и с помощью API, который доступен в jScrollPane (об этом чуть позже), но проще будет написать так:

$('#comments_block').jScrollPane({autoReinitialise: true});

В этом случае полоса прокрутки будет переопределяться автоматически. Другой сценарий использования этого параметра - динамическое добавление содержимого в блок с прокруткой. Если автоматического переопределения нет, то при добавлении контента полоса прокрутки не будет обновлена и к новому содержимому нельзя будет перейти (он останется за пределами блока и будет невидим) - свойство autoReinitialise позволит избежать этой проблемы. Обратите внимание, что по умолчанию автоматическое переопределение выполняется очень часто - каждые полсекунды. Если в вашем случае достаточно будет обновлять полосу прокрутки каждые, скажем, 5 секунд, то необходимо передать ещё один параметр autoReinitialiseDelay:

$('#comments_block').jScrollPane({autoReinitialise: true, autoReinitialiseDelay: 5000});

Значение задаётся в милисекундах.

Также обратите внимание, что если фокус установлен на блоке с полосой прокрутки, пользователь может осуществлять прокрутку с помощью стрелок "вверх" и "вниз" на клавиатуре. Если вы хотите отключить такую возможность, установите параметр enableKeyboardNavigation в значение false.

API для работы с jScrollPane

Последнее о чём я немного расскажу - это API для управления jScrollPane. Доступ к API осуществляется очень просто:

var my_comments_block = $('#comments_block').jScrollPane();
var api = my_comments_block.data('jsp');

Теперь переменную api можно использовать для доступа к функциям jScrollPane. Например, этот код

api.reinitialise();

запустит принудитильное обновление полосы прокрутки (не забывайте, что можно использовать параметр autoReinitialise для автоматического обновления). Другим интересным методом API является scrollToElement, который позволяет осуществить принудительную прокрутку к определённому элементу в контейнере; этот элемент передаётся в качестве первого аргумента и может быть определён либо как объект jQuery, либо как узел DOM, либо как селектор jQuery. Вторым аргументом передаётся логическое значение true или false, которое определяет, должен ли элемент, к которому мы осуществляем прокрутку, оказаться на самом верху контейнера; если установлено значение false, то jScrollPane попытается осуществить минимальную прокрутку для того, чтобы элемент просто появился в видимой области. Третьим параметром также передаётся логическое значение, которое указывает, следует ли анимировать прокрутку. Продемонстрируем этот метод на примере. Для этого внесём небольшие изменения в нашу разметку, которая использовалась ранее:

<a href="#" class="scroll_to_element">Scroll to element!</a>

<div id="comments_block">
   <div>
      <p>Text</p>
      <p class="scroll_to_me">Scroll to me!</p>
      <p>More text</p>
   </div>
</div>

В наш блок поместим несколько строк текста, а между ними добавим параграф с классом .scroll_to_me, к которому и будем осуществлять принудительную прокрутку. В начале страницы будет располагаться ссылка с классом .scroll_to_element, при клике по которой и будет запускаться метод scrollToElement, который осуществит прокрутку до выбранного параграфа. Модифицируем код JavaScript:

$(document).ready(function() {
   var my_jsp = $('#comments_block').jScrollPane({});
   var api = my_jsp.data('jsp');

   $('.scroll_to_element').click(function(e) {
      e.preventDefault();
      api.scrollToElement('.scroll_to_me', true, true);
   })
});

Здесь мы сначала объявляем переменную api, с помощью которой и будем выполнять методы jScrollPane, а затем привязываем обработчик события click к ссылке с классом .scroll_to_element. При клике по ссылке сначала будет запрещена обработка стандартного поведения с помощью метода preventDefault(), чтобы браузер не пытался выполнять переход по ссылке. Затем производится принудительная прокрутка, причём мы устанавливаем оба логических параметра в значение true, чтобы элемент оказался наверху видимой области и чтобы прокрутка анимировалась.

Существует ряд методов, которые выполняют сходные задачи: scrollTo (прокрутить до определённой точки, которая задаётся как координаты x и y относительно левого верхнего угла контейнера); scrollToX и scrollToY (прокрутить до определённой точки по оси x или y); scrollToPercentX и scrollToPercentY (прокрутить по соответствующей оси на определённый процент) и прочие. Помимо этого, API позволяет опрашивать jScrollPane: getIsScrollableH и getIsScrollableV (можно ли прокручивать по горизонтали и вертикали); getContentPositionX и getContentPositionY (получить положение по оси x и y соответственно); getPercentScrolledX и getPercentScrolledY (сколько процентов прокручено по оси x и y соответственно) и ряд других. И, наконец, для того, чтобы вернуть контейнеру обычную полосу прокрутки, удалив функционал jScrollPane, можно использовать метод API destroy.

На этом, пожалуй, я закончу обзор данной библиотеки, которая может оказаться действительно полезной многим разработчикам. Как мы увидели, она предоставляет не только интерфейс для достаточно гибкой настройки, но и методы API для последующего управления. Библиотека находится в состоянии постоянного развития; если вы обнаруживаете баг или хотите предложить внедрить дополнительный функционал, откройте новую заявку в репозитарии на GitHub. Если сообщаете об обнаруженной ошибке, не забудьте подробно её описать (используемая версия библиотеки, версия jQuery на вашем сайте, сценарий использования jScrollPane).

Для разработчиков Ruby on Rails

Разработчикам Ruby on Rails предоставляется небольшой бонус, который позволяет удобнее подключать jScrollPane и сопутствующие библиотеки к своему проекту. Для подключения jScrollPane вы можете добавить в свой Gemfile строку gem 'jscrollpane-rails'. Библиотеку jscrollpane-rails создал автор данной статьи; я постоянно обновляю её и вы можете быть уверены, что используете последнюю версию jScrollPane. После установки данной библиотеки с помощью команды bundle install, добавьте в файл application.js строку //= require jquery.jscrollpane и в файл application.css строку *= require jscrollpane. Не забудьте, что в проекте также должна использоваться jQuery.

Если вместе с jScrollPane вы хотите использовать плагин MouseWheel для поддержки колёсика мышки, добавьте в ваш Gemfile строку gem "jquery-mousewheel-rails", установите библиотеку, а затем в application.js поместите строку //= require jquery.mousewheel. Автором библиотеки jquery-mousewheel-rails является Майк МакДональд.

И, наконец, если вы решили использовать MouseWheelIntent для улучшенной поддержки колёсика мышки, добавьте в Gemfile строку gem "mwheelintent-rails", выполните bundle install, а затем в application.js поместите строку //= require jquery.mwheelintent. Библиотеку mwheelintent-rails также создал автор данной статьи.

Надеюсь, что данные библиотеки будут полезны разработчикам Ruby on Rails. Свои вопросы задавайте в комментариях. Успешной работы и до новых встреч!

Что-то не работает? Нужна помощь? Объясни, что именно не работает! Это ведь так просто. Я не смогу помочь, если не буду знать, что не работает, каковы симптомы проблемы и какие шаги предпринимались для её решения. Давайте уважать друг друга, ведь я трачу собственное время на ведение этого блога, не получая за это ни копейки (рекламы здесь нет и не будет). Наиболее удобный вариант - разместить свой код на сайте jsfiddle.net, чтобы продемонстрировать проблему вживую.

Обратите внимание также, что я не автор этой библиотеки и на данный момент она не развивается активно, хотя всё ещё является лучшим подобным решением. Если возникает какая-то ошибка, в первую очередь имеет смысл почитать список открытых запросов на GitHub (который на данный момент уже включает в себя более сотни позиций) - вполне вероятно, что вы найдёте свой случай там. Если кто-то уже сталкивался с такой проблемой, вполне возможно было найдено временное решение.

Спасибо за понимание и удачной работы.

Follow me on Twitter to get updates about new articles >>