Фитискин Александр

Укрощаем колесо мыши и создаем полноценный scroll bar средствами JavaScript.

Вступление

Все началось с маленькой неподвижной html-заготовки:


<div id="content">
    <!-- Полоса прокрутки с ползунком -->
    <div id="scrollbar">        
        <img id="scroller" style="left: 0px;" alt="" src="scroller.gif" />
        <!-- Бегунок мы будем перемещать по полосе задавая css-параметр left -->
    </div>
    <!-- Таблица, которая будет перемещаться при перемещении ползунка -->
    <table class="js_menu" style="margin-left: 0px;" id="content">
        <tr>
            <!-- Некоторое содержание таблицы -->
        </tr>
    </table>
    <!-- Перемещать ее мы будем задавая параметр margin-left, причем значения в нем должны быть отрицательные -->
</div>
.scrolling_line img 
{
    position: absolute;
}
.content
{
    overflow:hidden;
}
</style>


Таблица будет шире, чем блок content, поэтому ее часть будет скрыта. Изменяя ее сдвиг (margin-left), мы будем двигать ленту ячеек, визуально создавая эффект прокрутки.

Вот такую html-заготовку использовал я:

Россия
Название
Описание
Цена
 
Англия
Name
Description
Price
 
Германия
Bezeichnung
Beschreibung
Preis
 
Франция
Nom
Description
Prix
 
Испания
Nombre
Descripcion
Precio
 
Италия
Nome
Descrizione
Prezzo
 
Украина
Назва
Описування
Ціна
 
Португалия
Nome
Descricao
Preco
 
Норвегия
Navn
Beskrivelse
Pris
 
Хорватия
Naziv
Opis
Cijena
 
Финляндия
Nimi
Kuvaus
Hinta
 
Чехия
Nazev
Popis
Cena
 
Голландия
Titel
Omschrijving
Prijs
 
Болгария
Заглавието
Описание
Цена
 

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

На старт, внимание, марш!

Сделаем заготовку скрипта, в которой получим все необходимые элементы и их параметры:


function get(id)
{
    return document.getElementById(id);
}

var scroller = get('scroller');
var scrollerBar = get('scroller_bar');
var object = get('object');
var content = get('content');

// Ширина видимой части объекта (в нашем случае — таблицы)
var objectWidth = content.offsetWidth; 

// Ширина объекта целиком
var objectTrackWidth = menu.offsetWidth; 

// Ширина ползунка
var scrollerWidth = Math.round( (objectWidth * scrollerTrackWidth) / objectTrackWidth );

// Учтем, что максимальная ширина ползунка - это ширина полосы прокрутки
scrollerWidth = (scrollerWidth > scrollerTrackWidth) ?  scrollerTrackWidth : scrollerWidth;

// Устанавливаем ширину ползунка
scroller.style.width = scrollerWidth + "px";

// На каждый пиксель сдвига бегунка мы будем сдвигать меню на величину delta
var delta = objectTrackWidth / scrollerTrackWidth;

Россия
Название
Описание
Цена
 
Англия
Name
Description
Price
 
Германия
Bezeichnung
Beschreibung
Preis
 
Франция
Nom
Description
Prix
 
Испания
Nombre
Descripcion
Precio
 
Италия
Nome
Descrizione
Prezzo
 
Украина
Назва
Описування
Ціна
 
Португалия
Nome
Descricao
Preco
 
Норвегия
Navn
Beskrivelse
Pris
 
Хорватия
Naziv
Opis
Cijena
 
Финляндия
Nimi
Kuvaus
Hinta
 
Чехия
Nazev
Popis
Cena
 
Голландия
Titel
Omschrijving
Prijs
 
Болгария
Заглавието
Описание
Цена
 

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

Тащи-бросай (drag&drop;)

Перетаскивание ползунка подразумевает 3 события: захватить, перетащить и бросить, которые мы сейчас и реализуем:



// Захватить
scroller.onmousedown = drag;

// Перетащить
window.onmousemove = move;

// Бросить
window.onmouseup = drop;

// Эта переменная нам поможет определить:
// Мы просто двигаем мышью по экрану или все-таки перетаскиваем ползунок
var canDrag = false;

// Здесь будем хранить начальный сдвиг ползунка
var shift_x;    

