Pull to refresh

Comments 62

Дизайнеров, которые требуют нестандартных скроллбаров, надо ИМХО наказывать за непрофессионализм.
На самом деле этот вопрос довольно сложен — в некоторых случаях необходимо избавиться от скроллбара в центре сайта, т.к. это портит весь дизайн. Про замену системного скроллбара, который скроллит всю страницу, здесь речи не идёт.
Наличие прокручиваемого блока само по себе нередко говорит о беспомощности дизайнера. Необходимость нестандартной стилизации соответствующей локальной полосы прокрутки — лишь следствие.
На всякий случай: если работа с дизайном, использующим локальную (и нестандартно стилизованную) полосу прокрутки, неизбежна, то наличие JavaScript-решений, несомненно, полезно. Главное — чтобы использование JS-решения было способом воплощения неправильного дизайна, а не, наоборот, дизайнер беспечно использовал локальную прокрутку только на том основании, что технические решения для реализации нестандартной полосы прокрутки существуют. На уровне дизайна использование локальной прокрутки — решение в подавляющем большинстве случаев неудачное.
Поддерживаю. Люто ненавижу замену системным скролам. Для google wave например даже расширение в хроме было, возвращающее родной скролл.
Если вести по диагонали и упереться в одну из сторон, то начинает глючить.
Как именно и в каком браузере?
А как именно начинает глючить? В чём проявляется?
Просто у меня во время тестирования на такой же конфигурации никаких отклонений от стандартного поведения не наблюдалось. Возможно я что-то упустил во время тестов.
Если вести допустим строго в право а потом вниз, вместо прокрутки (на втором примере, на первом похоже работает как надо), браузер прокручивает основное окно.

PS в примере с XP барами, не хватает эффекта вдавленности.
Такое поведение наблюдается в Хроме и с родным скроллом. Дело в том, что при достижении конца скролла (т.е. когда контент полностью прокручен в том направлении, в котором Вы его ведёте), скролл перехватывается основным окном, и обратно на элемент уже не возвращается.

Кстати, первый и второй скролл абсолютно одинаковы по функциональности. Различие — применяемые стили.

Насчёт вдавленности: скролл поддерживает изменение стилей для dragged-скролла, просто не добавлены CSS-стили.

Прмеры CSS-изменения цвета в зависимости от hover и от dragged добавлены во втором и третьем примере (Simple outer scrollbar): hover делается нативным CSS, а при нажатии мыши скроллу добавляется класс scroll-draggable.

Чуть позже добавлю пример для скролла в стиле MacOS — из-за изменения системы позиционирования, стили для этого скролла не были переписаны, поэтому пример не был добавлен.
Я вам еще раз повторяю, в первом скроле все работает как надо (стиль XP), во втором возникает этот баг.
Честно говорю — без понятия почему так происходит, попробуйте. Если не верите могу сделать видео.
Что именно тормозит? Какие действия производите?
Для сравнения справа есть две кнопки Init и Destroy для возможности сравнить с оригинальным поведением скролла.
Скроллинг тормозит, нативный работает нормально, ваш же имеет задержку в несколько миллисекунд.
Возможно тормозит изменение позиции бегунка скроллбара, но скролл контента тормозить не должен. Отличие JavaScript обёртки от полной эмуляции скролла в том, что в полной эмуляции вначале генерируется событие, которое изменяет всё почти одновременно, а в обёртке вначале браузер производит действие, потом генерирует событие, обрабатываемое JavaScript-ом.

Если же речь идёт об изменении размеров содержимого, то там стоит задрежка в 300 мс для пересчёта размеров скроллбара. Другого способа автоматически отловить изменение размеров контейнера я не нашёл.

Можно, конечно же, вызывать переинициализацию скролла и вручную сразу после изменения размеров контейнера/содержимого, но задача стояла именно в том, чтобы «подключить и забыть». По этой причине я не стал делать переинициализацию сразу же, а показываю то, что ожидает пользователя при практическом применении.

Если задержка критична, можно вручную вызывать переинициализацию нужного контейнера после обновления.
Вы настолько крут, что замечаете задержку в несколько миллисекунд? Оо
Понравился, скроллбар близок к идеалу
Спасибо, этого и добивался.
jScrollPane отличный плагин, сталкивался с ним. Но на тот момент, когда мы им пользовался, сталкивался с проблемами переинициализации скролла, после того, как контейнер становился невидимым или изменял свой размер.
Там же есть функция для принудительно переинициализации. То же самое приходится делать при изменении содержимого прокручиваемой области. Да, решение генерит лапшу в коде, но вполне реально сделать красиво.
В том-то и проблема. что в нашем случае переинициализация не помогала. Возможно проблема была в том, что менялись стили — контейнер скрывался/показывался с помощью jQuery slideUp/slideDown. После подобного помогает только дестрой и новая инициализация скролла. Помимо этой, были и некоторые другие проблемы, связанные с тем, что данная реализация — это всё же эмуляция скролла, а не родное поведение.
Нажатия на стрелки по краям полос срабатывают только при отпускании, в родном же варианте при нажатии, а при задержании нажатия начинается продолжительная прокрутка.
Довольно сложно обработать все нативные события скролла. Для обработки подобных событий необходимо подключать дополнительную библиотеку обработки событий мыши, чего мне очень не хотелось делать так же, как и увеличивать размер плагина. По этой причине я ограничился минимальным необходимым для эмуляции фукнцоиналом.

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

