I’d like to make the browser to scroll the page to a given anchor, just by using JavaScript.
I have specified a name or id attribute in my HTML code:
<a name="anchorName">..</a>
or
<h1 id="anchorName2">..</h1>
I’d like to get the same effect as you’d get by navigating to http://server.com/path#anchorName. The page should be scrolled so that the anchor is near the top of the visible part of the page.
function scrollTo(hash) {
location.hash = "#" + hash;
}
No jQuery required at all!
Way simpler:
var element_to_scroll_to = document.getElementById('anchorName2');
// Or:
var element_to_scroll_to = document.querySelectorAll('.my-element-class')[0];
// Or:
var element_to_scroll_to = $('.my-element-class')[0];
// Basically `element_to_scroll_to` just have to be a reference
// to any DOM element present on the page
// Then:
element_to_scroll_to.scrollIntoView();
You can use jQuery's .animate(), .offset() and scrollTop. Like
$(document.body).animate({
'scrollTop': $('#anchorName2').offset().top
}, 2000);
Example link: http://jsbin.com/unasi3/edit
If you don't want to animate, use .scrollTop() like:
$(document.body).scrollTop($('#anchorName2').offset().top);
Or JavaScript's native location.hash like:
location.hash = '#' + anchorid;
2018-2020 Pure JavaScript:
There is a very convenient way to scroll to the element:
el.scrollIntoView({
behavior: 'smooth', // smooth scroll
block: 'start' // the upper border of the element will be aligned at the top of the visible part of the window of the scrollable area.
})
But as far as I understand, it does not have such good support as the options below.
Learn more about the method.
If it is necessary that the element is in the top:
const element = document.querySelector('#element')
const topPos = element.getBoundingClientRect().top + window.pageYOffset
window.scrollTo({
top: topPos, // scroll so that the element is at the top of the view
behavior: 'smooth' // smooth scroll
})
Demonstration example on CodePen
If you want the element to be in the center:
const element = document.querySelector('#element')
const rect = element.getBoundingClientRect() // get rects(width, height, top, etc)
const viewHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
window.scroll({
top: rect.top + rect.height / 2 - viewHeight / 2,
behavior: 'smooth' // smooth scroll
});
Demonstration example on CodePen
Support:
They write that scroll is the same method as scrollTo, but support shows better in scrollTo.
More about the method.
Great solution by jAndy, but the smooth scroll seems to be having issues working in Firefox.
Writing it this way works in Firefox as well.
(function($) {
$(document).ready(function() {
$('html, body').animate({
'scrollTop': $('#anchorName2').offset().top
}, 2000);
});
})(jQuery);
In 2018, you don't need jQuery for something simple like this. The built in scrollIntoView() method supports a "behavior" property to smoothly scroll to any element on the page. You can even update the browser URL with a hash to make it bookmarkable.
From this tutorial on scrolling HTML Bookmarks, here is a native way to add smooth scrolling to all anchor links on your page automatically:
let anchorlinks = document.querySelectorAll('a[href^="#"]')
for (let item of anchorlinks) { // relitere
item.addEventListener('click', (e)=> {
let hashval = item.getAttribute('href')
let target = document.querySelector(hashval)
target.scrollIntoView({
behavior: 'smooth',
block: 'start'
})
history.pushState(null, null, hashval)
e.preventDefault()
})
}
Here is a pure JavaScript solution without jQuery. It was tested on Chrome and Internet Explorer, but not tested on iOS.
function ScrollTo(name) {
ScrollToResolver(document.getElementById(name));
}
function ScrollToResolver(elem) {
var jump = parseInt(elem.getBoundingClientRect().top * .2);
document.body.scrollTop += jump;
document.documentElement.scrollTop += jump;
if (!elem.lastjump || elem.lastjump > Math.abs(jump)) {
elem.lastjump = Math.abs(jump);
setTimeout(function() { ScrollToResolver(elem);}, "100");
} else {
elem.lastjump = null;
}
}
Demo: https://jsfiddle.net/jd7q25hg/12/
The easiest way to to make the browser to scroll the page to a given anchor is to add *{scroll-behavior: smooth;} in your style.css file and in your HTML navigation use #NameOfTheSection.
*{scroll-behavior: smooth;}
<a href="#scroll-to">Click to Scroll<a/>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<p>other sections</p>
<section id="scroll-to">
<p>it will scroll down to this section</p>
</section>
Smoothly scroll to the proper position
Get correct y coordinate and use window.scrollTo({top: y, behavior: 'smooth'})
const id = 'anchorName2';
const yourElement = document.getElementById(id);
const y = yourElement.getBoundingClientRect().top + window.pageYOffset;
window.scrollTo({top: y, behavior: 'smooth'});
$(document).ready ->
$("a[href^='#']").click ->
$(document.body).animate
scrollTop: $($(this).attr("href")).offset().top, 1000
The solution from CSS-Tricks no longer works in jQuery 2.2.0. It will throw a selector error:
JavaScript runtime error: Syntax error, unrecognized expression: a[href*=#]:not([href=#])
I fixed it by changing the selector. The full snippet is this:
$(function() {
$("a[href*='#']:not([href='#'])").click(function() {
if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') && location.hostname == this.hostname) {
var target = $(this.hash);
target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
if (target.length) {
$('html,body').animate({
scrollTop: target.offset().top
}, 1000);
return false;
}
}
});
});
This works:
$('.scroll').on("click", function(e) {
e.preventDefault();
var dest = $(this).attr("href");
$("html, body").animate({
'scrollTop': $(dest).offset().top
}, 2000);
});
https://jsfiddle.net/68pnkfgd/
Just add the class 'scroll' to any links you wish to animate
Most answers are unnecessarily complicated.
If you just want to jump to the target element, you don't need JavaScript:
# the link:
Click here to jump.
# target element:
<div id="target">Any kind of element.</div>
If you want to scroll to the target animatedly, please refer to 5hahiL's answer.
jQuery("a[href^='#']").click(function(){
jQuery('html, body').animate({
scrollTop: jQuery( jQuery(this).attr('href') ).offset().top
}, 1000);
return false;
});
This is a working script that will scroll the page to the anchor.
To set it up, just give the anchor link an id that matches the name attribute of the anchor that you want to scroll to.
<script>
jQuery(document).ready(function ($){
$('a').click(function (){
var id = $(this).attr('id');
console.log(id);
if ( id == 'cet' || id == 'protein' ) {
$('html, body').animate({ scrollTop: $('[name="' + id + '"]').offset().top}, 'slow');
}
});
});
</script>
I found an easy and simple jQuery solution on CSS-Tricks. That's the one I'm using now.
$(function() {
$('a[href*=#]:not([href=#])').click(function() {
if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') && location.hostname == this.hostname) {
var target = $(this.hash);
target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
if (target.length) {
$('html,body').animate({
scrollTop: target.offset().top
}, 1000);
return false;
}
}
});
});
A Vue.js 2 solution ... add a simple data property to simply force the update:
const app = new Vue({
...
, updated: function() {
this.$nextTick(function() {
var uri = window.location.href
var anchor = ( uri.indexOf('#') === -1 ) ? '' : uri.split('#')[1]
if ( String(anchor).length > 0 && this.updater === 'page_load' ) {
this.updater = "" // only on page-load !
location.href = "#"+String(anchor)
}
})
}
});
app.updater = "page_load"
/* Smooth scrolling in CSS - it works in HTML5 only */
html, body {
scroll-behavior: smooth;
}
Related
I am using some JavaScript to create a smooth scroll effect to achnor links. The site has a fixed header so the content needs to be offset by whatever the height of the header is (this varies due to #media rules). On top of this when the user is logged in to WordPress the content needs to be offset further by the height of the WP admin bar (again, the height of this vaires depending on screen size).
I have set up two variables in my script to separately get the height of both these elements:
var headerHeight = $('header').height();
var adminbarHeight = $('#wpadminbar').height();
Further on in the script I want to offset the top by the height of the header plus the height of the admin bar if it exists (i.e. if a user is logged in).
$('html, body').animate({scrollTop: target.offset().top - headerHeight - adminbarHeight }, 500,
I am trying to offset by the headerHeight and the adminbarHeight but this is not working for me. If I remove 'adminbarHeight' it works but then it does not look correct for logged in users.
Is there something wrong with my syntax? Or perhaps I need to create an if statement to check if the adminbarHeight is greater than 0?
The full script I am enqueueing in my WP child theme is below:
( function( $ ) {
'use strict';
$('a[href*="#"]')
.not('[href="#"]')
.not('[href="#0"]')
.click(function(event) {
var headerHeight = $('header').height();
var adminbarHeight = $('#wpadminbar').height();
if (
location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '')
&&
location.hostname == this.hostname
) {
var target = $(this.hash);
target = target.length ? target : $('[name=' + this.hash.slice(1) + ']');
if (target.length) {
event.preventDefault();
$('html, body').animate({scrollTop: target.offset().top - headerHeight - adminbarHeight }, 500,
function() {
var $target = $(target);
$target.focus();
if ($target.is(":focus")) {
return false;
} else {
$target.attr('tabindex','-1');
$target.focus();
};
});
}
}
});
}( jQuery ) );
Any help will be greatly appreciated! I am new to JavaScript so apologies if this is a really obvious error.
Thanks,
Chris
I have this input element:
<input type="text" class="textfield" value="" id="subject" name="subject">
Then I have some other elements, like other tag's & <textarea> tag's, etc...
When the user clicks on the <input id="#subject">, the page should scroll to the page's last element, and it should do so with a nice animation (It should be a scroll to bottom and not to top).
The last item of the page is a submit button with #submit:
<input type="submit" class="submit" id="submit" name="submit" value="Ok, Done.">
The animation should not be too fast and should be fluid.
I am running the latest jQuery version. I prefer to not install any plugin but to use the default jQuery features to achieve this.
Assuming you have a button with the id button, try this example:
$("#button").click(function() {
$([document.documentElement, document.body]).animate({
scrollTop: $("#elementtoScrollToID").offset().top
}, 2000);
});
I got the code from the article Smoothly scroll to an element without a jQuery plugin. And I have tested it on the example below.
<html>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
<script>
$(document).ready(function (){
$("#click").click(function (){
$('html, body').animate({
scrollTop: $("#div1").offset().top
}, 2000);
});
});
</script>
<div id="div1" style="height: 1000px; width 100px">
Test
</div>
<br/>
<div id="div2" style="height: 1000px; width 100px">
Test 2
</div>
<button id="click">Click me</button>
</html>
jQuery .scrollTo(): View - Demo, API, Source
I wrote this lightweight plugin to make page/element scrolling much easier. It's flexible where you could pass in a target element or specified value. Perhaps this could be part of jQuery's next official release, what do you think?
Examples Usage:
$('body').scrollTo('#target'); // Scroll screen to target element
$('body').scrollTo(500); // Scroll screen 500 pixels down
$('#scrollable').scrollTo(100); // Scroll individual element 100 pixels down
Options:
scrollTarget: A element, string, or number which indicates desired scroll position.
offsetTop: A number that defines additional spacing above scroll target.
duration: A string or number determining how long the animation will run.
easing: A string indicating which easing function to use for the transition.
complete: A function to call once the animation is complete.
If you are not much interested in the smooth scroll effect and just interested in scrolling to a particular element, you don't require some jQuery function for this. Javascript has got your case covered:
https://developer.mozilla.org/en-US/docs/Web/API/element.scrollIntoView
So all you need to do is: $("selector").get(0).scrollIntoView();
.get(0) is used because we want to retrieve the JavaScript's DOM element and not the JQuery's DOM element.
UPDATE
now is possible to scroll with animation, passing scroll options (see MDN). You can even control the block position. It seems to have large support, except for Safari
$("selector").get(0).scrollIntoView({behavior: 'smooth'});
This is achievable without jQuery:
document.getElementById("element-id").scrollIntoView();
Using this simple script
if($(window.location.hash).length > 0){
$('html, body').animate({ scrollTop: $(window.location.hash).offset().top}, 1000);
}
Would make in sort that if a hash tag is found in the url, the scrollTo animate to the ID. If not hash tag found, then ignore the script.
jQuery(document).ready(function($) {
$('a[href^="#"]').bind('click.smoothscroll',function (e) {
e.preventDefault();
var target = this.hash,
$target = $(target);
$('html, body').stop().animate( {
'scrollTop': $target.offset().top-40
}, 900, 'swing', function () {
window.location.hash = target;
} );
} );
} );
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul role="tablist">
<li class="active" id="p1">Section 1</li>
<li id="p2">Section 2</li>
<li id="p3">Section 3</li>
</ul>
<div id="pane1"></div>
<div id="pane2"></div>
<div id="pane3"></div>
This is the way I do it.
document.querySelector('scrollHere').scrollIntoView({ behavior: 'smooth' })
Works in any browser.
It can easily be wrapped into a function
function scrollTo(selector) {
document.querySelector(selector).scrollIntoView({ behavior: 'smooth' })
}
Here is a working example
$(".btn").click(function() {
document.getElementById("scrollHere").scrollIntoView( {behavior: "smooth" })
})
.btn {margin-bottom: 500px;}
.middle {display: block; margin-bottom: 500px; color: red;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button class="btn">Scroll down</button>
<h1 class="middle">You see?</h1>
<div id="scrollHere">Arrived at your destination</div>
Docs
The solution by Steve and Peter works very well.
But in some cases, you may have to convert the value to an integer. Strangely, the returned value from $("...").offset().top is sometimes in float.
Use: parseInt($("....").offset().top)
For example:
$("#button").click(function() {
$('html, body').animate({
scrollTop: parseInt($("#elementtoScrollToID").offset().top)
}, 2000);
});
A compact version of "animate" solution.
$.fn.scrollTo = function (speed) {
if (typeof(speed) === 'undefined')
speed = 1000;
$('html, body').animate({
scrollTop: parseInt($(this).offset().top)
}, speed);
};
Basic usage: $('#your_element').scrollTo();
With this solution you do not need any plugin and there's no setup required besides placing the script before your closing </body> tag.
$("a[href^='#']").on("click", function(e) {
$("html, body").animate({
scrollTop: $($(this).attr("href")).offset().top
}, 1000);
return false;
});
if ($(window.location.hash).length > 1) {
$("html, body").animate({
scrollTop: $(window.location.hash).offset().top
}, 1000);
}
On load, if there is a hash in the address, we scroll to it.
And - whenever you click an a link with an href hash e.g. #top, we scroll to it.
##Edit 2020
If you want a pure JavaScript solution: you could perhaps instead use something like:
var _scrollToElement = function (selector) {
try {
document.querySelector(selector).scrollIntoView({ behavior: 'smooth' });
} catch (e) {
console.warn(e);
}
}
var _scrollToHashesInHrefs = function () {
document.querySelectorAll("a[href^='#']").forEach(function (el) {
el.addEventListener('click', function (e) {
_scrollToElement(el.getAttribute('href'));
return false;
})
})
if (window.location.hash) {
_scrollToElement(window.location.hash);
}
}
_scrollToHashesInHrefs();
If you are only handling scrolling to an input element, you can use focus(). For example, if you wanted to scroll to the first visible input:
$(':input:visible').first().focus();
Or the first visible input in an container with class .error:
$('.error :input:visible').first().focus();
Thanks to Tricia Ball for pointing this out!
Easy way to achieve the scroll of page to target div id
var targetOffset = $('#divID').offset().top;
$('html, body').animate({scrollTop: targetOffset}, 1000);
If you want to scroll within an overflow container (instead of $('html, body') answered above), working also with absolute positioning, this is the way to do :
var elem = $('#myElement'),
container = $('#myScrollableContainer'),
pos = elem.position().top + container.scrollTop() - container.position().top;
container.animate({
scrollTop: pos
}
After finding the way to get my code work, I think I should make thing a bit clear:
For using:
$('html, body').animate({
scrollTop: $("#div1").offset().top
}, 2000);
you need to be on top of the page since $("#div1").offset().top will return different numbers for different positions you scroll to. If you already scrolled out of the top, you need to specify the exact pageY value (see pageY definition here: https://javascript.info/coordinates).
So now, the problem is to calculate the pageY value of one element. Below is an example in case the scroll container is the body:
function getPageY(id) {
let elem = document.getElementById(id);
let box = elem.getBoundingClientRect();
var body = document.getElementsByTagName("BODY")[0];
return box.top + body.scrollTop; // for window scroll: box.top + window.scrollY;
}
The above function returns the same number even if you scrolled somewhere. Now, to scroll back to that element:
$("html, body").animate({ scrollTop: getPageY('div1') }, "slow");
Animations:
// slide to top of the page
$('.up').click(function () {
$("html, body").animate({
scrollTop: 0
}, 600);
return false;
});
// slide page to anchor
$('.menutop b').click(function(){
//event.preventDefault();
$('html, body').animate({
scrollTop: $( $(this).attr('href') ).offset().top
}, 600);
return false;
});
// Scroll to class, div
$("#button").click(function() {
$('html, body').animate({
scrollTop: $("#target-element").offset().top
}, 1000);
});
// div background animate
$(window).scroll(function () {
var x = $(this).scrollTop();
// freezze div background
$('.banner0').css('background-position', '0px ' + x +'px');
// from left to right
$('.banner0').css('background-position', x+'px ' +'0px');
// from right to left
$('.banner0').css('background-position', -x+'px ' +'0px');
// from bottom to top
$('#skills').css('background-position', '0px ' + -x + 'px');
// move background from top to bottom
$('.skills1').css('background-position', '0% ' + parseInt(-x / 1) + 'px' + ', 0% ' + parseInt(-x / 1) + 'px, center top');
// Show hide mtop menu
if ( x > 100 ) {
$( ".menu" ).addClass( 'menushow' );
$( ".menu" ).fadeIn("slow");
$( ".menu" ).animate({opacity: 0.75}, 500);
} else {
$( ".menu" ).removeClass( 'menushow' );
$( ".menu" ).animate({opacity: 1}, 500);
}
});
// progres bar animation simple
$('.bar1').each(function(i) {
var width = $(this).data('width');
$(this).animate({'width' : width + '%' }, 900, function(){
// Animation complete
});
});
In most cases, it would be best to use a plugin. Seriously. I'm going to tout mine here. Of course there are others, too. But please check if they really avoid the pitfalls for which you'd want a plugin in the first place - not all of them do.
I have written about the reasons for using a plugin elsewhere. In a nutshell, the one liner underpinning most answers here
$('html, body').animate( { scrollTop: $target.offset().top }, duration );
is bad UX.
The animation doesn't respond to user actions. It carries on even if the user clicks, taps, or tries to scroll.
If the starting point of the animation is close to the target element, the animation is painfully slow.
If the target element is placed near the bottom of the page, it can't be scrolled to the top of the window. The scroll animation stops abruptly then, in mid motion.
To handle these issues (and a bunch of others), you can use a plugin of mine, jQuery.scrollable. The call then becomes
$( window ).scrollTo( targetPosition );
and that's it. Of course, there are more options.
With regard to the target position, $target.offset().top does the job in most cases. But please be aware that the returned value doesn't take a border on the html element into account (see this demo). If you need the target position to be accurate under any circumstances, it is better to use
targetPosition = $( window ).scrollTop() + $target[0].getBoundingClientRect().top;
That works even if a border on the html element is set.
This is my approach abstracting the ID's and href's, using a generic class selector
$(function() {
// Generic selector to be used anywhere
$(".js-scroll-to").click(function(e) {
// Get the href dynamically
var destination = $(this).attr('href');
// Prevent href=“#” link from changing the URL hash (optional)
e.preventDefault();
// Animate scroll to destination
$('html, body').animate({
scrollTop: $(destination).offset().top
}, 500);
});
});
<!-- example of a fixed nav menu -->
<ul class="nav">
<li>
Item 1
</li>
<li>
Item 2
</li>
<li>
Item 3
</li>
</ul>
Very simple and easy to use custom jQuery plugin. Just add the attribute scroll= to your clickable element and set its value to the selector you want to scroll to.
Like so: <a scroll="#product">Click me</a>. It can be used on any element.
(function($){
$.fn.animateScroll = function(){
console.log($('[scroll]'));
$('[scroll]').click(function(){
selector = $($(this).attr('scroll'));
console.log(selector);
console.log(selector.offset().top);
$('html body').animate(
{scrollTop: (selector.offset().top)}, //- $(window).scrollTop()
1000
);
});
}
})(jQuery);
// RUN
jQuery(document).ready(function($) {
$().animateScroll();
});
// IN HTML EXAMPLE
// RUN ONCLICK ON OBJECT WITH ATTRIBUTE SCROLL=".SELECTOR"
// <a scroll="#product">Click To Scroll</a>
$('html, body').animate(...) does not work for me in the iPhone, Android, Chrome, or Safari browsers.
I had to target the root content element of the page.
$('#cotnent').animate(...)
Here is what I have ended up with:
if (navigator.userAgent.match(/(iPod|iPhone|iPad|Android)/)) {
$('#content').animate({
scrollTop: $("#elementtoScrollToID").offset().top
}, 'slow');
}
else{
$('html, body').animate({
scrollTop: $("#elementtoScrollToID").offset().top
}, 'slow');
}
All body content wired up with a #content div
<html>
....
<body>
<div id="content">
...
</div>
</body>
</html>
$('html, body').animate({scrollTop:
Math.min(
$(to).offset().top-margintop, //margintop is the margin above the target
$('body')[0].scrollHeight-$('body').height()) //if the target is at the bottom
}, 2000);
To show the full element (if it's possible with the current window size):
var element = $("#some_element");
var elementHeight = element.height();
var windowHeight = $(window).height();
var offset = Math.min(elementHeight, windowHeight) + element.offset().top;
$('html, body').animate({ scrollTop: offset }, 500);
var scrollTo = function($parent, $element) {
var topDiff = $element.position().top - $parent.position().top;
$parent.animate({
scrollTop : topDiff
}, 100);
};
This is Atharva's answer from: https://developer.mozilla.org/en-US/docs/Web/API/element.scrollIntoView.
Just wanted to add if your document is in an iframe, you can choose an element in the parent frame to scroll into view:
$('#element-in-parent-frame', window.parent.document).get(0).scrollIntoView();
I wrote a general purpose function that scrolls to either a jQuery object, a CSS selector, or a numeric value.
Example usage:
// scroll to "#target-element":
$.scrollTo("#target-element");
// scroll to 80 pixels above first element with class ".invalid":
$.scrollTo(".invalid", -80);
// scroll a container with id "#my-container" to 300 pixels from its top:
$.scrollTo(300, 0, "slow", "#my-container");
The function's code:
/**
* Scrolls the container to the target position minus the offset
*
* #param target - the destination to scroll to, can be a jQuery object
* jQuery selector, or numeric position
* #param offset - the offset in pixels from the target position, e.g.
* pass -80 to scroll to 80 pixels above the target
* #param speed - the scroll speed in milliseconds, or one of the
* strings "fast" or "slow". default: 500
* #param container - a jQuery object or selector for the container to
* be scrolled. default: "html, body"
*/
jQuery.scrollTo = function (target, offset, speed, container) {
if (isNaN(target)) {
if (!(target instanceof jQuery))
target = $(target);
target = parseInt(target.offset().top);
}
container = container || "html, body";
if (!(container instanceof jQuery))
container = $(container);
speed = speed || 500;
offset = offset || 0;
container.animate({
scrollTop: target + offset
}, speed);
};
When the user clicks on that input with #subject, the page should
scroll to the last element of the page with a nice animation. It
should be a scroll to bottom and not to top.
The last item of the page is a submit button with #submit
$('#subject').click(function()
{
$('#submit').focus();
$('#subject').focus();
});
This will first scroll down to #submit then restore the cursor back to the input that was clicked, which mimics a scroll down, and works on most browsers. It also doesn't require jQuery as it can be written in pure JavaScript.
Can this fashion of using focus function mimic animation in a better way, through chaining focus calls. I haven't tested this theory, but it would look something like this:
<style>
#F > *
{
width: 100%;
}
</style>
<form id="F" >
<div id="child_1"> .. </div>
<div id="child_2"> .. </div>
..
<div id="child_K"> .. </div>
</form>
<script>
$('#child_N').click(function()
{
$('#child_N').focus();
$('#child_N+1').focus();
..
$('#child_K').focus();
$('#child_N').focus();
});
</script>
I set up a module scroll-element npm install scroll-element. It works like this:
import { scrollToElement, scrollWindowToElement } from 'scroll-element'
/* scroll the window to your target element, duration and offset optional */
let targetElement = document.getElementById('my-item')
scrollWindowToElement(targetElement)
/* scroll the overflow container element to your target element, duration and offset optional */
let containerElement = document.getElementById('my-container')
let targetElement = document.getElementById('my-item')
scrollToElement(containerElement, targetElement)
Written with help from the following SO posts:
offset-top-of-an-element-without-jquery
scrolltop-animation-without-jquery
Here is the code:
export const scrollToElement = function(containerElement, targetElement, duration, offset) {
if (duration == null) { duration = 1000 }
if (offset == null) { offset = 0 }
let targetOffsetTop = getElementOffset(targetElement).top
let containerOffsetTop = getElementOffset(containerElement).top
let scrollTarget = targetOffsetTop + ( containerElement.scrollTop - containerOffsetTop)
scrollTarget += offset
scroll(containerElement, scrollTarget, duration)
}
export const scrollWindowToElement = function(targetElement, duration, offset) {
if (duration == null) { duration = 1000 }
if (offset == null) { offset = 0 }
let scrollTarget = getElementOffset(targetElement).top
scrollTarget += offset
scrollWindow(scrollTarget, duration)
}
function scroll(containerElement, scrollTarget, duration) {
let scrollStep = scrollTarget / (duration / 15)
let interval = setInterval(() => {
if ( containerElement.scrollTop < scrollTarget ) {
containerElement.scrollTop += scrollStep
} else {
clearInterval(interval)
}
},15)
}
function scrollWindow(scrollTarget, duration) {
let scrollStep = scrollTarget / (duration / 15)
let interval = setInterval(() => {
if ( window.scrollY < scrollTarget ) {
window.scrollBy( 0, scrollStep )
} else {
clearInterval(interval)
}
},15)
}
function getElementOffset(element) {
let de = document.documentElement
let box = element.getBoundingClientRect()
let top = box.top + window.pageYOffset - de.clientTop
let left = box.left + window.pageXOffset - de.clientLeft
return { top: top, left: left }
}
Updated answer as of 2019:
$('body').animate({
scrollTop: $('#subject').offset().top - $('body').offset().top + $('body').scrollTop()
}, 'fast');
ONELINER
subject.onclick = e=> window.scroll({ top: submit.offsetTop, behavior: 'smooth'});
subject.onclick = e=> window.scroll({top: submit.offsetTop, behavior: 'smooth'});
.box,.foot{display: flex;background:#fdf;padding:500px 0} .foot{padding:250px}
<input type="text" class="textfield" value="click here" id="subject" name="subject">
<div class="box">
Some content
<textarea></textarea>
</div>
<input type="submit" class="submit" id="submit" name="submit" value="Ok, Done.">
<div class="foot">Some footer</div>
For what it's worth, this is how I managed to achieve such behavior for a general element which can be inside a DIV with scrolling. In our case we don't scroll the full body, but just particular elements with overflow: auto; within a larger layout.
It creates a fake input of the height of the target element, and then puts a focus to it, and the browser will take care about the rest no matter how deep within the scrollable hierarchy you are. Works like a charm.
var $scrollTo = $('#someId'),
inputElem = $('<input type="text"></input>');
$scrollTo.prepend(inputElem);
inputElem.css({
position: 'absolute',
width: '1px',
height: $scrollTo.height()
});
inputElem.focus();
inputElem.remove();
This worked for me:
var targetOffset = $('#elementToScrollTo').offset().top;
$('#DivParent').animate({scrollTop: targetOffset}, 2500);
I have the Html code like below,
<div data-stored="storenow" data-save="save" class="saveIcon" data-unique="game">Save</div>
And I write the jquery to scroll to the gameNo 456 like below.
var container = $("html,body");
var scrollTo = $(this).find('.saveIcon').attr('data-unique', 456);
container.animate({
scrollTop: scrollTo.offset().top - container.offset().top + container.scrollTop()
});
I am using jQuery version 1.9. I am getting error in console:
Cannot read property 'top' of undefined
Is that not possible to scroll to class name instead of id?
But it is working fine in Firefox. But not in chrome or IE.
I try to find the solutions from stackoverflow. But all other solutions are different than my case.
You are not targeting a DOM object, you are targeting a string.
scrollTo = $(this).find('.saveIcon').attr('data-unique', 456); -> this is wrong
So, while you are trying to target an element, you are actually setting the 'data-unique' to the '.saveIcon' element.
Try this:
scrollTo = $('.saveIcon');
Working code:
var $container = $("html,body");
var $scrollTo = $('.saveIcon');
$container.animate({scrollTop: $scrollTo.offset().top - $container.offset().top + $container.scrollTop(), scrollLeft: 0},300);
have you looked at scroll to view function?
https://developer.mozilla.org/en-US/docs/Web/API/element.scrollIntoView
element.scrollIntoView(true);
these two codes worked for me like a charm this first will take to scroll to the top of the page but if you want to scroll to some specific div use the second one with your div id.
$('body, html, #containerDiv').scrollTop(0);
document.getElementById('yourDivID').scrollIntoView();
If you want to scroll to by a class name use the below code
var $container = $("html,body");
var $scrollTo = $('.main-content');
$container.animate({scrollTop: $scrollTo.offset().top - $container.offset().top +
$container.scrollTop(), scrollLeft: 0},300);
I am using following plain js, please try if you can use it in you codes:
$('a.smooth-scroll[href*=#]:not([href=#])').click(function () {
if (location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') && location.hostname == this.hostname) {
var target = $(this.hash);
target = target.length ? target : $('[name=' + this.hash.slice(1) + ']');
if (target.length) {
$('html,body').animate({
scrollTop: target.offset().top
}, 1000);
return false;
}
}
});
Basically I've created a single page website and I've used JQuery to create a ScrollTo effect when clicking on different links. Because I have a fixed div at the top of the page, I've offset the target to the height of the fixed div at the top of the page, so that when it scrolls, the contents isn't hidden by the fixed div at the top of the page:
if ($target) {
var targetOffset = $target.offset().top - $("#div_at_top_of_page").outerHeight();
This works fine, scrolling the target div below my fixed navigation at the top of my page. However in Safari, the scroll to already scrolls below the div by default, so adding:
$("#div_at_top_of_page").outerHeight();
this causes Safari to scroll to the target, but also adding the height of the div at the top of the page, creating a margin.
I'm just looking for a solution to cancel this:
$("#div_at_top_of_page").outerHeight()
for Safari only. Any help would be appreciated, thanks!
EDIT: I'm open to any other solutions rather than browser detection.
Here's the complete thing:
$(document).ready(function() {
function filterPath(string) {
return string
.replace(/^\//,'')
.replace(/(index|default).[a-zA-Z]{3,4}$/,'')
.replace(/\/$/,'');
}
$('a[href*=#]').each(function() {
if ( filterPath(location.pathname) == filterPath(this.pathname)
&& location.hostname == this.hostname
&& this.hash.replace(/#/,'') ) {
var $targetId = $(this.hash), $targetAnchor = $('[name=' + this.hash.slice(1) +']');
var $target = $targetId.length ? $targetId : $targetAnchor.length ? $targetAnchor : false;
if ($target) {
var targetOffset = $target.offset().top - $("#fixed_div_at_top").outerHeight();
$(this).click(function(e) {
$('html, body').animate({scrollTop: targetOffset}, 800);
e.preventDefault();
var d = document.createElement();
d.style.height = "101%";
d.style.overflow = "hidden";
document.body.appendChild(d);
window.scrollTo(0,scrollToM);
setTimeout(function() {
d.parentNode.removeChild(d);
}, 10);
return false;
});
}
}
The direct answer to your question is to use $.browser (http://api.jquery.com/jQuery.browser/ -- deprecated long ago and removed in jQuery 1.9), but I can't recommend it. Better to use feature detection. Even better not to rely on either method. Have provided this as an answer only because you initially asked specifically about targeting Safari.
I have this input element:
<input type="text" class="textfield" value="" id="subject" name="subject">
Then I have some other elements, like other tag's & <textarea> tag's, etc...
When the user clicks on the <input id="#subject">, the page should scroll to the page's last element, and it should do so with a nice animation (It should be a scroll to bottom and not to top).
The last item of the page is a submit button with #submit:
<input type="submit" class="submit" id="submit" name="submit" value="Ok, Done.">
The animation should not be too fast and should be fluid.
I am running the latest jQuery version. I prefer to not install any plugin but to use the default jQuery features to achieve this.
Assuming you have a button with the id button, try this example:
$("#button").click(function() {
$([document.documentElement, document.body]).animate({
scrollTop: $("#elementtoScrollToID").offset().top
}, 2000);
});
I got the code from the article Smoothly scroll to an element without a jQuery plugin. And I have tested it on the example below.
<html>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
<script>
$(document).ready(function (){
$("#click").click(function (){
$('html, body').animate({
scrollTop: $("#div1").offset().top
}, 2000);
});
});
</script>
<div id="div1" style="height: 1000px; width 100px">
Test
</div>
<br/>
<div id="div2" style="height: 1000px; width 100px">
Test 2
</div>
<button id="click">Click me</button>
</html>
jQuery .scrollTo(): View - Demo, API, Source
I wrote this lightweight plugin to make page/element scrolling much easier. It's flexible where you could pass in a target element or specified value. Perhaps this could be part of jQuery's next official release, what do you think?
Examples Usage:
$('body').scrollTo('#target'); // Scroll screen to target element
$('body').scrollTo(500); // Scroll screen 500 pixels down
$('#scrollable').scrollTo(100); // Scroll individual element 100 pixels down
Options:
scrollTarget: A element, string, or number which indicates desired scroll position.
offsetTop: A number that defines additional spacing above scroll target.
duration: A string or number determining how long the animation will run.
easing: A string indicating which easing function to use for the transition.
complete: A function to call once the animation is complete.
If you are not much interested in the smooth scroll effect and just interested in scrolling to a particular element, you don't require some jQuery function for this. Javascript has got your case covered:
https://developer.mozilla.org/en-US/docs/Web/API/element.scrollIntoView
So all you need to do is: $("selector").get(0).scrollIntoView();
.get(0) is used because we want to retrieve the JavaScript's DOM element and not the JQuery's DOM element.
UPDATE
now is possible to scroll with animation, passing scroll options (see MDN). You can even control the block position. It seems to have large support, except for Safari
$("selector").get(0).scrollIntoView({behavior: 'smooth'});
This is achievable without jQuery:
document.getElementById("element-id").scrollIntoView();
Using this simple script
if($(window.location.hash).length > 0){
$('html, body').animate({ scrollTop: $(window.location.hash).offset().top}, 1000);
}
Would make in sort that if a hash tag is found in the url, the scrollTo animate to the ID. If not hash tag found, then ignore the script.
jQuery(document).ready(function($) {
$('a[href^="#"]').bind('click.smoothscroll',function (e) {
e.preventDefault();
var target = this.hash,
$target = $(target);
$('html, body').stop().animate( {
'scrollTop': $target.offset().top-40
}, 900, 'swing', function () {
window.location.hash = target;
} );
} );
} );
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul role="tablist">
<li class="active" id="p1">Section 1</li>
<li id="p2">Section 2</li>
<li id="p3">Section 3</li>
</ul>
<div id="pane1"></div>
<div id="pane2"></div>
<div id="pane3"></div>
This is the way I do it.
document.querySelector('scrollHere').scrollIntoView({ behavior: 'smooth' })
Works in any browser.
It can easily be wrapped into a function
function scrollTo(selector) {
document.querySelector(selector).scrollIntoView({ behavior: 'smooth' })
}
Here is a working example
$(".btn").click(function() {
document.getElementById("scrollHere").scrollIntoView( {behavior: "smooth" })
})
.btn {margin-bottom: 500px;}
.middle {display: block; margin-bottom: 500px; color: red;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button class="btn">Scroll down</button>
<h1 class="middle">You see?</h1>
<div id="scrollHere">Arrived at your destination</div>
Docs
The solution by Steve and Peter works very well.
But in some cases, you may have to convert the value to an integer. Strangely, the returned value from $("...").offset().top is sometimes in float.
Use: parseInt($("....").offset().top)
For example:
$("#button").click(function() {
$('html, body').animate({
scrollTop: parseInt($("#elementtoScrollToID").offset().top)
}, 2000);
});
A compact version of "animate" solution.
$.fn.scrollTo = function (speed) {
if (typeof(speed) === 'undefined')
speed = 1000;
$('html, body').animate({
scrollTop: parseInt($(this).offset().top)
}, speed);
};
Basic usage: $('#your_element').scrollTo();
With this solution you do not need any plugin and there's no setup required besides placing the script before your closing </body> tag.
$("a[href^='#']").on("click", function(e) {
$("html, body").animate({
scrollTop: $($(this).attr("href")).offset().top
}, 1000);
return false;
});
if ($(window.location.hash).length > 1) {
$("html, body").animate({
scrollTop: $(window.location.hash).offset().top
}, 1000);
}
On load, if there is a hash in the address, we scroll to it.
And - whenever you click an a link with an href hash e.g. #top, we scroll to it.
##Edit 2020
If you want a pure JavaScript solution: you could perhaps instead use something like:
var _scrollToElement = function (selector) {
try {
document.querySelector(selector).scrollIntoView({ behavior: 'smooth' });
} catch (e) {
console.warn(e);
}
}
var _scrollToHashesInHrefs = function () {
document.querySelectorAll("a[href^='#']").forEach(function (el) {
el.addEventListener('click', function (e) {
_scrollToElement(el.getAttribute('href'));
return false;
})
})
if (window.location.hash) {
_scrollToElement(window.location.hash);
}
}
_scrollToHashesInHrefs();
If you are only handling scrolling to an input element, you can use focus(). For example, if you wanted to scroll to the first visible input:
$(':input:visible').first().focus();
Or the first visible input in an container with class .error:
$('.error :input:visible').first().focus();
Thanks to Tricia Ball for pointing this out!
Easy way to achieve the scroll of page to target div id
var targetOffset = $('#divID').offset().top;
$('html, body').animate({scrollTop: targetOffset}, 1000);
If you want to scroll within an overflow container (instead of $('html, body') answered above), working also with absolute positioning, this is the way to do :
var elem = $('#myElement'),
container = $('#myScrollableContainer'),
pos = elem.position().top + container.scrollTop() - container.position().top;
container.animate({
scrollTop: pos
}
After finding the way to get my code work, I think I should make thing a bit clear:
For using:
$('html, body').animate({
scrollTop: $("#div1").offset().top
}, 2000);
you need to be on top of the page since $("#div1").offset().top will return different numbers for different positions you scroll to. If you already scrolled out of the top, you need to specify the exact pageY value (see pageY definition here: https://javascript.info/coordinates).
So now, the problem is to calculate the pageY value of one element. Below is an example in case the scroll container is the body:
function getPageY(id) {
let elem = document.getElementById(id);
let box = elem.getBoundingClientRect();
var body = document.getElementsByTagName("BODY")[0];
return box.top + body.scrollTop; // for window scroll: box.top + window.scrollY;
}
The above function returns the same number even if you scrolled somewhere. Now, to scroll back to that element:
$("html, body").animate({ scrollTop: getPageY('div1') }, "slow");
Animations:
// slide to top of the page
$('.up').click(function () {
$("html, body").animate({
scrollTop: 0
}, 600);
return false;
});
// slide page to anchor
$('.menutop b').click(function(){
//event.preventDefault();
$('html, body').animate({
scrollTop: $( $(this).attr('href') ).offset().top
}, 600);
return false;
});
// Scroll to class, div
$("#button").click(function() {
$('html, body').animate({
scrollTop: $("#target-element").offset().top
}, 1000);
});
// div background animate
$(window).scroll(function () {
var x = $(this).scrollTop();
// freezze div background
$('.banner0').css('background-position', '0px ' + x +'px');
// from left to right
$('.banner0').css('background-position', x+'px ' +'0px');
// from right to left
$('.banner0').css('background-position', -x+'px ' +'0px');
// from bottom to top
$('#skills').css('background-position', '0px ' + -x + 'px');
// move background from top to bottom
$('.skills1').css('background-position', '0% ' + parseInt(-x / 1) + 'px' + ', 0% ' + parseInt(-x / 1) + 'px, center top');
// Show hide mtop menu
if ( x > 100 ) {
$( ".menu" ).addClass( 'menushow' );
$( ".menu" ).fadeIn("slow");
$( ".menu" ).animate({opacity: 0.75}, 500);
} else {
$( ".menu" ).removeClass( 'menushow' );
$( ".menu" ).animate({opacity: 1}, 500);
}
});
// progres bar animation simple
$('.bar1').each(function(i) {
var width = $(this).data('width');
$(this).animate({'width' : width + '%' }, 900, function(){
// Animation complete
});
});
In most cases, it would be best to use a plugin. Seriously. I'm going to tout mine here. Of course there are others, too. But please check if they really avoid the pitfalls for which you'd want a plugin in the first place - not all of them do.
I have written about the reasons for using a plugin elsewhere. In a nutshell, the one liner underpinning most answers here
$('html, body').animate( { scrollTop: $target.offset().top }, duration );
is bad UX.
The animation doesn't respond to user actions. It carries on even if the user clicks, taps, or tries to scroll.
If the starting point of the animation is close to the target element, the animation is painfully slow.
If the target element is placed near the bottom of the page, it can't be scrolled to the top of the window. The scroll animation stops abruptly then, in mid motion.
To handle these issues (and a bunch of others), you can use a plugin of mine, jQuery.scrollable. The call then becomes
$( window ).scrollTo( targetPosition );
and that's it. Of course, there are more options.
With regard to the target position, $target.offset().top does the job in most cases. But please be aware that the returned value doesn't take a border on the html element into account (see this demo). If you need the target position to be accurate under any circumstances, it is better to use
targetPosition = $( window ).scrollTop() + $target[0].getBoundingClientRect().top;
That works even if a border on the html element is set.
This is my approach abstracting the ID's and href's, using a generic class selector
$(function() {
// Generic selector to be used anywhere
$(".js-scroll-to").click(function(e) {
// Get the href dynamically
var destination = $(this).attr('href');
// Prevent href=“#” link from changing the URL hash (optional)
e.preventDefault();
// Animate scroll to destination
$('html, body').animate({
scrollTop: $(destination).offset().top
}, 500);
});
});
<!-- example of a fixed nav menu -->
<ul class="nav">
<li>
Item 1
</li>
<li>
Item 2
</li>
<li>
Item 3
</li>
</ul>
Very simple and easy to use custom jQuery plugin. Just add the attribute scroll= to your clickable element and set its value to the selector you want to scroll to.
Like so: <a scroll="#product">Click me</a>. It can be used on any element.
(function($){
$.fn.animateScroll = function(){
console.log($('[scroll]'));
$('[scroll]').click(function(){
selector = $($(this).attr('scroll'));
console.log(selector);
console.log(selector.offset().top);
$('html body').animate(
{scrollTop: (selector.offset().top)}, //- $(window).scrollTop()
1000
);
});
}
})(jQuery);
// RUN
jQuery(document).ready(function($) {
$().animateScroll();
});
// IN HTML EXAMPLE
// RUN ONCLICK ON OBJECT WITH ATTRIBUTE SCROLL=".SELECTOR"
// <a scroll="#product">Click To Scroll</a>
$('html, body').animate(...) does not work for me in the iPhone, Android, Chrome, or Safari browsers.
I had to target the root content element of the page.
$('#cotnent').animate(...)
Here is what I have ended up with:
if (navigator.userAgent.match(/(iPod|iPhone|iPad|Android)/)) {
$('#content').animate({
scrollTop: $("#elementtoScrollToID").offset().top
}, 'slow');
}
else{
$('html, body').animate({
scrollTop: $("#elementtoScrollToID").offset().top
}, 'slow');
}
All body content wired up with a #content div
<html>
....
<body>
<div id="content">
...
</div>
</body>
</html>
$('html, body').animate({scrollTop:
Math.min(
$(to).offset().top-margintop, //margintop is the margin above the target
$('body')[0].scrollHeight-$('body').height()) //if the target is at the bottom
}, 2000);
To show the full element (if it's possible with the current window size):
var element = $("#some_element");
var elementHeight = element.height();
var windowHeight = $(window).height();
var offset = Math.min(elementHeight, windowHeight) + element.offset().top;
$('html, body').animate({ scrollTop: offset }, 500);
var scrollTo = function($parent, $element) {
var topDiff = $element.position().top - $parent.position().top;
$parent.animate({
scrollTop : topDiff
}, 100);
};
This is Atharva's answer from: https://developer.mozilla.org/en-US/docs/Web/API/element.scrollIntoView.
Just wanted to add if your document is in an iframe, you can choose an element in the parent frame to scroll into view:
$('#element-in-parent-frame', window.parent.document).get(0).scrollIntoView();
I wrote a general purpose function that scrolls to either a jQuery object, a CSS selector, or a numeric value.
Example usage:
// scroll to "#target-element":
$.scrollTo("#target-element");
// scroll to 80 pixels above first element with class ".invalid":
$.scrollTo(".invalid", -80);
// scroll a container with id "#my-container" to 300 pixels from its top:
$.scrollTo(300, 0, "slow", "#my-container");
The function's code:
/**
* Scrolls the container to the target position minus the offset
*
* #param target - the destination to scroll to, can be a jQuery object
* jQuery selector, or numeric position
* #param offset - the offset in pixels from the target position, e.g.
* pass -80 to scroll to 80 pixels above the target
* #param speed - the scroll speed in milliseconds, or one of the
* strings "fast" or "slow". default: 500
* #param container - a jQuery object or selector for the container to
* be scrolled. default: "html, body"
*/
jQuery.scrollTo = function (target, offset, speed, container) {
if (isNaN(target)) {
if (!(target instanceof jQuery))
target = $(target);
target = parseInt(target.offset().top);
}
container = container || "html, body";
if (!(container instanceof jQuery))
container = $(container);
speed = speed || 500;
offset = offset || 0;
container.animate({
scrollTop: target + offset
}, speed);
};
When the user clicks on that input with #subject, the page should
scroll to the last element of the page with a nice animation. It
should be a scroll to bottom and not to top.
The last item of the page is a submit button with #submit
$('#subject').click(function()
{
$('#submit').focus();
$('#subject').focus();
});
This will first scroll down to #submit then restore the cursor back to the input that was clicked, which mimics a scroll down, and works on most browsers. It also doesn't require jQuery as it can be written in pure JavaScript.
Can this fashion of using focus function mimic animation in a better way, through chaining focus calls. I haven't tested this theory, but it would look something like this:
<style>
#F > *
{
width: 100%;
}
</style>
<form id="F" >
<div id="child_1"> .. </div>
<div id="child_2"> .. </div>
..
<div id="child_K"> .. </div>
</form>
<script>
$('#child_N').click(function()
{
$('#child_N').focus();
$('#child_N+1').focus();
..
$('#child_K').focus();
$('#child_N').focus();
});
</script>
I set up a module scroll-element npm install scroll-element. It works like this:
import { scrollToElement, scrollWindowToElement } from 'scroll-element'
/* scroll the window to your target element, duration and offset optional */
let targetElement = document.getElementById('my-item')
scrollWindowToElement(targetElement)
/* scroll the overflow container element to your target element, duration and offset optional */
let containerElement = document.getElementById('my-container')
let targetElement = document.getElementById('my-item')
scrollToElement(containerElement, targetElement)
Written with help from the following SO posts:
offset-top-of-an-element-without-jquery
scrolltop-animation-without-jquery
Here is the code:
export const scrollToElement = function(containerElement, targetElement, duration, offset) {
if (duration == null) { duration = 1000 }
if (offset == null) { offset = 0 }
let targetOffsetTop = getElementOffset(targetElement).top
let containerOffsetTop = getElementOffset(containerElement).top
let scrollTarget = targetOffsetTop + ( containerElement.scrollTop - containerOffsetTop)
scrollTarget += offset
scroll(containerElement, scrollTarget, duration)
}
export const scrollWindowToElement = function(targetElement, duration, offset) {
if (duration == null) { duration = 1000 }
if (offset == null) { offset = 0 }
let scrollTarget = getElementOffset(targetElement).top
scrollTarget += offset
scrollWindow(scrollTarget, duration)
}
function scroll(containerElement, scrollTarget, duration) {
let scrollStep = scrollTarget / (duration / 15)
let interval = setInterval(() => {
if ( containerElement.scrollTop < scrollTarget ) {
containerElement.scrollTop += scrollStep
} else {
clearInterval(interval)
}
},15)
}
function scrollWindow(scrollTarget, duration) {
let scrollStep = scrollTarget / (duration / 15)
let interval = setInterval(() => {
if ( window.scrollY < scrollTarget ) {
window.scrollBy( 0, scrollStep )
} else {
clearInterval(interval)
}
},15)
}
function getElementOffset(element) {
let de = document.documentElement
let box = element.getBoundingClientRect()
let top = box.top + window.pageYOffset - de.clientTop
let left = box.left + window.pageXOffset - de.clientLeft
return { top: top, left: left }
}
Updated answer as of 2019:
$('body').animate({
scrollTop: $('#subject').offset().top - $('body').offset().top + $('body').scrollTop()
}, 'fast');
ONELINER
subject.onclick = e=> window.scroll({ top: submit.offsetTop, behavior: 'smooth'});
subject.onclick = e=> window.scroll({top: submit.offsetTop, behavior: 'smooth'});
.box,.foot{display: flex;background:#fdf;padding:500px 0} .foot{padding:250px}
<input type="text" class="textfield" value="click here" id="subject" name="subject">
<div class="box">
Some content
<textarea></textarea>
</div>
<input type="submit" class="submit" id="submit" name="submit" value="Ok, Done.">
<div class="foot">Some footer</div>
For what it's worth, this is how I managed to achieve such behavior for a general element which can be inside a DIV with scrolling. In our case we don't scroll the full body, but just particular elements with overflow: auto; within a larger layout.
It creates a fake input of the height of the target element, and then puts a focus to it, and the browser will take care about the rest no matter how deep within the scrollable hierarchy you are. Works like a charm.
var $scrollTo = $('#someId'),
inputElem = $('<input type="text"></input>');
$scrollTo.prepend(inputElem);
inputElem.css({
position: 'absolute',
width: '1px',
height: $scrollTo.height()
});
inputElem.focus();
inputElem.remove();
This worked for me:
var targetOffset = $('#elementToScrollTo').offset().top;
$('#DivParent').animate({scrollTop: targetOffset}, 2500);