function drag(event)
{
    if (!event)
    {
        // Всем известно, что в Mozilla event передается как параметр
        // А в IE его можно получить вот так:
        event = window.event;
    }
    
    // Отметим, что мы захватили ползунок.
    // Теперь при сдвиге мыши, ползунок должен сдвинуться вместе с ней
    canDrag = true;
    
    // А так же запомним начальный сдвиг
    shift_x = event.clientX - parseInt(scroller.style.left);
    return false;
}

function move(event)
{
    if (!event)
    {
        event = window.event;
    }
    // Здесь мы как раз и проверяем:
    // Сдвигать ли нам ползунок вслед за мышью, или оставить его неподвижным
    if (canDrag)
    {
        setPosition(event.clientX - shift_x);
    }
    return false;
}

function drop()
{
    // Освобождаем ползунок
    canDrag = false; 
}

function setPosition(newPosition)
{
    // Проверим не выйдет ли наш ползунок за границы полосы прокрутки
    // Заметим что предельной точкой справа является разность ширины полосы прокрутки и ширины ползунка
    // Ведь мы устанавливаем позицию его левой границы
    if ( (newPosition <= scrollerTrackWidth - scrollerWidth) && (newPosition >= 0) )
    {
        scroller.style.left = newPosition + "px";
    }
    else if (newPosition > scrollerTrackWidth - scrollerWidth)
    {
        scroller.style.left = scrollerTrackWidth - scrollerWidth + "px";
    }
    else
    {
        scroller.style.left = 0 + "px";
    }
    // Вслед за ползунком передвинем меню:
    menu.style.marginLeft = Math.round( parseInt(scroller.style.left)  * delta * (-1) ) + "px";
    return false;
}

Замечание: как говорилось ранее, в параметр margin-left будем задавать отрицательные значения, для этого мы добавили умножение на -1.

Россия
Название
Описание
Цена
 
Англия
Name
Description
Price
 
Германия
Bezeichnung
Beschreibung
Preis
 
Франция
Nom
Description
Prix
 
Испания
Nombre
Descripcion
Precio
 
Италия
Nome
Descrizione
Prezzo
 
Украина
Назва
Описування
Ціна
 
Португалия
Nome
Descricao
Preco
 
Норвегия
Navn
Beskrivelse
Pris
 
Хорватия
Naziv
Opis
Cijena
 
Финляндия
Nimi
Kuvaus
Hinta
 
Чехия
Nazev
Popis
Cena
 
Голландия
Titel
Omschrijving
Prijs
 
Болгария
Заглавието
Описание
Цена
 

Все вроде хорошо, в Opera 9 все прекрасно работает, но в FF, IE и Safari есть некоторые недочеты, которые вы можете оценить сами. Один из самых нежелательных эффектов я заметил в надстройке MyIE2.0 к обычному IE. В нем каждый раз при перетаскивании позунка открывалась новая вкладка с картинкой ползунка, который мы перетаскивали.

Все нежелательные эффекты мы устраним добавив функцию BlockEvent():


function blockEvent(event)
{
    if (!event)
    {
        event = window.event;
    }
    if(event.stopPropagation) event.stopPropagation();
    else event.cancelBubble = true;
    if(event.preventDefault) event.preventDefault();
    else event.returnValue = false;
}

Она предотвращает «высплытие» события наружу, тем самым подавляет все нежелательные эффекты.
Вызывать ее следует:


function drag(event)
{
    if (!event)
    {
        event = window.event;
    }
    canDrag = true;
    shift_x = event.clientX - parseInt(scroller.style.left);
    // Здесь:
    blockEvent(event);
    return false;
}

function move(event)
{
    if (!event)
    {
        event = window.event;
    }
    if (canDrag)
    {
        setPosition(event.clientX - shift_x);
        // И здесь:
        blockEvent(event);
    }
    return false;
}

Добавив всего одну функцию, мы убили все ненужные эффекты:

Россия
Название
Описание
Цена
 
Англия
Name
Description
Price
 
Германия
Bezeichnung
Beschreibung
Preis
 
Франция
Nom
Description
Prix
 
Испания
Nombre
Descripcion
Precio
 
Италия
Nome
Descrizione
Prezzo
 
Украина
Назва
Описування
Ціна
 
Португалия
Nome
Descricao
Preco
 
Норвегия
Navn
Beskrivelse
Pris
 
Хорватия
Naziv
Opis
Cijena
 
Финляндия
Nimi
Kuvaus
Hinta
 
Чехия
Nazev
Popis
Cena
 
Голландия
Titel
Omschrijving
Prijs
 
