Pull to refresh

Вертикальный скроллинг страницы средствами jQuery и кроссбраузерность

jQuery *
Sandbox
Далее представлена кроссбраузерная реализация скроллинга страницы средствами jQuery.

Как всё начиналось


В последнее время на многих сайтах можно увидеть в той или иной вариации кнопки для прокручивания страницы вверх или вниз. Смотрится это довольно мило, удобно в использовании, и просто в реализации. Столкнувшись с проблемой прокрутки объёмного контента в очередном разрабатываемом проекте, решил реализовать подобную функциональность.
Задача была следующая: сделать две кнопки. По нажатию на одну осуществлять прокрутку страницы в самое начало, по нажатию на другую – в самый конец. Также было решено дополнительно реализовать возможности чисто визуального характера, типа анимации, исчезновения кнопок и прочее, здесь я останавливаться на этом не буду, так как тема это – кросбраузерность. Собственно это стало основной проблемой в процессе написания кода.
Нарисовав симпатичные кнопочки, прикрутив анимацию и исчезновение кнопок, и реализовав собственно саму прокрутку, я обнаружил, что в разных браузерах наблюдаются проблемы со скроллингом. Раздосадованный (и почему-то ни капли не удивленный…) этим фактом (а также тем, что не получится уйти с работы пораньше), я решил ознакомиться с аналогичными реализациями в Интернете. Просмотрев несколько примеров, точно также, не воспринимающих какой-либо браузер, а подчас и работающих только в одном определённом, было решено заняться прототипированием, экспериментированием, решением задачи методом тыка (нужное подчеркнуть).
Далее я приведу кроссбраузерный вариант реализации простенького скроллинга страницы вверх/вниз, с пояснениями, где и что может пойти не так и в каком браузере (ни в коем случае не претендую на оригинальность решения, это просто желание поделиться собственным опытом, и сэкономить людям время при решении аналогичных задач). Ах да, забыл оговориться, подавляющая часть кода написана на jQuery.

Подготавливаем основу


Итак, что мы будем делать. Будем делать две кнопки «вверх» и «вниз», по нажатию на которые осуществляется плавный скроллинг страницы в самое начало и в самый конец, соответственно. При этом реализация должна одинаково работать во всех современных браузерах.
Задача ясна, приступим к реализации. Для начала, напишем самое простое, а именно HTML код кнопок и соответствующие им CSS стили.

HTML код кнопок:

<div id="up"><p class="pPageScroll">Вверх</p></div>
<div id="down"><p class="pPageScroll">Вниз</p></div>


CSS стили:

#up
{
width:60px;
height:60px;
position:fixed;
bottom:50px;
left:20px;
background-color:#000000;
border-radius:30px;
}
#down
{
width:60px;
height:60px;
position:fixed;
bottom:50px;
left:90px;
background-color:#000000;
border-radius:30px;
}
.pPageScroll
{
color:#FFFFFF;
font:bold 12pt 'Comic Sans MS';
text-align:center;
}


В итоге мы имеем два круга с надписями «Вверх» и «Вниз» в левом нижнем углу браузера.

Проблемы начинаются


Теперь начинается самое интересное – JavaScript, а точнее jQuery. Как известно, для организации скроллинга выполняются манипуляции над свойствами scrollTop и scrollLeft. В jQuery эти манипуляции осуществляются при помощи методов .scrollTop() и .scrollLeft() соответственно. Нас интересует только .scrollTop.
Первый, самый простой вариант скроллинга выглядел следующим образом:

//Обработка нажатия на кнопку "Вверх"
$("#up").click(function(){
//Необходимо прокрутить в начало страницы
$("body").animate({"scrollTop":0},"slow");
});

//Обработка нажатия на кнопку "Вниз"
$("#down").click(function(){
//Необходимо прокрутить в конец страницы
var height=$("body").height();
$("body").animate({"scrollTop":height},”slow”);
});


Всё, ну очень просто и незатейливо. Но, вот незадача, если в Chrom’е всё было довольно безоблачно и симпатично, в Oper’е тоже довольно сносно (прокрутка вверх осуществлялась мгновенно), то «ВредныйЛис» скролиться отказывался напрочь. Не долго думая, заменив в строчке: $(«body»).animate «body» на «html», я изменил ситуации кардинально: FireFox заработал, Opera перестал рывком прокручивать вверх и стал делать это плавно, но теперь уже Chrome перестал реагировать на манипуляции с кнопками. Из приведённых выше мытарств последовал следующий вариант перевариваемый всеми браузерами: $(«html,body»).animate… Других приемлемых способов осуществлять скроллинг, работающих во всех браузерах найдено не было.

