I want to smoothly scroll down. I do not want to have to write a function for that - especially if jQuery already has one.
12 Answers
You can just use .animate()
the scrollTop
property, like this:
$("html, body").animate({ scrollTop: "300px" });

- 623,446
- 136
- 1,297
- 1,155
-
Very nice.. no need to use plugins for this. – Amol M Kulkarni Feb 08 '13 at 12:33
-
16Why do you need both `html` and `body`? There is some insight here: http://stackoverflow.com/questions/2123690/slow-down-scroll-to-top-event-by-jquery-animate/2123721#comment16858893_2123721, but it is not a complete answer. – Haralan Dobrev Dec 13 '13 at 15:22
-
29body is used by webkit, html is used by firefox. – Jory Apr 01 '14 at 17:15
-
This fiddle with `html` only (no `body`) works in IE, Firefox & Chrome. http://jsfiddle.net/gNgRj/1/ . Which version of webkit fixed this? – user Jul 26 '14 at 06:49
-
2FYI: If `` has `overflow-x:hidden;` this animate will not work. (Might not work for `overflow-y:hidden`, and `overflow:hidden`, but I have not tested. – collinhaines Jun 09 '15 at 15:02
-
There are some collateral effects on using both html and body: as mention in a few answers the complete callback is called twice but that also mean that jquery animate is executing 2 animations. – Chris Cinelli Jun 17 '15 at 18:01
-
@Error Yes, that fiddle's alert works, but that doesn't mean it's actually scrolling. Try this fiddle: https://jsfiddle.net/8uswq8u3/ – Adam Taylor May 03 '16 at 17:34
-
**Note:** You can change the animation speed, by the second argument in miliseconds. – Sep 22 '17 at 16:56
-
1I think `body` worked in Chrome as of earlier this year, but now it has to be `html`. – Nick Davies Dec 08 '17 at 19:19
-
`html` works for Chrome and Firefox. `body` works for Edge. – MSC Nov 14 '18 at 21:33
Nick's answer works great. Be careful when specifying a complete() function inside the animate() call because it will get executed twice since you have two selectors declared (html and body).
$("html, body").animate(
{ scrollTop: "300px" },
{
complete : function(){
alert('this alert will popup twice');
}
}
);
Here's how you can avoid the double callback.
var completeCalled = false;
$("html, body").animate(
{ scrollTop: "300px" },
{
complete : function(){
if(!completeCalled){
completeCalled = true;
alert('this alert will popup once');
}
}
}
);

- 1,548
- 14
- 21
-
1
-
21Because depending on which browser you are, you can either animate body OR html. By animating BOTH, you cover more browsers. – Bene Oct 30 '13 at 18:21
-
But in this case it will popup really only once, also if it has to be called repeatedly (click event on button) or am I missed something? – HoGo Dec 10 '13 at 07:23
-
Yes, in this case it will only popup once. If you need to animate repeatedly, you would make the completeCalled variable local to the callback function that executes the animate function. That way it will still popup only once when you click, but it will popup again (just once) when you click again. – Kita Jan 10 '14 at 15:43
-
To prevent double callback function firing you can use `die()` function before `live()` function call. This guaranties, that your `live()` handler will be called only once. – Lord Nighton Nov 23 '15 at 15:32
-
[_If multiple elements are animated, the callback is executed once per matched element, not once for the animation as a whole. Use the .promise() method to obtain a promise to which you can attach callbacks that fire once for an animated set of any size, including zero elements._](http://api.jquery.com/animate/#callbacks) – c24w Feb 12 '19 at 11:20
Nick's answer works great and the default settings are nice, but you can more fully control the scrolling by completing all of the optional settings.
here is what it looks like in the API:
.animate( properties [, duration] [, easing] [, complete] )
so you could do something like this:
.animate(
{scrollTop:'300px'},
300,
swing,
function(){
alert(animation complete! - your custom code here!);
}
)
here is the jQuery .animate function api page: http://api.jquery.com/animate/

- 1,606
- 18
- 22
Like Kita mentioned there is a problem with multiple callbacks firing when you animate on both 'html' and 'body'. Instead of animating both and blocking subsequent callbacks I prefer to use some basic feature detection and only animate the scrollTop property of a single object.
The accepted answer on this other thread gives some insight as to which object's scrollTop property we should try to animate: pageYOffset Scrolling and Animation in IE8
// UPDATE: don't use this... see below
// only use 'body' for IE8 and below
var scrollTopElement = (window.pageYOffset != null) ? 'html' : 'body';
// only animate on one element so our callback only fires once!
$(scrollTopElement).animate({
scrollTop: '400px' // vertical position on the page
},
500, // the duration of the animation
function() {
// callback goes here...
})
});
UPDATE - - -
The above attempt at feature detection fails. Seems like there's not a one-line way of doing it as webkit type browsers pageYOffset property always returns zero when there's a doctype. Instead, I found a way to use a promise to do a single callback for every time the animation executes.
$('html, body')
.animate({ scrollTop: 100 })
.promise()
.then(function(){
// callback code here
})
});
-
1
-
This needs more upvotes. I've never seen promise used for this before, and this is something I end up searching for every few months. As Allan said, genius. – Tortilaman Apr 26 '18 at 07:28
I have what I believe is a better solution than the $('html, body')
hack.
It's not a one-liner, but the issue I had with $('html, body')
is that if you log $(window).scrollTop()
during the animation, you'll see that the value jumps all over the place, sometimes by hundreds of pixels (though I don't see anything like that happening visually). I needed the value to be predictable, so that I could cancel the animation if the user grabbed the scroll bar or twirled the mousewheel during the auto-scroll.
Here is a function will animate scrolling smoothly:
function animateScrollTop(target, duration) {
duration = duration || 16;
var scrollTopProxy = { value: $(window).scrollTop() };
if (scrollTopProxy.value != target) {
$(scrollTopProxy).animate(
{ value: target },
{ duration: duration, step: function (stepValue) {
var rounded = Math.round(stepValue);
$(window).scrollTop(rounded);
}
});
}
}
Below is a more complex version that will cancel the animation on user interaction, as well as refiring until the target value is reached, which is useful when trying to set the scrollTop instantaneously (e.g. simply calling $(window).scrollTop(1000)
— in my experience, this fails to work about 50% of the time.)
function animateScrollTop(target, duration) {
duration = duration || 16;
var $window = $(window);
var scrollTopProxy = { value: $window.scrollTop() };
var expectedScrollTop = scrollTopProxy.value;
if (scrollTopProxy.value != target) {
$(scrollTopProxy).animate(
{ value: target },
{
duration: duration,
step: function (stepValue) {
var roundedValue = Math.round(stepValue);
if ($window.scrollTop() !== expectedScrollTop) {
// The user has tried to scroll the page
$(scrollTopProxy).stop();
}
$window.scrollTop(roundedValue);
expectedScrollTop = roundedValue;
},
complete: function () {
if ($window.scrollTop() != target) {
setTimeout(function () {
animateScrollTop(target);
}, 16);
}
}
}
);
}
}