Болгария
Заглавието
Описание
Цена
 

Wheel'ы

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

Первой мыслью было использование события onScroll, однако оно существует только в IE и только при наличии на странице активной полосы прокрутки. Событие onMouseWheel же обрабатывается в IE, Opera и Safari, однако в каждом браузере по-своему, но в Mozilla, к сожалению, нет и этого события.

Пришло время разложить все по полочкам и, наконец, подробно разобрать обработку события колеса мыши.

Начнем с инициализации события:


  // Инициализация обработчика колеса мыши, повесим его только на слой content 
  // Для Mozilla необходимо создать EventListener:
  if (get('content').addEventListener)
  {
      get('content').addEventListener('DOMMouseScroll', wheel, false);
  }
  // Для всех остальных браузеров подойдет вот такая инициализация:
  get('content').onmousewheel = wheel;

Поймали событие — полдела позади, осталось разобрать все тонкости его обработки:


function wheel(event)
{
    // Переменная, в которой будем хранить сдвиг
    var wheelDelta = 0;
    
    // Шаг меню при прокрутке
    var step = 300;
    if (!event) 
    {
        event = window.event;
    }
    if (event.wheelDelta) 
    {
        // В IE и Opera при сдвиге колеса на один шаг event.wheelDelta принимает значение 120
        // Значения сдвига в этих двух браузерах совпадают по знаку.
        wheelDelta = event.wheelDelta/120;
    } 
    else if (event.detail) 
    {
        // В Mozilla, значение wheelDelta отличается по знаку от значения в IE.
        // Сдвиг колеса на один шаг соответствует значению 3 параметра event.detail          
        wheelDelta = -event.detail/3;
    }
    // При скроллинге вверх wheelDelta > 0
    // При скролинге вниз - wheelDelta < 0
    if (wheelDelta)
    {
        var currentPosition = parseInt(scroller.style.left);               
        var newPosition = wheeldelta*step + currentPosition;
        setPosition(newPosition); 
    }
    
    // Убиваем событие (чтобы страница не скроллилась)
    if (event.preventDefault)
    {
        event.preventDefault();
    }
    event.returnValue = false;
    blockEvent(event);
}

Россия
Название
Описание
Цена
 
Англия
Name
Description
Price
 
Германия
Bezeichnung
Beschreibung
Preis
 
Франция
Nom
Description
Prix
 
Испания
Nombre
Descripcion
Precio
 
Италия
Nome
Descrizione
Prezzo
 
Украина
Назва
Описування
Ціна
 
Португалия
Nome
Descricao
Preco
 
Норвегия
Navn
Beskrivelse
Pris
 
Хорватия
Naziv
Opis
Cijena
 
Финляндия
Nimi
Kuvaus
Hinta
 
Чехия
Nazev
Popis
Cena
 
Голландия
Titel
Omschrijving
Prijs
 
Болгария
Заглавието
Описание
Цена
 

Так же внеся некоторые изменения в код мы можем организовать вертикальный скроллинг:

Внесем изменения в самое начало скрипта:


// Ширина видимой части объекта (в нашем случае — таблицы)
// Не стал менять название переменной, просто получил в нее значение высоты
var objectWidth = content.offsetHeight; 

// Ширина объекта целиком
// Аналогично
var objectTrackWidth = menu.offsetHeight; 

// Устанавливаем высоту ползунка
scroller.style.height = scrollerWidth + "px";

Внесем изменения в функции drag(), move() и setPosition():


function drag(event)
{
    if (!event)
    {
        // Всем известно, что в Mozilla event передается как параметр
        // А в IE его можно получить вот так:
        event = window.event;
    }
    
    // Отметим, что мы захватили ползунок.
    // Теперь при сдвиге мыши, ползунок должен сдвинуться вместе с ней
    canDrag = true;
    
    // А так же запомним начальный сдвиг
    shift_x = event.clientY - parseInt(scroller.style.top);
    return false;
}

function move(event)
{
    if (!event)
    {
        event = window.event;
    }
    // Здесь мы как раз и проверяем:
    // Сдвигать ли нам ползунок вслед за мышью, или оставить его неподвижным
    if (canDrag)
    {
        setPosition(event.clientY - shift_x);
    }
    return false;
}