Это есть в JavaScript без библиотек, и событие уже обрабатывается, но не верно (отпускание/нажатие кнопки мыши).
Изменил поведение на mousedown — это действительно удобнее, чем клик. Однако насколько необходима поддержка удерживания кнопки мыши нажатой на данном элементе — вот в чём вопрос.
Обновил плагин и добавил поддержку удержания мыши. Хотя поведение немного и отличается от родного, но работает почти также.

Отличие в том, что родной скролл перестаёт работать если убрать мышь за пределы стрелочки. В JavaScript-е это сделать нельзя, т.к. событие mouseleave не происходит, если кнопка мыши не отпущена. Но думаю, что это событие можно отследить через mousemove.
UFO just landed and posted this here
Планирую добавить по возможности отключение скролла всей страницы, если у контента прокручивается, т.к. мне тоже не нравится подобное поведение. Однако текущей задачей стояло сохранение родного поведения скролла браузера.
UFO just landed and posted this here
Извиняюсь, обдумывал другую проблему, поэтому не до конца вник в смысл предыдущего комментария.

Сейчас довольно сильно отличается прокрутка колёсиком мыши основного контента, от эмулируемой прокрутки (когда указатель мыши находится над скроллбаром — упомянуто в топике), и отличия не только в различии шага прокрутки, но и в не очень хорошей поддержке JavaScript-обработки событий скроллинга мыши. Насколько я знаю, не во всех браузерах указывается отдельно указывается прокрученное растояние по осям X/Y (по крайней мере так написано в док-е по jQuery MouseWheel event).

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

Другой вопрос — то, что есть мыши, позволяющие прокручивать и по горизонтали, как в Вашем примере. Исходя из того, что я возможно не смогу отличить скролл по вертикали от скролла по горизонтали средствами JavaScript, считаете, что стоит отключить подобное поведение?
UFO just landed and posted this here
Учтено. Отключил обработку скролла мыши горизонтальным скроллбаром. Но пока комитить не буду, т.к. работаю над другой задачей и изменения нестабильны.
Для анимаций лучше использовать requestAnimationFrame и transform: translateX[Y] (поддержка gpu) в купе с фоллбэками для старых браузеров.

Советую посмотреть исходники скроллера Sly и статью Leaner, Meaner, Faster Animations with requestAnimationFrame.

Разница может быть такой (а в мобильных браузерах она будет особенно заметна):
Спасибо за наводку. Прежде не сталкивался с оптимизацией анимации, но в данном случае мне хватает возможностей, предоставляемых jQuery. В данном плагине я стараюсь свести количество используемой анимации к минимальному, либо вообще отказаться от анимации.
Есть техника отслеживания изменения размеров блока через подписку на события «overflowchanged» / «resize» — работает в IE, Firefox, Chrome, Opera, Safari
Это позволит вам избавится от setInterval для проверки изменения размеров блока.
Там, где эта техника не работает (напр., Opera), можно оставить setInterval.
Большое спасибо за ссылку, не знал про это. Протестирую и добавлю функционал в плагин в ближайшее время.
Я попробовал воспользоваться методом, используемым в той статье, но, увы, у меня ничего не получилось. Данный метод позволяет обнаружить изменения в размере самого блока, но не изменения размера внутреннего содержимого. К сожалению, пока что придётся оставить обновление по интервалу, а в критичных случаях — вручную пользователем, после какого-либо изменения.
Сделал pull request
Чтобы детектить изменения размера контента, достаточно его обернуть в блок, который флотнуть- а на этом блоке уже «слушать» события «overflowChanged»/«resize».
Теперь во всех юраузерах, где срабатывает способ, описанный в ссылке выше- используется он вместо setInterval.
Иначе- все по-старому.
Метод без setInterval не сработал, как и ожидалось, только в Opera.
Большое спасибо за участие в проекте.

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

Как Вы видели в обсуждении, даже минимально необходимое вмешательство в структуру HTML может привести к недопониманию «почему мой код раньше изменял элемент, а теперь не работает?», подобное же вмешательство может привести к пересмотру кода и необходимости исправить его с учётом наличия/отсутствия подконтейнера resize-listener.

Пользователь всегда может вручную переинициализировать скролл при изменении содержимого.
Ну и как теперь делать программную прокрутку в нужную позицию?

