Карта города и справочник предприятий
87,02
рейтинг
19 февраля 2013 в 09:57

Разработка → Кроссбраузерная кастомизация системного скроллбара



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

Под катом можно узнать, как в ближайшее время будет работать скролл в 2ГИС Онлайн.

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

Дизайн же системного скроллбара, особенно Windows младше 8 версии, способен изуродовать значительную часть сайтов интернета. То, что не все согласны с этим мириться, подтверждается фактом наличия большого числа решений, программно меняющих системный скроллбар на кастомный.

Сейчас в 2ГИС Онлайн (и, соответственно, в API 2ГИС) мы используем FleXcroll: он эмулирует механизм скролла и не подходит нам по ряду причин:

  • Не является кроссплатформенным решением (в частности, плохо работает на Mac)
  • Как и любой эмулятор в принципе, имеет проблемы с производительностью
  • Не имеет встроенного механизма фиксации заголовков.

Все эти факторы заставили нас задуматься над двумя вопросами:

  • существует ли нужное нам готовое решение, или необходимо создавать собственное?
  • возможно ли в принципе сохранить системный механизм скролла, но полностью заменить его дизайн?

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

  1. Системный механизм скролла должен быть сохранён: коррекции подвергается только его дизайн.
  2. Общий размер всех зависимостей должен быть минимизирован. В идеальном случае их не должно быть вообще. Должен быть минимизирован размер и самого решения.
  3. Должен присутствовать механизм фиксации заголовков контента при выходе их за поле зрения, либо простой интерфейс для добавления такого механизма (подробнее об этом пункте см. ниже).

Ограничения


На момент написания статьи, более или менее гибко кастомизировать скроллбар средствами CSS можно только в браузерах на движке webkit. Цвета скроллбара можно поменять в браузере Internet Explorer. В остальных браузерах поддержка кастомизации скроллбара через CSS полностью отсутствует. Отчасти это связано с жёсткой позицией w3c:
There are just some things that CSS should not do, full stop.

Существующие решения




Из того большого числа js-библиотек более половины подменяют нативный механизм скролла. Это значит, что для враппера свойство overflow выставляется в значение hidden, а вложенный контейнер с нужным нам контентом меняет свою абсолютную позицию при генерации событий, связанных со скроллом (например, mousewheel). К таким решениям можно отнести: jScrollPane, Scrollbar Paper, jQuery Custom Scrollbar plugin, FleXcroll, Tiny Scrollbar и многие другие.

При таком подходе возникает сразу два фундаментальных недостатка: отсутствие кроссбраузерности и отсутствие же кроссплатформенности. Дело в том, что интерфейс событий, генерируемых действиями пользователя, при помощи которых пользователь что-то скроллит, существенно отличается от браузера к браузеру: с точки зрения стандартов тут творится настоящий бардак. Более того, последовательность и логика «бросания» событий серьёзно отличается и между платформами. Например, трекпады на платформе Mac при скролле генерируют события типа Wheel с большей частотой, чем колесо обычной мыши, что приводит к чересчур быстрому скроллу в ряде подобных решений.

Именно эти недостатки эмуляции скролла привели нас к формулированию первого пункта требований.

Многие решения изначально позиционируются как плагины к jQuery. В ситуации, когда мы используем jQuery по частям, возникает проблема экономии трафика. Проблема существенно растёт при наличии у плагина зависимости от куда более тяжеловесного jQuery UI. Это касается, например, ShortScroll и Vertical Scroll. А также от ряда других библиотек: например, один из немногих jQuery плагинов, сохраняющих нативный механизм скролла, Scrollbars, зависит от 4 плагинов: event.drag, resize, mousehold и mousewheel общим весом более 10 кб.

Третьему пункту требований не удовлетворяет ни одно из найденных нами решений.

Собственное решение


У решения есть две основных задачи: 1) скрыть системный скроллбар и 2) отобразить кастомный скроллбар.

Для простоты будем рассматривать только вертикальный скроллбар — в нашем случае, как и в большинстве других, нужен только он. Кроме того, это экономит объём выходного кода. Для случая с горизонтальным скроллбаром рассуждения расширяются по аналогии.

Для начала, построим html структуру:

<div class='wrapper' id='wrapper'>
	<div class='scroller' id='scroller'>
		<article class='container' id='container'>
		</article>
	</div>
</div>

где container — собственно, то, что мы хотим скроллировать; scroller — блок, в который по высоте не помещается container, но у него выставлено свойство overflow-y: scroll, что приводит к появлению системного скроллбара у его правой границы; wrapper — окно с шириной чуть меньшей, чем у scroller и свойством overflow: hidden. Ширина меньше ровно на ширину скроллбара scroller.