- 1,371
- 18
- 14
I was having issues where the animation was always starting from the top of the page after a page refresh in the other examples.
I fixed this by not animating the css directly but rather calling window.scrollTo();
on each step:
$({myScrollTop:window.pageYOffset}).animate({myScrollTop:300}, {
duration: 600,
easing: 'swing',
step: function(val) {
window.scrollTo(0, val);
}
});
This also gets around the html
vs body
issue as it's using cross-browser JavaScript.
Have a look at http://james.padolsey.com/javascript/fun-with-jquerys-animate/ for more information on what you can do with jQuery's animate function.

- 2,610
- 1
- 29
- 37
You can use the jQuery animation for scroll page with a specific duration:
$("html, body").animate({scrollTop: "1024px"}, 5000);
where 1024px is the scroll offset and 5000 is the duration of animations in millisecond.

- 2,509
- 28
- 21
-
Great answer! Glad you included the duration option. Just wanted to add that `$("html, body").animate({scrollTop: 1024}, 5000);` also works. – Ryan Taylor Sep 12 '17 at 17:59
Try the scrollTo plugin.

- 6,193
- 4
- 28
- 44

- 123,288
- 34
- 187
- 185
-
-
The code to accomplish this is so simple. Why would you add a plugin to do something you can do with one line of code? – Gavin Nov 05 '14 at 07:24
-
5
$(".scroll-top").on("click", function(e){
e.preventDefault();
$("html, body").animate({scrollTop:"0"},600);
});

- 16,800
- 14
- 110
- 131

- 2,503
- 2
- 22
- 23
If you want to move down at the end of the page (so you don't need to scroll down to bottom) , you can use:
$('body').animate({ scrollTop: $(document).height() });

- 11
- 2
But if you really want to add some animation while scrolling, you can try my simple plugin (AnimateScroll) which currently supports more than 30 easing styles

- 16,266
- 13
- 66
- 81
the cross browser code is:
$(window).scrollTop(300);
it is without animation but works everywhere

- 51,061
- 28
- 99
- 211

- 11
- 1
-
6I was looking for a way "to animate scrollTop with jQuery?" An answer that is "without animation" is not an answer. – 700 Software Sep 10 '13 at 20:08