function setPosition(newPosition)
{
    // Проверим не выйдет ли наш ползунок за границы полосы прокрутки
    // Заметим что предельной точкой справа является разность ширины полосы прокрутки и ширины ползунка
    // Ведь мы устанавливаем позицию его левой границы
    if ( (newPosition <= scrollerTrackWidth - scrollerWidth) && (newPosition >= 0) )
    {
        scroller.style.top = newPosition + "px";
    }
    else if (newPosition > scrollerTrackWidth - scrollerWidth)
    {
        scroller.style.top = scrollerTrackWidth - scrollerWidth + "px";
    }
    else
    {
        scroller.style.top = 0 + "px";
    }
    // Вслед за ползунком передвинем меню:
    menu.style.marginTop = Math.round( parseInt(scroller.style.top)  * delta * (-1) ) + "px";
    return false;
}

Россия
Название
Описание
Цена
 
Англия
Name
Description
Price
 
Германия
Bezeichnung
Beschreibung
Preis
 
Франция
Nom
Description
Prix
 
Испания
Nombre
Descripcion
Precio
 
Италия
Nome
Descrizione
Prezzo
 
Украина
Назва
Описування
Ціна
 
Португалия
Nome
Descricao
Preco
 
Норвегия
Navn
Beskrivelse
Pris
 
Хорватия
Naziv
Opis
Cijena
 
Финляндия
Nimi
Kuvaus
Hinta
 
Чехия
Nazev
Popis
Cena
 
Голландия
Titel
Omschrijving
Prijs
 
Болгария
Заглавието
Описание
Цена
 
Глеб Арестов
26 августа
Стрелочки на самой кнопке дают ощущение, что их можно отдельно нажать и всё подвинется только на пару пикселов..
Всё таки привычно, когда стрелочки у начала и конца документа, а на ползунке ничего нет
Никита Козин
26 августа
Здорово, жаль только, что прокрутка колёсиком не плавная. Можно добавить setInterval и крутить мягко.

P.S. В самом первом куске кода потерялся открывающий тег style.
Фитискин Александр
26 августа
Ничто не мешает добавить эту функцию в данный скрипт, далее можно все эти функции объединить в объект и использовать, но это будет в качестве домашнего задания :)
Фитискин Александр
26 августа
Глеб, стрелочки на ползунке - это решение дизайнеров, которое дает понять, что ползунок передвигается, и ничего более того.
Глеб Арестов
26 августа
То, что это решение дизайнеров не говорит что это правильное решение; просто посмотрите как сделаны скроллбары в разных операционных системах.

я не говорю о том что следует повторять за кем-то, я пытаюсь обратить взор на то как пользователю привычнее и удобнее
GreLI
26 августа
Скролл работает, но на мышке есть ещё так называемый тилтинг, когда колесо можно отклонять влево-вправо, и он не работает :(. Нелогично на горизонтальной прокрутке.
Марк
26 августа
Занятно, понравилось. Спасибо вам.
Дима Фитискин
27 августа
Глеб, мы всегда за простоту и удобство. Но давайте вернемся к сути поста - мы же обсуждаем JavaScript реализацию. Картинки то можно изменить при использовании в другом проекте.
Никита Козин
27 августа
Да, кстати, если бы ещё при нажатии на колёсико и смещении курсора можно было бы скроллить — было бы вообще круто. Не знаю, правда, на сколько это реализуемо, но третья кнопка мыши вроде бы обрабатывается.
BOLK
27 августа
В FF пример прекрасно прокручивается колесом.
Артур
27 августа
Потрясающе! Похвала да и только! Ценю вашу работу.
Еще добавить бы мягкости при прокрутке, + дополнительно решения этого всего на jQuery и смело давать на всеобщее пользование.
Guest
27 августа
Двойной щелчок мышой по полосе прокрутки (не по ползунку) селектит ползунок. Мелочь, но некрасиво.
Глеб Арестов
27 августа
реализация отличная!
Tony
27 августа
В коде есть одна небольшая недоговорка. Значение wheelDelta (которое вы вычисляете) на один _условный поворот колеса мыши_ (в винде это называется "поворот колесика на один щелчок") зависит от предпочтениий пользователя. Например, в настройках колеса мыши в Windows XP по умолчанию стоит "перемещать на 3 строчки". Отсюда и значение 3, которое вы захардкодили для Firefox. В IE/Opera (Safari?), возможно, существует какой-то коэффициент к этому значению (это объясняет хардкодинг значения "120").

Таким образом теоретически вы никогда не можете сказать, сколько условных крутков колесиком сделал юзер, так как его предпочтения (а соотв. поле объекта event detail в Firefox) могут отличаться.

Хотя когда я поменял свои предпочтения колеса мыши и поскроллировал ваше меню, то оно сдвигалось на такой же шаг. Это мне показалось странным.

Кстати, интересно поисследовать поведение при скроллировании трекпадом.
Фитискин Александр
28 августа
Хотя когда я поменял свои предпочтения колеса мыши и поскроллировал ваше меню, то оно сдвигалось на такой же шаг. Это мне показалось странным.

Tony, выходит, что ваши предположения относительно связи значения event.detail (event.wheelDelta) и значения в настройках колеса мыши в ОС ошибочны.
Tony
28 августа
Нет, не ошибочны, я проверил прежде чем писать (не предположения, а утверждение). Более того, у меня есть Firebug ). Попробуйте сами поменять предпочтения и посмотреть значение e.detail на одном прокручивании колеса мыши.
Фитискин Александр
28 августа
Tony, sorry, да действительно вы правы, спасибо за замечания, учел в посте и кое что подправил.
Дима Фитискин
28 августа
Tony, что касается скроллирования трекпадом - у меня на макбуке отлично прокручивается двумя пальцами. Полный контроль над сдвигом в оба направления. Даже удобнее чем колесом на мой взгляд.
EasyRider
31 августа
Спасибо! Очень красиво и очень вовремя!
Павел
31 августа
Спасибо, познавательно. сам когдато столкнулся с такой надобностью
забил на джаваскрипт использовал флэш и весит немного если чистым ас кодом.
Максим
30 сентября
Классно!
Вы настоящий профессионал своего дела. Перенес себе, все работает во всех браузерах. Подумываю, как теперь расширить jQuery, добавить туда еще событие wheel...
masic
28 октября
вот что любопытно:
скопировал ваш код, сделал вертикальную прокрутку ... наотрез отказалась работать в осле, пока не поправил:

// Перетащить
document.body.onmousemove = move;

// Бросить
document.body.onmouseup = drop;
Александр
11 ноября
Спасибо огромное за скрипт.
Сейчас срочно понадобилась подобная штука, а времени писать самому нету. Выручили.
Во всех основных браузерах работает отлично.
Юра
11 ноября
Перерыл весь гугл.И о чудо!!! Зашел сюда.То что нужно!только переделаю вечером в вертикальную прокрутку и усё! Пасибо баа-а-а-а-а-альшое :)
vitaliy
12 ноября
Здравствуйте, помогите плз.
хочу это чудо прикрутить.
нужно прокручивать div вертикально... что не получается(((
Фитискин Александр
12 ноября
vitaliy, никакой сложности нет.
Необходимо изменить все параметры, связанные с шириной, на аналогичные параметры связанные с высотой (например offsetWidth -> offsetHeight), а так же все параметры сдвига слева на сдвиг сверху (style.left -> style.top и style.marginLeft -> style.marginTop).
Главное не забыть изменить в верстке стартовое положение:
Было:
<img id="scroller" style="left: 0px;" alt="" src="scroller.gif" />
и
<table style="margin-left: 0px;" id="object">

Станет:
<img id="scroller" style="top: 0px;" alt="" src="scroller.gif" />
и
<table style="margin-top: 0px;" id="object">

Если все же возникнут трудности, могу выложить готовый скрипт для вертикальной прокрутки.
Alexiy
14 ноября
У меня возникли... не смог переделать в вертикальный, прошу помочь!
Фитискин Александр
17 ноября
Дополнил пост описанием создания вертикальной прокурутки, надеюсь будет полезно
Wowa Savin
28 ноября
Тормозит немного, добавил бы что бы при прогрутки колёсиком, если прокручивать некуда, событие прокрутки передавалось бы на более верхний уровень
Георгий Виноградов
3 декабря
Есть глюк: если при вертикальной прокрутке дойти до самого низа, третий с конца флаг показывается полностью, чего быть не должно (браузер - Epiphany, про другие не знаю)
sergy
23 декабря
Подскажите пожалуйста, как разместить 2 горизонтальных скрола на 1 странице?
Фитискин Александр
23 декабря
Sergy, для этого необходимо обернуть вышеописанное в класс, и создать 2 экземпляра данного класса.
sergy
23 декабря
Александр, что то я ничего толком не понял, покажите на простом примере?
MrAngel
26 января
Отличная статья. Для себя содрал прокрутку :)

Кстати у меня другое предложение. Весь контент посадить в DIV где overflow: hidden;. И крутить при помощи contentDIVObject.scrollLeft. Для вертикальной прокрутки соответственно .scrollTop.
На сколько я знаю это естественная прокрутка в диве, но только через Javascript.
Работает в IE и Firefox - в других не проверял.
Kosten
27 января
Очень полезный пример работы с колесом мыши. Добавил в избранное. Спасибо.
Фитискин Александр
2 Февраля
Sergy, самый простой пример: поглядеть как подключены скроллы на данной странице (их здесь несколько). Если посмотрите скрипт в файле drag_menu2.js подключенный на данной странице, то увидете, что в нем описано 3 класса: горизонтальный скролл [Scroll], вертикальный скролл [VerticalScroll], и горизонтальный скролл с неполным функционалом [ScrollWithBugs] (для демонстрации). Подключение производится в функции init. Каждую строчку кода здесь описать не могу, займет много места и времени, я думаю, что вы сможете разобраться.
Дмитрий
2 марта
В коде вступления ошибка: 2 id с одинаковым именем (content)
Алексей
5 марта
Шикарный скрипт. Но хотелосьбы узнать, как довести его до ума, добавив кнопки прокрутки туда - обратно, и центровку на нужной фотографиию т.е. как сделано на яндекс картинках, когда фото "еще с сайта" прокручиваються в правом вертикальном блоке.
http://images.yandex.ru/yandsearch?p=11&ed;=1&text;=%D0%B2%D0%B0%D0%B7%202110&spsite;=car-exotic.com&img;_url=avtovaz.narod.ru%2F2110%2Fpictures%2Fdvig10-1.jpe&rpt;=simage
блок Еще на сайте 223.
Евгений
16 марта
Кстати, а как сделать что бы при выделении в данном блоке, он тоже прокручивался? Т.е. при выделении в обычном диве при подведении курсора к низу он прокручивается (при выделении)
JoHn
5 апреля
В Internet Exporer 5.5 не работает
Василий
27 апреля
В топку Internet Exporer 5.5
rusart
6 мая
Респект, товарищ! Долго копал справочники по JS чтобы найти нормальный вариант обработки колеса, а тут прямо все по полочкам разложено.
Фитискин Александр
12 мая
Алексей, это уже материал для новой статьи :)

Евгений, необходимо на событие onmousedown у всего блока (id="content") повесить обработчик drag (ведь выделение по сути не отличается ничем от перетаскивания ползунка)

JoHn, на дворе 21 век, IE 5.5 канул в лету.
BaN
28 мая
У меня ошибка вылазит если блок не заполнен контентом превышающим этот блок. Как это исправить?
Спасибо!
Фитискин Александр
28 мая
Ban, требуется добавить проверку после задания ширина ползунка. Если контента меньше, чем ширина блока, то scrollerWidth будет больше чем scrollerTrackWidth. В таком случае следует не включать обработчики событий, и ошибок быть не должно.
Василий
10 июня
Спасибо!
Пригодилось :-)
Ruman
1 июля
Клевый скрипт! какраз его искал. Спасибо.