К сожалению, средствами CSS невозможно точно узнать ширину системного скроллбара. Например, не работает вариант с выставлением ширины 125% для scroller и 80% для container, при котором, казалось бы, ширины container и wrapper должны точно совпасть. Можно сделать scroller заведомо шире, а wrapper и container выставить одинаковую ширину, но такой способ не подходит для резиновой вёрстки и порождает баг в webkit браузерах (см. ниже).

Введём js-переменные:

var wrapper = document.getElementById('wrapper'),
scroller = document.getElementById('scroller'),
container = document.getElementById('container');

Теперь мы можем вычислить ширину системного скроллбара: scroller.offsetWidth — это ширина scroller, включающая в себя border, padding, а также системный скроллбар. Если мы обнулим border и padding при помощи CSS, и вычтем scroller.clientWidth, мы получим искомую ширину скроллбара в пикселях.

В webkit-браузерах существует особенность, заставляющая скроллиться элементы при выделении в них текста в горизонтальном направлении, даже при overflow-x: hidden. То есть scroller начинает двигаться по горизонтали внутри меньшего по ширине wrapper, в результате чего обнажается скрытый нами системный скроллбар. К счастью, в webkit-браузерах, и только в них, мы можем обнулить ширину скроллбара средствами CSS, после чего ширины всех трёх блоков в точности совпадут и места для горизонтального скролла просто не будет:

.scroller::-webkit-scrollbar {
    width: 0;
}

Теперь нарисуем и спозиционируем кастомный скроллбар. Для этого минимально усложним html структуру на 1 элемент, который и будет полностью отвечать за визуальное представление скроллбара:

<div class='wrapper' id='wrapper'>
	<div class='scroller' id='scroller'>
		<article class='container' id='container'>
		</article>
		<div class='scroller__bar'></div>
	</div>
</div>

Здесь важно отметить, что для нашей задачи не требовалась прорисовка кнопок «вверх» и «вниз», а также подстилающего «трека». Впрочем, никаких ограничений для их реализации нет.

При реализации драга нарисованного кастомного скроллбара, главное — запретить выделение текста внутри скроллируемого контента. Для этого достаточно сделать вот такой бинд:

function dontStartSelect() {
	return false;
}

function selection(on) {
	if (on) {
		$(document).on('selectstart', dontStartSelect);
	} else {
		$(document).off('selectstart', dontStartSelect);
	}
}

event(bar, 'mousedown', function(e) {
	e.preventDefault();
	selection(false); // Disable text selection in IE8
});

event(document, 'mouseup blur', function() {
	selection(true); // Enable text selection in IE8
});

Как видите, большая часть кода нужна для браузера IE8, который пока, к сожалению, нельзя сбрасывать со счетов. Обратите внимание, что сброс «нажатого» состояния мыши должен происходить не только при отпускании кнопки мыши, но и при потере страницей фокуса (blur).

Прилипающие заголовки


Некоторые элементы внутри container всегда должны быть видны пользователю. Например, это могут быть заголовки разделов какой-то статьи, при клике на которые (это дополнительный функционал, который выходит за рамки решения) контент «перематывался» бы к кликнутому заголовку.

Ни абсолютное (относительно scroller), ни относительное (относительно своих начальных позиций) позиционирование заголовков в чистом виде, в данном случае не подходит. Первое — по причине схлапывания контента, окружающего заголовок и соответствующих им рывков при скролле; второе — по причине нативных неустранимых transition'ов у браузера Internet Explorer для скролла, которые приводят к дрожанию всех зафиксированных заголовков.

В связи с этим, html структуру пришлось ещё немного усложнить, обернув все заголовки в врапперы, задача которых — сохранять место под заголовками при их вырывании из потока во время фиксации абсолютным позиционированием. В принципе, аналогичного результата можно добиться подбором отрицательных margin'ов для заголовков и секций, к которым они относятся — тогда можно обойтись и без врапперов заголовков.

При каждом скролле для каждого заголовка необходимо проверять условие:

scroller.scrollTop - H[i].offsetTop > Sum(H[j].offsetHeight, j=0..i-1)
scroller.scrollTop - H[i].offsetTop < scroller.clientHeight - Sum(H[j].offsetHeight, j=i..n-1)

где H — массив элементов заголовков; i — номер заголовка, меняется в диапазоне от 0 до n-1; scroller.scrollTop — виртуальное расстояние от верхней границы container до верхней границы видимой части container; H[i].offsetTop — расстояние от верхней границы container до верхней границы заголовка H[i].

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

Пробрасывание события mousewheel


В webkit браузерах мы столкнулись с неприятным багом: событие mousewheel не пробрасывалось с фиксированных заголовков вверх к scroller. Это создавало эффект поломки (внезапного прекращения) скролла при попадании под курсор фиксированного заголовка (например, в результате всё того же скролла). То есть, пользователь крутит колесо мыши, под курсор попадает заголовок, фиксируется, и, внезапно, скролл перестаёт работать (точнее, скроллиться начинает вся страница).

