Меняем скроллбар на сайте. CSS. JavaScript

Меняем скроллбар на сайте. CSS. JavaScript

Механизм системного скролла реализуется на уровне базовых возможностей операционной системы, поэтому с уверенностью можно сказать, что он всегда лучше js-эмуляции: он производительнее, работает независимо от JavaScript и реализует все необходимые «фичи» системы для разного типа устройств.

Дизайн системного скроллбара способен изуродовать значительную часть сайтов интернета.

Доброго времени суток!

Хочу немножко покопаться в окрестностях данной темы.

На момент написания статьи, более или менее гибко кастомизировать скроллбар средствами CSS можно только в браузерах на движке webkit.

Сразу пример:
Пропишем несколько строк и откроем страницу в том же chrome:

        
// SCROLL
    ::-webkit-scrollbar {
        width: 10px;
        height: 10px;
    }

    ::-webkit-scrollbar-track {
        -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); 
        /*border-radius: 3px;*/
    }

    ::-webkit-scrollbar-thumb {
        // border-radius: 10px;
        -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.5); 
    }
        

В остальном это попытки большого числа js-библиотек, более половины которых подменяют нативный механизм скролла. При таком подходе возникает сразу два фундаментальных недостатка: отсутствие кроссбраузерности и отсутствие же кроссплатформенности.

Когда-то я использовал jScrollPane. На тот момент плагин вполне справлялся со своей задачей, но сейчас понимаю, что на странице генерируется куча мусора, которую сложно контролировать.

Вообще, все подобные решения - УЖаС, по этому лучше закройте эту статью и призывайте всех перейти на лучший браузер в мире.

Но все таки давайте поразмышляем немножко на эту тему..

Поставим задачу (а это пол дела!):

Скрыть системный скроллбар

Отобразить кастомный скроллбар.

Все должно быть максимально просто и понятно, а подключение не требует дополнительных махинаций

В особенности хочу обратить внимание на третий пункт. Решения, что требуют для себя слишком многое - в пекло. Есть архитектура приложения, и ничто не должно на нее сильно влиять. Иначе - будем грести проблемы с поддержкой в будущем.

Например, раньше, чтобы поставить Яндекс карты, нужно было написать целое сочинение. Сейчас они все упаковали в одну строчку.

Я опишу идею, которая может быть будет кому-то полезна в велосипедостроении :)

HTML

        
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit Lorem ipsum dolor sit amet, consectetur adipisicing elit Lorem ipsum dolor sit amet, consectetur adipisicing elit
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit Lorem ipsum dolor sit amet, consectetur adipisicing elit Lorem ipsum dolor sit amet, consectetur adipisicing elit

LESS

        
.t-scroll-container { 
    overflow: hidden !important; /* Прячем прокрутку */
    position: relative;
    & > .t-scroll { /* Полоса, по которой будет бегать наш ползунок */
        position: absolute;
        right: 0px;
        top: 0;
        width: 12px;
        background: rgb(243, 247, 254);
        z-index: 2;
        button { /* Ползунок, собственно :) */
            position: absolute;
            right: 0;
            top: 0;
            width: 10px;
            height: 50px;
            background: #b6b6b6;
            border-radius: 4px;
        }
    }
}
        

