- How to animate scroll in jQuery
- Simple example: scroll to the top of the page
- Scroll to the top of an element
- Scroll to the bottom of the page
- Normalizing the scroll rate
- Вертикальный скроллинг страницы средствами jQuery и кроссбраузерность
- Как всё начиналось
- Подготавливаем основу
- Проблемы начинаются
- Добавим рюшечек и бантиков
- Итоговый вариант
- Резюме
How to animate scroll in jQuery
In this guide, I’ll provide sample code for animating scroll in jQuery, and for those looking for more I’ll break down each component.
Simple example: scroll to the top of the page
Assume we have a simple button at the bottom of our page that when clicked scrolls the user to the top of the page.
Note that the first line, $(function() is shorthand for $(document).ready(function() . This simply means we are passing a callback function to the document ready event. It’s necessary to do this when our code is expecting DOM elements to exist. Next we are creating a click event handler for our button, $(«#top»).on(‘click’, function() . First we specify which element we are listening to, which in our case is #top. The on(‘click’ is very readable — simple means when the user clicks on the #top element. And as before, the anonymous function we create is being passing in as a callback function. So whenever the user clicks on the #top element this function will get fired. Now for the animation. First it should be noted that we are targeting both HTML and BODY for browser compatibility. Some browsers scroll by settings scrollTop on BODY and other on HTML. No, I don’t know which ones, and it will probably be unnecessary soon if it isn’t already. jQuery provides an animate function that takes a dictionary of CSS properties and values as the first parameter, and an integer representing the animation duration in milliseconds as the second parameter. In our case we are passing in only one css property: scrollTop. And since we are scrolling to the top, we’ll set scrollTop to 0. Then as the second parameter we’re setting the duration to 1000 milliseconds or if you’re really good at math: 1 second. This should give us plenty of time to watch our animation.
Keep in mind that if you’re going to use this code, you’ll need to add enough content to your page to enable scrolling otherwise the button will do nothing!
Scroll to the top of an element
Now suppose we have an element on the page and we want to scroll to the top of it.
var position = $("#image").offset().top;
jQuery’s offset() function returns an object containing properties top and left. We’re only interested in top because we want to scroll to the top of this element. So using what we’ve already learned about scroll, we can use our new position as the value of scrollTop:
Scroll to the bottom of the page
Since scrollTop is the position on the page that should land at the top of the window, scrolling to the bottom of the page requires a little bit of math. The position we want to know is the document height — window height. document height will give us the height of the entire web page, while window height just gives us the height of the scrollable area.
var bottom = $(document).height() - $(window).height();
Normalizing the scroll rate
If you’ve been experimenting with animating scroll, you’ve probably noticed that if the scroll distance is small it scrolls very slowly and if the scroll distance is large is scrolls more quickly. This is because we are specifying a duration for the animation, and it doesn’t care about distance. In most cases, when your scroll distance can vary you’ll want to normalize the scroll rate. So instead of always passing in 1000 for the duration, we want to take our scroll distance into account. First, we have to decide the rate we want to scroll. Let’s pick something easy — 1000px/500ms or 1000px/0.5s. We need to write a function that takes the target scroll position, that is the position we are scrolling to, and returns the new duration in milliseconds.
function getDuration(target) < var currentTop = $(window).scrollTop(), rate = 0.5, // 1000px/500ms distance; distance = Math.abs(currentTop - target); return distance * rate; >
First we set our variables. We need to get our current scrollTop position and store that value as currentTop. This allows us to properly calculate the distance between our current position and the target position. Then we specify our rate, which in our case is 0.5 or 1000px/500ms. Finally, we declare our distance variable which will be set soon. Calculating the distance is as simple as subtracting the target from the currentTop. We need to take the absolute value of the result to ensure this works for both directions. Finally we return the new distance we calculated multiplied by the rate. Now let’s put our function to use in an example that scrolls us to the bottom of the page at our newly calculated rate.
As you can see the only changes are calling the getDuration function and using the newly calculated duration as the second parameter of the animate function. This method is beneficial because if all of your scrolls will animate at the same speed. If you want to change the speed, all you have to do is modify the rate in our getDuration function. Adjusting the rate to 0.2 will make it go much faster, whereas changing it to 1.5 will slow it down significantly.
Вертикальный скроллинг страницы средствами jQuery и кроссбраузерность
Далее представлена кроссбраузерная реализация скроллинга страницы средствами jQuery.
Как всё начиналось
В последнее время на многих сайтах можно увидеть в той или иной вариации кнопки для прокручивания страницы вверх или вниз. Смотрится это довольно мило, удобно в использовании, и просто в реализации. Столкнувшись с проблемой прокрутки объёмного контента в очередном разрабатываемом проекте, решил реализовать подобную функциональность.
Задача была следующая: сделать две кнопки. По нажатию на одну осуществлять прокрутку страницы в самое начало, по нажатию на другую – в самый конец. Также было решено дополнительно реализовать возможности чисто визуального характера, типа анимации, исчезновения кнопок и прочее, здесь я останавливаться на этом не буду, так как тема это – кросбраузерность. Собственно это стало основной проблемой в процессе написания кода.
Нарисовав симпатичные кнопочки, прикрутив анимацию и исчезновение кнопок, и реализовав собственно саму прокрутку, я обнаружил, что в разных браузерах наблюдаются проблемы со скроллингом. Раздосадованный (и почему-то ни капли не удивленный…) этим фактом (а также тем, что не получится уйти с работы пораньше), я решил ознакомиться с аналогичными реализациями в Интернете. Просмотрев несколько примеров, точно также, не воспринимающих какой-либо браузер, а подчас и работающих только в одном определённом, было решено заняться прототипированием, экспериментированием, решением задачи методом тыка (нужное подчеркнуть).
Далее я приведу кроссбраузерный вариант реализации простенького скроллинга страницы вверх/вниз, с пояснениями, где и что может пойти не так и в каком браузере (ни в коем случае не претендую на оригинальность решения, это просто желание поделиться собственным опытом, и сэкономить людям время при решении аналогичных задач). Ах да, забыл оговориться, подавляющая часть кода написана на jQuery.
Подготавливаем основу
Итак, что мы будем делать. Будем делать две кнопки «вверх» и «вниз», по нажатию на которые осуществляется плавный скроллинг страницы в самое начало и в самый конец, соответственно. При этом реализация должна одинаково работать во всех современных браузерах.
Задача ясна, приступим к реализации. Для начала, напишем самое простое, а именно HTML код кнопок и соответствующие им 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(,»slow»);
>);
//Обработка нажатия на кнопку «Вниз»
$(«#down»).click(function() //Необходимо прокрутить в конец страницы
var height=$(«body»).height();
$(«body»).animate(,”slow”);
>);
Всё, ну очень просто и незатейливо. Но, вот незадача, если в Chrom’е всё было довольно безоблачно и симпатично, в Oper’е тоже довольно сносно (прокрутка вверх осуществлялась мгновенно), то «ВредныйЛис» скролиться отказывался напрочь. Не долго думая, заменив в строчке: $(«body»).animate «body» на «html», я изменил ситуации кардинально: FireFox заработал, Opera перестал рывком прокручивать вверх и стал делать это плавно, но теперь уже Chrome перестал реагировать на манипуляции с кнопками. Из приведённых выше мытарств последовал следующий вариант перевариваемый всеми браузерами: $(«html,body»).animate… Других приемлемых способов осуществлять скроллинг, работающих во всех браузерах найдено не было.
Добавим рюшечек и бантиков
С самой простой частью разобрались. Базовый функционал получен, теперь можно придумать, что-нибудь поинтереснее. Первое же, что бросается в глаза, так это скорость скроллинга. При наличии сколь бы то ни было насыщенного контента, использование скроллинга становится настоящим тестом на склонность к эпилепсии. Поэтому, хочется, чтобы скроллинг был более плавным. Решение в лоб, задать определённую константу времени за которое должен осуществляться скроллинг. Очевидный плюс: элементарность решения. Не менее очевидный минус: никак не учитывается объём контента. Разумное решение: вычислять время выполнения скроллинга в зависимости от размера контента. Приступим.
В код обоих кнопок нужно дописать, вычисление текущей позиции. Для этого как раз и используется jQuery() метод .scrollTop().
Здесь, появляются уже известные проблемы: $(«body»).scrollTop() работает только в Chrome, $(«html»).scrollTop() не работает в Chrome. Что, вообще говоря, удивляет, так как получается, что конструкцией $(«body»).animate(,”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(,scrollTime);
>);
//Обработка нажатия на кнопку «Вниз»
$(«#down»).click(function() //Необходимо прокрутить в конец страницы
var curPos=$(document).scrollTop();
var height=$(«body»).height();
var scrollTime=(height-curPos)/1.73;
$(«body,html»).animate(,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(,scrollTime); приводит к моментальному переходу в начало страницы. Эта проблема исчезает с переходом на Opera 11.
UPD: Поправлен итоговый пример.