К счастью, в webkit браузерах (а нам требовалось обратиться только к ним) есть такая возможность:

$(headers).on('mousewheel', function(e) {
	var evt = document.createEvent('WheelEvent');
	evt.initWebKitWheelEvent(e.originalEvent.wheelDeltaX, e.originalEvent.wheelDeltaY);
	scroller.dispatchEvent(evt); // Пробрасываем событие на scroller
	e.preventDefault(); // Останавливаем скролл страницы
});

Конечно, это сокращённая версия кода: необходимо проверять наличие соответствующих функций и типа события, чтоб не генерировать ошибки в других браузерах.

Пример


Для минимизации объёма js-кода и зависимостей был использован подход, при котором библиотека не является плагином jQuery, хотя по-умолчанию использует его.

Например, в самом простом случае (без фиксации заголовков), инициализация выглядит так:

baron($('.wrapper'), {
	scroller: '.scroller',
	container: '.container',
	bar: '.scroller__bar'
});

Причём $('.wrapper') может быть массивом html объектов — проинициализируется каждый из них.

Если вы хотите фиксации заголовков, ограничения верхнего положения скроллбара, и использования альтернатив jQuery, инициализация немного усложняется:

baron($('.test_advanced'), {
	scroller: '.scroller',
	container: '.container',
	bar: '.scroller__bar',
	barOnCls: '.scroller__bar_state_on', // Класс, навешиваемый скроллбару, когда он должен быть видимым
	barTop: 40, // Ограничитель позиции скроллбара сверху
	header: '.header__title',
	hFixCls: 'header__title_state_fixed', // Класс, навешиваемый зафиксированным заголовкам
	selector: qwery, // Селектор
	event: function(elem, event, func, off) { // Менеджер событий
		if (off) {
			bean.off(elem, event, func);
		} else {
			bean.on(elem, event, func);
		}
	},
	dom: bonzo // Библиотека для работы с DOM
});

Для менеджера событий пришлось сделать обёртку, поскольку его интерфейс отличается в разных библиотеках. В принципе, можно обернуть нативные функции типа addEventListener и отказаться от специализированного менеджера событий.

Тестирование


В тестировании принимали участие актуальные версии браузеров Chrome, Firefox, Opera, Safari и Internet Explorer (IE) на платформах Windows, Mac и iOs (тестировались, конечно, только существующие версии браузеров :)). Кроме этого, тестировался IE9 и IE8. Все тесты на всех браузерах проходят нормально.

Особенность предлагаемого в данной статье решения заключается в том, что даже в случае каких-то ошибок в JavaScript, скролл всё равно будет работать, поскольку он системный, поэтому категорию риска попадают лишь браузеры устаревших версий Android и Opera Mini, в которых системный скролл на элементах не реализован, или реализован плохо.

Итог


Предложенное решение позволяет сохранить механизм системного скролла, заменить его дизайн, полностью отказаться от жестких зависимостей от других библиотек, и уложиться в 998 байт сжатого кода (минифицированного и сжатого gzip). В довесок к этому, есть механизм фиксации каких-либо элементов скроллируемого контента (например, заголовков).

К недостаткам можно отнести отсутствие горизонтального скроллбара и контролов управления вертикальным.

Код решения можно скачать с Github.
Демо.

Внедрение данного решения запланировано на начало марта.
Автор: @Diokuz
2ГИС
рейтинг 87,02
Карта города и справочник предприятий