P/s кому нужна простота в создании скроллбаров юзайте плагин jScrollPane библиотеки jQuery
magelan
13 июля
Джиквери - не панацея, тяжелая и никому ненужная библиотека, которая может оправдать себя только на интранет решениях с тоннами скриптов.

Для тех, кто готов бороться руками, замечу, что такой веселый браузер Chrome посылает событие колеса мыши чаще, чем остальные браузеры, навскидку, в 3 раза. Дополнение jScrollHorizontalPane к Джиквери, кстати, это не учитывает.
Валерий
9 августа
В обычных скролах есть такая особенность что когда скрол доходит до своего придела(нижней или верхней) дальше начинает прокручиватся сама страница. В приведенном скрипте как и во всех которые я видел и jquery в том числе, это не учтено. Очень не удобно искать на странице "живое" место где бы можно было ее полностью прокрутить. Не подскажите как можно решить эту проблему?
Фитискин Александр
12 августа
Валерий, если я вас правильно понял, то вы имеете ввиду, что нужно не блокировать событие, если скроллить дальше некуда. Эта проблема решается добавлением условия для вызова функции blockEvent (проверить а есть ли куда крутить). Думаю с этой задачей вы легко справитесь и сделаете скрипт более приятным.
Valintin
15 августа
Почему прокрутка происходит только строк таблицы? если взять много текста и засунуть в одну таблицу и попытаться промотать что мы сразу попадем на конец таблицы тоесть перемотка все таблицы не текста
Фитискин Александр
17 августа
Valintin, на самом деле можно задать прокрутку как жестко в пикселях (к примеру по 100px), так и на любую другую величину (к примеру высоту строки таблицы). Если внимательнее просмотрите скрипт, то найдете места, в которых эти величины сдвига можно задать
Valintin
18 августа
Спасибо, будем искать )
Valintin
29 августа
пипец короче не знаю я как его заставить работать тот пример что у вас на сайте у меня не работает я разобрал всю эту строницу целиком но по сторочно всеровно не мотает!!!
Фитискин Александр
31 августа
Valintin, на этой странице подключен сценарий drag_menu2.js
В нем описаны 3 класса: Scroll - горизонтальный, ScrollWithBugs - горизонтальный показательный с ошибками и VerticalScroll - вертикальный.