JS

        
var makeThis = function(el) {
    if (!el.length)
        return false;

    var el = $(el[0]);

    if (el.hasClass('t-scroll-container')) // Если мы уже тут были, уходим
        return false;

    // Формируем наш ползунок. Все просто: div, внутри button
        var scroll = $('<div class="t-scroll"/>').append('<button type="button"/>');
        el.append(scroll);
        el.addClass('t-scroll-container');

    // Update
        var change = function() {
            // Если скролл не нужен - прячем
                if (!(el[0].scrollHeight - el.outerHeight()))
                    el.find(' > .t-scroll').hide();

            // Задаем высоту полоски под ползунком
                el.find(' > .t-scroll').css('height', el[0].scrollHeight);

            // Высчитываем высоту ползунка. 
            // Как вариант - можно задать фиксированное значение или переписать
                var butH = el.outerHeight() / 6;
                var scrollDelta = (el[0].scrollHeight - el.outerHeight());
                if (el.outerHeight()    < scrollDelta)
                    butH = butH / (scrollDelta / el.outerHeight());
                butH = Math.max(butH, 30);
                el.find(' > .t-scroll button').css('height', butH);
        }
        change();

    // Запоминаем смещение скролла и 
    // расстояние между точкой клика на кнопку и верзней грани ползунка
        el[0].bScroll = {
            delta: Math.min(el.outerHeight() / 3, 
                (el[0].scrollHeight - el.outerHeight()) / 4),
            offsetY: 0
        }

    // 
        var mouseUp = function(e) {
            window.removeEventListener('mousemove', mouseMove);
        }

    // 
        var mouseMove = function(e) {
            if (!el[0].bScroll)
                return false;

            // Получили высоту кнопки
                var butH = el.find(' > .t-scroll button').outerHeight();

            // Считаем разницу
                var diff = -(el.offset().top - $(window).scrollTop() - e.clientY) - 
                    el[0].bScroll.offsetY;

            // Находим процент прокрутки / 100
                h = diff / (el.outerHeight() - butH);
                h = Math.max(h, 0);
                h = Math.min(h, 1);

            // Новую позицию    
                var fScrollTop = h * (el[0].scrollHeight - el.outerHeight());
            
            // Двигаем документ
                el.scrollTop(fScrollTop);

            // Находим позицию ползунка
                var scrollPos = fScrollTop + h * (el.outerHeight() - butH);

            // Двигаем
                el.find('.t-scroll button').css('top', scrollPos);

            return false;
        }

    //
        var scrollTo = function(fScrollTop) {
            // Ограничения
                fScrollTop = Math.max(fScrollTop, 0);
                fScrollTop = Math.min(fScrollTop, el[0].scrollHeight - el.outerHeight());

            // Защита от деления на 0
                if (!(el[0].scrollHeight - el.outerHeight()))
                    return false;

            // Ищем позицию ползунка
                var h = fScrollTop / (el[0].scrollHeight - el.outerHeight());
                var pos = fScrollTop + el.outerHeight() * h;
                pos -= el.find('.t-scroll button').outerHeight() * h;

            // Двигаем
                el.find('.t-scroll button').stop().animate({
                    top: pos,
                }, 'fast');

                el.stop().animate({
                    scrollTop: fScrollTop,
                }, 'fast');
        }
    
    // EVENTS
            el.on('DOMNodeInserted resize', function(e) {
                change();
                scrollTo(el.scrollTop());
            });
            
        // MOUSE WHEEL
            el.on('DOMMouseScroll mousewheel', function(e) {
                if (!el[0].bScroll)
                    return false;

                var fScrollTop = el.scrollTop() - 
                    Math.sign(e.originalEvent.wheelDelta || -e.originalEvent.detail) * 
                        el[0].bScroll.delta

                scrollTo(fScrollTop);

                return false;
            });

        // MOUSEDOWN
            el.find(' > .t-scroll button').off('mousedown');
            el.find(' > .t-scroll button').on('mousedown', function(e) {
                if (!el[0].bScroll)
                    return false;

                el[0].bScroll.offsetY = e.offsetY;

                window.addEventListener('mouseup', mouseUp);
                window.addEventListener('mousemove', mouseMove);
            });
}
        

Все, что нам осталось, это вызвать makeThis для нашего ul

        
$(document).ready(function() {
    makeThis($('.it-is-me'));
});
        

Обработку touchstart, touchmove, touchup можно посмотреть в коде примера ниже или написать самостоятельно по аналогии :)

  • Lorem ipsum dolor sit amet, consectetur adipisicing elit Lorem ipsum dolor sit amet, consectetur adipisicing elit Lorem ipsum dolor sit amet, consectetur adipisicing elit
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit Lorem ipsum dolor sit amet, consectetur adipisicing elit Lorem ipsum dolor sit amet, consectetur adipisicing elit
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit Lorem ipsum dolor sit amet, consectetur adipisicing elit Lorem ipsum dolor sit amet, consectetur adipisicing elit
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit Lorem ipsum dolor sit amet, consectetur adipisicing elit Lorem ipsum dolor sit amet, consectetur adipisicing elit
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit Lorem ipsum dolor sit amet, consectetur adipisicing elit Lorem ipsum dolor sit amet, consectetur adipisicing elit
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit Lorem ipsum dolor sit amet, consectetur adipisicing elit Lorem ipsum dolor sit amet, consectetur adipisicing elit
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit Lorem ipsum dolor sit amet, consectetur adipisicing elit Lorem ipsum dolor sit amet, consectetur adipisicing elit
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit Lorem ipsum dolor sit amet, consectetur adipisicing elit Lorem ipsum dolor sit amet, consectetur adipisicing elit
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit Lorem ipsum dolor sit amet, consectetur adipisicing elit Lorem ipsum dolor sit amet, consectetur adipisicing elit
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit Lorem ipsum dolor sit amet, consectetur adipisicing elit Lorem ipsum dolor sit amet, consectetur adipisicing elit
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit Lorem ipsum dolor sit amet, consectetur adipisicing elit Lorem ipsum dolor sit amet, consectetur adipisicing elit
  • Lorem ipsum dolor sit amet, consectetur adipisicing elit Lorem ipsum dolor sit amet, consectetur adipisicing elit Lorem ipsum dolor sit amet, consectetur adipisicing elit
Коротко о себе

Доброго времени суток!
Меня зовут Константин. Здесь я пишу об интересующих меня вещах и временами - просто о жизни.

Мой выбор
Коллегам
Наверх