Комментарии (132)

  • +2
    Можно ли использовать в своих проектах? Если да, то это отлично. Работает плавно и красиво. Обожаю минималистичный дизайн. К тому же на iPad тоже работает. К заголовкам нужно привыкнуть, но скролл не хуже чем в gmail.
    • +4
      Да, конечно можно.

      Заголовки можно не использовать.
      Есть даже форк, где этот функционал вырезан.
      • +3
        darkwebdev.github.com/baron/test/ — ссылка на форк для ленивых. Для меня эта ссылка полезнее, чем демо из поста.
        • +3
          Я свернул браузер в окно и вот что вышло :) Chrome 25

          • +3
          • 0
            Это ошибка в вёрстке самого теста, а не барона… но всё равно спасибо)

            PS: Просто нужно чтоб каждый тест создал свой z-index контекст.
      • 0
        а чем не устроил user-select: none (с кросс-браузерными модификациями) для отмены выделения?
        css включен у всех, а javascript нет.
        • +7
          user-select — не кроссбраузерное и не стандартное решение. Например, оно не работает в Opera и IE. Более того, там где оно работает, оно может быть в любой момент отменено — так что без гарантий.
          В изначальном варианте блокировки выделения, врапперу выставлялся инлайновый стиль с префиксными свойствами user-select. Однако позже выяснилось, что оно, на фоне остальных механизмов, избыточно.

          Если у пользователя нет JS, то у него не будет работать не только кастомный скроллбар (но останется системный!), но и 2ГИС-онлайн в целом.
          В современном интернете отсутствие JS — нонсенс.
      • 0
        А зачем они включены в плагин по умолчанию? Лучше их сразу отдельным модулем оставить.
  • +2
    По сути это тоже костыль…
    • 0
      В чистом виде, но что делать, если скроллбары все еще являются кошмаром любого разработчика/дизайнера?
      • +2
        Использовать костыли :) Пока ваше решение самое изящное из всех существующих…
        • +1
          Это не мое. Хотя я реализовал поддержку нативного скролла таким же образом в более сложном варианте. Предложенное авторами решение работает в том числе и с touch-устройствами, без дополнительных ухищрений, о чем они забыли упомянуть.
          • 0
            Андроид 2.2 в родном браузере не работает
            • 0
              Решение делалось под iPad и ввиду, отказа заказчика от разработки — не закончено (остановились на beta-версии), поэтому может и не работать, но это легко фиксится, так как работает на дефолтном скроле.
              • 0
                В Андроид 2.2 вроде как нет дефолтного скрола.
    • +7
      так ведь в начале статьи написано, что в стандартах нет возможности кастомизации скроллбара, значит любое решение будет костылем. но верстальщикам не привыкать, если не тормозит и кроссбраузерно — вин.
  • 0
    Единственным существенным минусом этого решения является отсутствие возможности реализовать smooth scroll средствами css transitions.
    А для «библиотечности» нужно упростить работу и дать возможность запускаться без настроек: acBar($('.scrollable)), используя только подготовленную верстку и кусок кода. И уж, если функция acBar понимает, что объект завернут в jQuery-обертку, то лучше использовать ее как расширение $('.scrollable').acBar()
    • +2
      Особенность решения в том, что оно не является плагином какой-либо библиотеки, и вообще не имеет жёстких зависимостей.
      jQuery легко может быть заменён на что угодно.
      Так, например, в одном из форков, ценой IE8, baron сделан полностью независимым от сторонних библиотек. Нам, к сожалению, пока ещё нужно поддерживать этот браузер.

      Что касается transition`ов, то это спорный вопрос. Все привыкли к тому, к чему привыкли — системному скроллбару.
      А вот, допустим, в IE transition`ы скролла есть по-умолчанию, и это портит жизнь разработчикам.
      • 0
        Если вы реализовали поддержку jQuery, то почему бы и не сделать это решение в стиле jQuery, для этого не придется изобретать костыли, зато упростит жизнь разработчикам. Отсутствие зависимостей — это плюс, но не стоит ради этого отказываться от удобства.

        • +1
          в принципе, можно написать малюсенький адаптер для jQuery и положить рядом на гитхаб
          • 0
            Я не говорю про полный отказ от использования глобальной функции, а лишь про то что библиотека использующая jQuery, должна включать вариант в стиле jQuery. Это вопрос профессионализма — подчиняться принятым стандартам, ради всеобщего удобства.
            Многие библиотеки из коробки одновременно поддерживают jQuery, nodejs и AMD. Зачем нужна поддержка jQuery, если в результате используется собственная конструкция? jQuery, тем и красив, что используется одинаково для разнообразных задач. И если бы разработчики jQuery рассуждали так же как автор, то мы бы продолжали заворачивать функцию в функцию, завернутую в функцию…
            • 0
              мне кажется тут где-то недопонимание, у барона нет поддержки jQuery, для уменьшения размера он написан на чистом js, просто в примере показано как передавать в опции элементы при помощи jQuery, если он уже подключен к проекту.

              т.е. можно написать baron($('.wrapper')...), а можно baron(getElementById('elementId')...)
  • 0
    Эталон кроссбраузерности :)
    image
    Если интересно, то аддонов ровно три — AdBlock, OmniBar и Speed Dial
    • 0
      На той же версии (но без плагинов) всё ок. Ну или поправили уже.
      • 0
        На той же версии с теми же плагинами проверяли — всё было ок. Видимо, проблема была не в браузере.
  • +11
    А зачем вообще делать кастомный скролл?
    • +2
      Затем что дефолтный скроллбар во вложенных элементах — это уродство?
      • +1
        Не понял что вы хотите сказать. Переформулируйте что ли?
        • +3
          Ну возьмите элемент поместите его по-середине страницы и поставьте overflow:scroll. Что ли.
        • +7
          вот это было бы уродством:

          image
          • 0
            вместо тысячи слов ))))
            • +15
              Ну а я бы не хотел, чтобы вы мой маковский скролл заменяли.
              • +1
                А его никто и не хочет заменять. Все хотят скролл как мой маковский ))
                • +1
                  И что, ваш скролл умеет исчезать или нет, в зависимости от настроек на «Маке»?
                  • 0
                    Я имел в виду, что у меня тоже Мак и мне хочется, чтобы все скроллы в мире были похожи на Маковский.
                    • +3
                      Это интересное желание, но у меня скролл, например, не пропадает, а у кого-то настроено, чтобы пропадал (поведение по-умолчанию). И мне хотелось бы, чтобы переключение этой настройки определяло как будут вести себя все скроллы в системе.
                    • +3
                      Я ни за что в жизни не хочу, что бы мой scroll был как на Маке, простите уж.
                      • +3
                        Почему?
                        • +1
                          Очевидно, потому что он не любит мак)
            • +22
              Хм, я почему-то не нахожу это уродством, нормальный скроллбар. Можно было бы утверждать что системный скроллбар уродство если у вас темный дизайн, но, в случае со светлым дизайном и светлым скроллбаром в виндах, я просто решительно не пойму яростное желание дизайнеров/владельцев сайта закастомизировать скроллбар. W3C на то и ответила «full stop», что скролбар это нечно больше чем элемент дизайна сайта — это системный контрол который люди привыкли видеть таким какой он есть. Ну и как маковод, лично я, например, ненавижу до глубины души когда сайты переиначивают нативный оверлейный/невидимый скроллбар и вставляют свой костыль со своим кастомным дизайном.
              • –4
                В том-то и суть, что сколлбар смотрится нормально только на Маке. И то что w3c ответила «full stop», говорит о том, что они не провели должного анализа и, вместо создания стандарта, отделались отговоркой. Они и пятый html не смогли запустить, пока их whatwg под жопу не пнуло. Так что не о чем разговаривать.
                • +9
                  Вкусовщина полнейшая. Я, когда Виндой пользовался, терпеть не мог маковские скроллы, они неестественно смотрятся в винде.
                  • 0
                    Дизайн скролла полностью задаётся в CSS. То, что демо-дизайн похож на маковский — ни о чём не говорит.

                    Вы можете сделать скроллбар в стиле Windows XP — и он таким будет на маках и линуксах ))
                    • +5
                      Я не понял зачем вы мне это говорите.

                      Я вам говорю, что в каждой системе чужой скролл смотрится неестественно. Желание «осчастливить» пользователей Винды маковским скроллбаром понятно не будет. Меня такие попытке на винде всегда раздражали.
                      • +1
                        А как вы поступите если есть макет дизайна с кастомным скроллбаром и нет возможности оставить нативный, так как и дизайнер и заказчик настаивает на его реализации?

                        Я не думаю что ваши аргументы убедят одного и другого в обратном.
                        • +10
                          Я никак не поступлю. Не занимаюсь этим. Меня как пользователя это бесить будет. Так и передайте вашему дизайнеру с заказчиком :)
                          • +1
                            Сколько людей, столько и мнений. Спасибо за фидбек!
              • +2
                W3C ответила по поводу скроллбара всей страницы в контексте того ужаса, который творился в IE заменой цветов, на красно-чёрный, например.

                Сейчас ситуация меняется. Если FF реализует кастомизацию скроллбара, то такая кастомизация станет де-факто стандартом, к которому со временем подтянется ИЕ. Весь webkit это уже поддерживает.
              • +2
                это бесконечный спор, почему можно кастомизировать кнопки, но нельзя скроллбар? или вообще ничего нельзя менять в интерфейсе?

                к примеру, на нашем проекте все наши дизайнеры сошлись в мнении, что стандартный скролл выглядит убого внутри попапа, поэтому мы договорились, что главный скролл на сайте должен быть стандартным (потому что он скроллит контент внутри стандартного окна и пользователю это привычно), а внутренние элементы интерфейса должны быть в стиле сайта.
                • 0
                  Лучше бы плавность скролла колёсиком в левом меню исправили, а не меняли внешний вид.
                  У меня нет возможности колёсиком нормально прокручивать, дергается и прыгает список.

                  А на телефоне, его так вообще невозможно промотать :(
                  • 0
                    извините, я погорячился… хотя у меня действительно скролл дергается и в Опере он не исчезает в левой панели, хотя его там не должно быть, т.к. контет может аш 2 раза там поместиться.
                    • 0
                      О какой левой панели идёт речь?

                      На maps.2gis сейчас используется FleXcroll, который будет заменён на baron где-то в марте.
          • 0
            Вообще-то на скриншоте ничто не мешает увеличить «облачко», чтобы не появлялся скролл. Не думаю, что это сложнее, чем написать свой скролл.
            • +1
              Это сложнее, т.к. «облачко» может иметь внутри все что угодно. Скриншот вверху лишь один из вариантов его контента.
              • 0
                Если «что-угодно» может быть настолько большим, что никак не поместится в «облачко», вполне вероятно, что стоит задуматься о другом способе подаче информации. См. например, смартфоны, в приложениях которых информации может быть много, а места на экране мало.
                • +2
                  Так мы можем уйти далеко в философию.
                  Применение скролла очевидно. Если есть интерфейс, размещающийся строго на одном экране, внутри всегда будут области, в которых необходим скрол. Возьмите тот же айпад и откройте настройки.
                  Я согласен, что «облачко» надо дорабатывать. Но скрол здесь не при чем.
                  • 0
                    На айпаде скроллятся целые части страниц. Механизм ничем не отличается, скажем, от проводника Windows. В таком интерфейсе нет проблемы: «скроллбар плохо смотрится в окружении». Я о том и говорю, что если скроллбар попал в окружение таким образом то, что-то пошло не так.
                    • 0
                      > Я о том и говорю, что если скроллбар попал в окружение таким образом то, что-то пошло не так.

                      Никак нет) Тенденция превращения длинных многостраничных сайтов в одностраничное приложение есть, и это факт. В таких приложениях у окна скролла нет вообще.
                      • –1
                        У окна проводника тоже нет скролла, только у частей. Но там нет проблемы плохо выглядещего скроллбара. Вы вообще понимаете, что я вам пытаюсь втолковать?
                        • 0
                          в проводнике весь интерфейс в таком же стиле, как и скроллбар. а на сайте дизайн совсем не такой как в ОС.
                          • 0
                            Что-то вас совсем не туда занесло.
        • +1
          Например, на андроиде скроллбар не виден у какого-либо элемента, только у всей страницы. На андроиде 2.3 вообще такое понятие, как скроллбар, знает только страница, а элементы не понимают overflow: scroll. Я тоже этим вопросом занимался, искал решение — а решений не было вменяемых, т.к. всё тормозило. Но данный скролл достаточно хорошо себя показал.
    • +3
      Не всегда есть возможность влиять на дизайнерские решения, для некоторых проектов кастомный скролл «ОЧЕНЬ важен!!!111», к сожалению.
  • 0
    Chrome 24 Mac OS X 10.8 трекпад — скролл какой-то дерганный, не то что бы совсем, но сразу бросается в глаза.
    • +4
      Chrome 24, Mac OS X 10.8, трекпад — скролл в демке плавный.
      • 0
        Так я и не говорю что он не плавный, но такое ощущение что нет 60-ти фпс
        • 0
          Если вы об этой ссылке diokuz.github.com/baron/
          то небольшое подтормаживание возможно на слабых системах из-за наложения двух градиентов поверх скроллируемого контента.

          Например, на Mac Air 2012 i5, fps в Chrome падает ниже 60 только в самом начале скролла. А вот на десктопе с дискретной видеокартой не происходит и этого — fps всегда выше 60.
          • 0
            Нет, здесь явно что-то не так, оно то нормально скроллится, то фпс явно проседает, несмотря на то что инспектор показывает 60 фпс всегда, MacBook Pro 13 late 2011.
            Кажется такое есть только если скролл доходит по инерции до конца, и когда курсор стоит внизу, потом начинаешь крутить вверх.
  • 0
    Сафари 6.0.2, Мак. Застревает скролл в некоторых положениях и не реагирует на прокрутку двумя пальцами.
    • +1
      Проблема не воспроизводится. Попробуйте посмотреть текущую версию baron diokuz.github.com/baron/

      Сам по себе скролл не может застрять в принципе, потому что он — системный.
      Сбой может происходить только при выходе курсора за пределы «окна» скроллируемого контента.
      • +1
        Всё ок сейчас.
  • 0
    htmlpreview.github.com/?https://github.com/Diokuz/baron/blob/master/demo/index.html

    Не понял куда смотреть. Скролл у меня дефолтный, только колесом почти не крутится.
    • 0
      Попробуйте вот сюда: diokuz.github.com/baron/
      Это самая новая, но нестабильная версия baron.
  • 0
    А почему на Mac не скрывается сам скроллбар?
    • 0
      Всё скрывается. Тот бежевый, что вы видите справа — и есть кастомный.
    • 0
      По-умолчанию в демо-дизайне кастомный скроллбар виден всё время.
      Можно настроить в CSS чтоб он делался более прозрачным (сейчас 0.6 и 0.8 при ховере).
  • +1
    Вы кстати как нибудь боролись с кастомный скролом внутри текстарии, или вам это не нужно было?
    • 0
      Это хороший вопрос, но пока ничего сказать не могу — исследований не было.

      На первый взгляд кажется, что должно работать, но это догадки, и надо проверять.
    • +1
      Было дело, изучал это и писал для этого скрипт.
      Для упрощения просто доработал (расширил) для этого jScrollPane.

      Это было давненько, в 2007 году, делал я это для проекта yatv.ru

      Вот как это выглядит:

      image

      Кстати, посмотрел сейчас код и вспомнил, что принцип тот же, что и у автора статьи — я увеличивал размер textarea, чтобы он выходил за пределы блока и поэтому всё было нативно. Если этого не делать, то textarea вроде не переносит overflow:hidden, как-то так, уже не помню, если точно =)

      Пользуйтесь js, css

      Вызывать так $('textarea').jScrollPane({showArrows:true, scrollbarWidth: 13, scrollbarMargin:0, wheelSpeed: 60});
  • 0
    На iPad'е прведение вашего скролла отличается от поведения системного — если скролл системный, то резким движением страница скроллится до предела, а у вас только на небольшой фрагмент.
    • 0
      Да, пока нет инерции, к сожалению.
      • +1
        Вдоль всех комментариев меня мучает вопрос. Почему в iУстройствах не оставить стандартный скролл, и только в других сделать кастомный? Как я понял, и вам, и пользователям нравится стандартный скролл iУстройств.
        • 0
          Почему же нет? Ничто вполне не мешает оставить стандартный скролл в iOS.
        • 0
          Для этого достаточно проверять в JS платформу, и инициализировать baron только на не маках.

          Но прилипающие заголовки работать не будут.
    • 0
      К сожалению, в iOS скролл на элементах реализован плохо (но он хотя бы есть, в отличие от старых версий андроид).

      То о чём вы говорите — скролл всей страницы. Он «летает» как надо.
      Скролл внутри элементов ведёт себя иначе и «тормозит». Тут я ничего сделать не могу, поскольку на механизм скролла никак не влияю.

      На OS X, кстати, скролл элементов по механизму идентичен скроллу окна — пользователи трекпадов уже оценили.
      • 0
        Попробуйте overflow: auto; и -webkit-overflow-scrolling: touch; — инерция вернется, но немного изменится механизм рендеринга.
        • 0
          При -webkit-overflow-scrolling: touch скроллбар не стилизуется.
  • 0
    Изменение размера страницы не приводит к пересчету размера хреновинки скроллера, зато она пересчитывается при первой попытке прокрутить. Выглядит не очень, но, вроде бы как, должно быть нетрудно исправить?
    • +2
      Это баг, будем править. Спасибо за наводку.
  • 0
    Отличное решение, спасибо

    Пример очень сильно шатает при изменении высоты окна браузера, из-за динамической высоты блока (70%). Высота скоролл-бара тоже пересчитывается только после вызова события (mousewheel у вас, вроде). Если это критично ресайз, наверно, придется тоже какой-то слушать.
    • +1
      window.resize уже слушается не чаще каждых 200 мс.
      Это баг.
    • +2
      Баг исправлен.
  • 0
    А как он реагирует подгруженный через ajax контент? высота скролла меняется, новый контент можно прокрутить?
    • 0
      хороший вопрос, завел тикет, чтобы автор не забыл)
      • 0
        можно в комплите ajax-a дергать $(window).resize();
    • +1
      В новой версии уже всё сделано) На днях вкомитаю в гитхаб.
  • +1
    А этот areaaperta.com/nicescroll/ не пробовали?
  • 0
    Ужас получается, когда на странице, которая выше окна браузера, встраивается еще pane с прокруткой, высотой чуть ниже видимой части страницы.

    Эти страдают очень многие сайты, и прокрутка становится мучением. Вариант один — жить с браузером ровно того размера, как у автора такой поделки.
  • 0
    Проблема подобных скроллов в том, что они никак не реагируют на выделение текста. Однажды я взял первый попавшийся scroll-плагин для jQuery и попробовал исправить этот недостаток.
    Что из этого получилось, можно посмотреть здесь narod2.ru
    • 0
      Не могли бы вы подробнее описать проблему? У меня выделение текста скроллит — как и положено.

      Или ваш пост относился к коментарию про nicescroll?

      PS: Ещё один плюс baron`а detected)
      • 0
        Проверил в хроме — скроллит, в опере у меня не скроллит
        • 0
          В опере не работает такой скролл внутри элементов. Это баг оперы, а не барона.
  • +1
    Некоторые отщепенцы, типа меня, пользуются плагином для FX Grab and Drag. Так вот ваш плагин один из немногих, кто не конфликтует и продолжают нормально работать. Колесико, конечно, панацея, но далеко не всегда, особенно если отсутствует кинетическая прокрутка (чем быстрее крутим, тем больше шаг прокрутки).
    • +2
      Просто это не плагин, поэтому конфликты невозможны)

      Что касается кинетической прокрутки — на нормальном железе всё давно реализовано. Например на маках, или на некоторых сенсорных мышках (тот же Genius с «синим глазом» вместо колеса).

      Идеология барона простая: как крутить — лучше знает железяка под управлением операционки, а как это показывать — дизайнер приложения.
  • 0
    Так и вижу минималистичную версию статьи:
    «Кроссбраузерная кастомизация системного скроллбара. …демо…, …аннотированный код…».
  • 0
    Мне кажется, без js должен быть виден нативный scroll:

    <noscript>
    <style>
    .wrapper {overflow:auto;}
    .scroller {overflow-y:visible;}
    </style>
    </noscript>

    А так хорошая идея, напоминает то, как сделали оформление кнопки «обзор» для загрузки файла — там эту кнопку скрывают и двигают над мышью, чтобы при клике она работала нативно =)
    • –1
      В примере так и сделано.
      • 0
        Ничего подобного (noscript) здесь нет diokuz.github.com/baron/
        скрин (js отключён) — прокрутки не видно.
        • 0
          noscript может и нет, но я явно вижу скролл при отключении JS.
          • 0
            да, в IE видно, в Хроме нет.
        • +1
          У вас, наверное, браузер на Webkit
          .scroller::-webkit-scrollbar { /* Preventing webkit bug of horizontal scrolling */
              width: 0;
          }
          
          • 0
            угу, значит нужно это тоже отрубить для noscript (или даже только это)

            спасибо
  • +1
    Автор, пожалуйста, оформите код в виде плагина. jquery plugin patterns
    Засорять window плохая практика.
    • 0
      Это можно сделать форком, но независимость baron от jQuery — ключевая его особенность и одно из основных наших требований.

      Скажу больше: в будущей стабильной версии, скорее всего, baron вообще никогда не будет использовать jQuery у себя внутри, поскольку требование IE8+ делает возможным использование plain js для добавления классов, стилей и обработчиков событий без заметного увеличения объёма кода.

      Сейчас единственный объект в глобальном пространстве — baron с двумя методами. Всё остальное в замыканиях. О других библиотеках baron js мне не известно, поэтому ограничение — только на глобальную переменную baron.
  • +2
    То есть, пользователь крутит колесо мыши, под курсор попадает заголовок, фиксируется, и, внезапно, скролл перестаёт работать (точнее, скроллиться начинает вся страница).

    Кстати, интересное решение на css, имхо:
    pointer-events: none;
    


    Конечно, не настолько таргетированное, как ваше, но со своими достоинствами.

    А вообще за статью спасибо. W3C — редкостные мудаки, что не дают стилизировать скроллбар.
    • 0
      Та же проблема, что и с user-select. Имея реализацию на JS, ограниченное CSS-свойство ни к чему.
      • 0
        К счастью, в webkit браузерах (а нам требовалось обратиться только к ним) есть такая возможность:

        Тот же кусок.
    • 0
      Шикарное решение! Правда, кроме неподдержки ie8, есть ещё один досадный недостаток — заголовки вообще перестают реагировать на мышь, и в них даже текст нельзя выделить. Но в комментарии CSS добавлю.
  • 0
    О найденных багах в WebKit сообщали?
    • 0
      Нет. Баг горизонтального скролла можно назвать фичей, которая позволяет просматривать скрытый контент.

      Есть опыт общения с багтрекерами вебкита и ff — тикеты висят годами, ибо не критичные.

      Один только баг анимации псевдоэлементов в вебките правили 2 года и 3 месяца — и это только до попадания в канарейку хрома.
      • 0
        Кстати, ещё overflow:hidden можно скроллить хитрым способом в ВебКитах)
        Нажимаем колёсико мышки на скроллабл-блоке и двигаем её.
    • 0
      Есть вот такой баг.
  • +7
    Запись эфира на радио маяк, в общем нам всем гореть в аду :)
    • +1
      image
  • +1
    barTop: 40, // Ограничитель позиции скроллбара сверху
    

    А есть ли возможность сделать оступы сверху и снизу? Я сейчас верстаю макет и вот у меня примерно такая задача… + трек.

    • +1
      Теперь можно)
      barTop отменён, позиционирование делается через css родителю bar`а (см. папку demo в текущей версии baron)

      Спасибо за пул-реквест)
      • +1
        оу еее! Спасибо тебе друг! А то такой костыль в верстке пришлось делать…
  • 0
    Может поздновато, но думаю кому-нибудь это будет любопытно:
    www.noinimod.ru/52/ — неплохое, давно созданное, решение.
  • 0
    Реально ли отключить Барона на iPad, так как там уже стоит webkit-overflow-scrolling: touch для скроллера?
    • 0
      Конечно!

      Детектим iOs stackoverflow.com/questions/9038625/detect-if-device-is-ios

      Далее если iOs — не инициализируем барона.

      Можно сделать ход конём и задисплейнонить кастомный скроллбар на ретинистых устройствах. Но там вроде лиса есть.
      • 0
        Пока ждал вашего коммента, реализовал похожим способом через Modernizr (https://gist.github.com/danott/855078), так как он уже подключен к странице. Добавляю класс на iPad'e и при его наличии скрываю скролл.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.

Самое читаемое Разработка