В каждом из них есть метод setStep, который задает сдвиг. Во всех 3х он описан примерно одинаково:

this.step = Math.round(this.menu.getElementsByTagName("td")['0'].offsetWidth * this.scrollerTrackWidth / this.menuTrackWidth);

берется первая ячейка таблицы, определяется ее ширина, и в процентном соотношении к общему размеру таблицы и размеру блока задается сдвиг. В вашем случае сдвиг нужно задать безо всяких отношений ровно на размер ячейки.
У меня к сожалению нет времени детально разобраться в каком месте у вас проблема вот так на слух, пришлите мне на почту пример скрипта, я попробую вам помочь: afitiskin[at]dominion.ru
Лёша
17 октября
Я реально был на грани срыва, пытаясь завернуть всё это дело в класс. Уже был готов мылить верёвку но вдруг нашел на одном форуме что ЗЫС в джаваскрипте НЕМНОЖКО не то что в других ОО языках... и что надо пользоваться ЗАМЫКАНИЕМ )))) В целом очень помогла ваша статья ;) надеюсь дальше у меня с джавоскриптом всё сложится приятнее. Огромное вам спасибо ;)
Leestarch Happer
20 октября
ужас! скрипт клевый, я долго искал чтонить подобное, но воспользоваться им с этой страницы нереально. перелопатить кучу тупого кода с элементами которые рушат представления о семантике, валидности и ясности кода... что мешает просто положить ниже код полностью? зачем устраивать такой замес.

конечно огромное спасибо за хорошую статью, но воспользоваться решением проблемы получается далеко не сразу...
Izgoj
23 октября
Александр!
Я абсолютный новичок в программировании. Используя ваш скрипт разобраться не смог. Прошу, просто потому, что очень надо) Если вам не трудно, подскажите каким-либо образом:

как в основном окне убрать полосу прокрутки, но оставить функцию прокрутки колесиком мышки ?
Павел
28 октября
Присоединяюсь к народу выше, выполнял поочереди, как написано, ничего не вышло. Выложите полный скрипт с кодом.
Николай
30 октября
В украинском языке слова - "Описування" не существует но есть "Опис"
DarkedAngel
3 ноября
Дибилизм да и только... Какие-то таблицы, какая-то куча непонятных объектов... Зачем??? Скрипт изначально корявый... Протрахался половину дня и нихера не получилось... Посмотри там, посмотри здесь... Если выкладываешь скрипт, то выкладывай также в виде файлов, а не кучи текста, и непонятного чего зачем...
Фитискин Александр
3 ноября
Leestarch Happer, воспользоваться скриптом со страницы возможно, ведь на странице то он работает, не правда ли? Ошибки в коде есть, но как говорили ребята выше — исправление этих ошибок только помогает понять суть работы. Если вам нужен готовый скрипт, тогда возьмите тот, который подключен на этой странице для примера: http://noinimod.ru/data/weblog/post/52/scripts/drag_menu.js

Izgoj, убрать полосу можно с помощью overflow: hidden например у тэга body. В этом случае все что будет за пределами окна не будет доступно, однако с помощью скрипта можно будет управлять прокруткой. В пример могу привести зуммер на этой странице: http://www.vtm-dorproekt.ru/portfolio/pgroup-10/project-31/photo/?photo=1. Там картинку можно передвигать мышкой, а на колесо я повесил событие изменения масштаба (как на картах Яндекс и Google). Вы же можете на колесо повесить функцию прокрутки... Однако это задание не для новичков, вам все же придется покопаться :)