$(".class:first")[0].scrollTop = pixelsFromStart;

Это больше не работает.
Следует помнить, что для работы стилизованного скроллбара необходима определённая HTML структура, для которой исходный контейнер JavaScript-ом оборачивается в другой контейнер при инициализации.

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


Фукнцоинал скролла родной — браузерный, т.е. все нативные фукнции работы со скроллом работают.

Решения два:
  • добавить нужному контейнеру айди: $('#elementId').get(0).scrollTop = pixelsFromStart;
  • отсеивать элементы по классу с помощью not: $('.class').not('.scroll-wrapper').eq(0).get(0).scrollTop = pixelsFromStart;
Спасибо! Извините, что невнимательно читал, просто нужно было быстро внедрить этот плагин, а на первый взгляд в посте ничего особенно важного не сообщалось.
Простите, а чем не подошёл baron, ссылка на который даже есть в статье? Удовлетворяет всем пунктам кроме последнего — отключение на мобильниках «из коробки», что решается трёхстрочной обёрткой.

diokuz.github.com/baron
От использования baron-а остановила незавершённость плагина — отсутствие горизонтального скролла. Кстати, именно с горизонтальным скроллом проблем намного больше, чем с вертикальным, т.к. все браузеры заточены именно на растягивание по ширине, но не по высоте. Либо для элемента необходимо выставлять фиксированную высоту, что, имхо, неправильно. Ну, плюс ещё несколько особенностей, среди которых неперекрывающий и внешний скролл.
Горизонтальный скролл давно реализован в бароне, это можно посмотреть на странице с тестами.

Внешний скролл / скролл произвольных размеров и позиций также возможен.
Наверно, фразу в конце вашей статьи: «К недостаткам можно отнести отсутствие горизонтального скроллбара…» стоит подкорректировать, потому что мне, например, пришлось из-за нее продолжить поиск альтернативного решения. К тому же, страница diokuz.github.io/baron/ не содержит примера с горизонтальным скроллом. Спасибо за отличный скрипт.
Статья была написана на конкретную версию барона — с тех пор много воды утекло.
Кстати баг в вебките с горизонтальным скроллом в бароне вылечен — об этом тоже в статье написано.
Буду честен, если скажу, что про баг в вебките я узнал именно из вашей статьи. Это свело на нет мою предыдущую реализацию, пришлось тотально пересматривать проблему позиционирования, что отложило выход этого поста на несколько дней. В представленной реализации баг решён только частично, а ваш способ с процентными размерами не подходит для высчитвания высоты контейнера.

Точное значение, на которое прокручивается контейнер при выделении текста, я высчитать пока не могу, но подозреваю, что это около 10-12 пикселей, даже если высота и ширина скролла в вебките выставлена в 0. Так что я нахожусь в активном поиске решения или хака
Прекратите поиски)) Под решением я подразумевал обнуление ширины скроллбара через

.scroller::-webkit-scrollbar { /* Preventing webkit cross-direction scrolling bug */
    width: 0;
}


Но вы можете вычислить и точное значение если хотите — это offsetWidth — clientWidth при обнуленном бордере.
Ширину и высоту обнулил — браузер всё равно продолжает скроллить. В демонстрации даже есть блок, помеченный (bug on text selecton in webkit browsers: chrome & safari), который всё равно продолжает скроллиться. Думаю, что тут дело в видимости внутреннего контейнера.

Не нашёл ссылки на демо с горизонтальным скроллом.

Там нет ссылки, нужно склонировать проект и посмотреть в тестах.

Также подключение горизонтального скролла описано в readme.
Да, чуть позже после комментария я скачал исходники и посмотрел тесты.
ИМХО, стоит обновить статью и добавить горизонтальный скроллбар в демо.
Хорошо бы, если иннер аутохайд скроллбар не пропадал, если он тягается, но мышь уже за пределами блока.
Легко — где-то на 446 строке (для сохранения порядка стилей) в CSS прописать

.scroll-simple_inner > .scroll-element.scroll-draggable .scroll-bar { display: block; }

Вечером внесу изменения в демо.
CSS решение (webkit)
::-webkit-scrollbar {
    width: 9px;
}

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

::-webkit-scrollbar-thumb {
    -webkit-border-radius: 10px;
    border-radius: 10px;
    background: rgba(241, 170, 44, 0.9);
    -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.5); 
}

Не хватает пары вещей. Было бы неплохо, если бы mousewheel крутил горизонтальный скролл, если вертикальный отсутствует, либо если на горизонтальный навели курсор).
А так неплохо
Как обсуждалось выше, данный функционал был специально отключён, т.к. данное поведение отличается от браузерного.

Однако его легко обратно включить — достаточно закомментировать условие на строке 249 (не забывая про закрывающую скобку): if(d == 'y'){
Sign up to leave a comment.

Articles