Добавим рюшечек и бантиков


С самой простой частью разобрались. Базовый функционал получен, теперь можно придумать, что-нибудь поинтереснее. Первое же, что бросается в глаза, так это скорость скроллинга. При наличии сколь бы то ни было насыщенного контента, использование скроллинга становится настоящим тестом на склонность к эпилепсии. Поэтому, хочется, чтобы скроллинг был более плавным. Решение в лоб, задать определённую константу времени за которое должен осуществляться скроллинг. Очевидный плюс: элементарность решения. Не менее очевидный минус: никак не учитывается объём контента. Разумное решение: вычислять время выполнения скроллинга в зависимости от размера контента. Приступим.
В код обоих кнопок нужно дописать, вычисление текущей позиции. Для этого как раз и используется jQuery() метод .scrollTop().
Здесь, появляются уже известные проблемы: $(«body»).scrollTop() работает только в Chrome, $(«html»).scrollTop() не работает в Chrome. Что, вообще говоря, удивляет, так как получается, что конструкцией $(«body»).animate({«scrollTop»:height},”slow”) в Opera мы можем скролить body, а при получении, свойство scrollTop тега body равно нулю, что, судя из описания element. scrollTop справедливо для элементов, которые скролить нельзя.
Вариант $(«body,html»).scrollTop() по понятным причинам нам не подходит. Ищем альтернативы. Оказывается, текущую позицию можно получить из объектов window и document, так чтобы это устраивало все браузеры. Думаю, следует упомянуть, что использование их для анимации (например вот так: $(document).animate.), ни к чему хорошему не приводит.
Итак, за рабочий вариант выяснения текущей позиции примем: $(document).scrollTop();
Теперь задумаемся над тем, как мы будем вычислять время. Вообще говоря решение тривиальное и известно каждому: время = путь/скорость. Для определения пути, нам как раз и нужна текущая позиция. Также, нужны координаты точки назначения. С кнопкой «Вверх» всё просто, координата точки назначения по вертикальной оси равна нулю, значит, путь равен текущему положению. Для кнопки «Вниз» всё немного сложнее, нам нужно получить «высоту» документа. Уже предвкушаем проблемы, да? Но нет, тут всё оказывается очень просто. Вполне подходящую высоту можно получить используя в качестве селектора «body», «html» или document.
Так. У нас есть путь, теперь нужна скорость. Здесь уже всё зависит лично от вас. Путём визуальных прикидок, мне показалась комфортной скорость 1.73 (цифра не имеет под собой никакого, сколь бы то ни было серьёзного обоснования и прикидывалась на глаз).

Итоговый вариант


Таким образом, рабочий код выглядит следующим образом:

$(document).ready(function(){
//Обработка нажатия на кнопку "Вверх"
$("#up").click(function(){
//Необходимо прокрутить в начало страницы
var curPos=$(document).scrollTop();
var scrollTime=curPos/1.73;
$("body,html").animate({"scrollTop":0},scrollTime);
});

//Обработка нажатия на кнопку "Вниз"
$("#down").click(function(){
//Необходимо прокрутить в конец страницы
var curPos=$(document).scrollTop();
var height=$("body").height();
var scrollTime=(height-curPos)/1.73;
$("body,html").animate({"scrollTop":height},scrollTime);
});
});


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

Резюме


В итоге мы получили очень простую реализацию скроллинга страницы, которая работает в любом современном браузере.
Испытания проводились для DOCTYPE: XHTML 1.0 Strict в браузерах Chrome 10, Opera 10, Opera 11, Firefox 4, Internet Explorer 8, Internet Explorer 9.

Некоторые проблемы:
  • border-radius как известно в IE8 не работает, но кроссбраузерность вёрстки это не тема данного топика.
  • В Opera 10 инструкция: $(«body,html»).animate({«scrollTop»:0},scrollTime); приводит к моментальному переходу в начало страницы. Эта проблема исчезает с переходом на Opera 11.


UPD: Поправлен итоговый пример.
Tags:
Hubs:
Total votes 21: ↑12 and ↓9 +3
Views 119K
Comments Comments 6