Павел, ссылку на скрипт я дал выше, но продублирую ее еще разок: js — http://noinimod.ru/data/weblog/post/52/scripts/drag_menu.js, html-код — http://noinimod.ru/data/weblog/post/52/annot.html, ccs — внутри тэга style в html

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

DarkedAngel, я не задавался целью выложить готовый скрипт, я задался целью рассказать о том, как перехватить событие колеса мыши. И с этой задачей я справился, судя по комментариям выше. Если вам интересен готовый скрипт, используйте jQuery, если же вы решили понять как это работает, то приложите немного усилий, и у вас получится. Ничего сложного в этом нет.

PS. Статье уже больше года, и, признаюсь честно, это вообще один из первых моих JS скриптов (а точнее — первый :) ). Код корявый, некрасивый и несемантичный. Возможно в ближайшее время я найду пару часов чтобы привести его в тонус. Если у кого есть какие вопросы: пишите письма на afitiskin[at]dominion.ru.
DarkedAngel
4 ноября
http://maverickd.sytes.net/scroll/ здесь результат моих трудов и бессонной сегоднешней ночи... скачать можно http://maverickd.sytes.net/scroll.rar

Скрипт полностью готов к использованию, пример в index.html и нужно подогнать под ваши стили.

Что добавлено: проверка наличия элемента div id="scroll". В случае того если его нет, то не выводится ошибка... Добавлена проверка нажатия кнопки мыши при перетаскивании скрола и ограничена область скрола по горизонтали в 20 пикселей в каждую сторону.
Druid
13 ноября
Если зажать среднюю клавишу мыши (IE6), протащить влево или вправо, затем вниз, после этого отпустить, то drag залипает.
Как влияет такая обработка на таймеры - по-прежнему не дает им отрабатывать?
Да, красиво, за код - респект, только мне он не поможет.
Druid
13 ноября
Спасибо DarkedAngel'у.
Serega
12 декабря
Доброго времени суток.. За скрипт огромное спасибо!!!!! Шикарно сделано, я в восторге, давно искал подобное! Я в яве не силен, и столкнулся с такой проблемой, здесь вы забираете id элементов, а как сделать чтобы забирал классы, просто прокруток у меня три... Заранее спасибо и извините за ламерский вопрос. Искал в инете нашел document.getElementsByClassName("class"); но применить так и получилось :(
Фитискин Александр
13 декабря
Druid, попробую поэкспериментировать, и если найду решение, напишу об этом, спасибо за тему для размышлений

Serega, я обычно поиск по названию класса осуществляю в 2 этапа:
1. Выбираю все элементы на странице (или в определенном блоке)
var elems = document.getElementsByTagName('*');
2. Листаю их и ищу совпадения на название класса вот таким образом:

for (var i = 0; i < elems.length; i++)
{
if (elems[i].className.search('class') > -1)
{
// этот элемент нам нужен
}
}
Mарина
13 января
Спасибо за тему! очень интересная!

Мне вот поставили задачу нужно для <textarea> сделать скин.. т.е. скроллинг из картинок собрать. Перерыла весь инет и не могу найти похожего скриптика.

Вот сделала скин прокрутки для дива на JScrollPanel
http://yurist.pl.ua/jscroll/
в верху обычный див, а ниже (хотела схитрить) поместила на див большой по высоте <textarea>, но работает оно не совсем корректно.. :(

Подскажите пожалуйста, может кто-то где-то видел уже такое?!
Mарина
14 января
А не могли бы вы еще доработать ваш скриптик..
если в контент, который скроллится по горизонтали, я ставлю курсор и стрелкой влево или вправо его перемещаю, курсор уходит за пределы видимости, а контент не скроллится за ним.
Это актуально в том случае если я диву ставлю contentEditable="true" и использую его как TextArea.
спасибо!
dimonlimon
3 Февраля
Выложите. пожалуйста, вертикальный скроллинг. Что-то не получается сварганить с ваших подсказок!
Фитискин Александр
10 Февраля
Mарина, если задача еще актуальна, напишите мне письмо на afitiskin[at]dominion.ru, и я попробую помочь вам решить вашу задачу)

dimonlimon, по просьбам многих в ближайшее время я немного перепишу свой скрипт, сделаю его менее зависимым от верстки и гибко-настриваемым, скоро выложу, ждите! :)
Croaton
12 марта
БОЛЬШОЕ спасибо за скрипт!!! Господи, благослови интернет...:-)