I'm trying to create a button that scrolls to a particular element that is further down on the page. I have managed to create a function that allows me to scroll to the top offset of the item like this:
const scrollToIntro = () => {
const viewPortOffSet = window.document
.getElementById("introduction")
.getBoundingClientRect();
window.scrollTo({
top: viewPortOffSet.top + window.scrollY,
behavior: "smooth",
});
};
However, I find that scrolling to the top to be a little too much in the sense that have scrolled too far down and would like to subtract some value from top relative to the viewport. One way I've found is to multiply the number by a factor like this:
const scrollToIntro = () => {
const viewPortOffSet = window.document
.getElementById("introduction")
.getBoundingClientRect();
window.scrollTo({
top: viewPortOffSet.top * 0.95 + window.scrollY,
behavior: "smooth",
});
};
But I am wondering if there are alternatives that can maybe involve subtraction of values using "vh" etc.
I want page to scroll up gently when modal opens opens. But it is not working as expected. Instead, the scrollbar is moving abruptly upward. Am I doing anything wrong here ?
ScrollingSteps() {
console.log(window.pageYOffset);/* This is giving me 0, even when scroll
bar is not on the top. Why is it showing this strange behavior ? */
if (window.pageYOffset === 0) {
clearInterval(this.state.intervalId);
}
window.scroll(0, window.pageYOffset - 5);// It is showing abrupt change
console.log(document.body.scrollTop,document.body.style.top)/*Even these 2 are 0 here. Don't understand why!*/
}
ScrollingToTop() {
let myID = setInterval(this.ScrollingSteps.bind(this), 5);
}
with window.scrollTo you can make use of behavior prop adn provide value smooth
window.scrollTo({
top: 0,
left: window.pageYOffset - 5,
behavior: 'smooth',
})
see here for details:
https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo
My ASP.Net application generates an <asp:Table> from the codebehind. What I need is for the header row of that table to slide down the page as the user scrolls past it.
I've tried the following approach using JavaScript:
window.onscroll = function () {
//grab the current scroll position
var scrollY = document.body.scrollTop;
if (scrollY == 0) {
if (window.pageYOffset)
scrollY = window.pageYOffset;
else
scrollY = (document.body.parentElement) ? document.body.parentElement.scrollTop : 0;
}
//grab the position of the header row I want to slide
var head = $("tr[name='headerrow']").offset();
var headtop = head.top;
var headleft = head.left;
//if the user has scrolled past the top of the header row
if (scrollY > headtop) {
//code correctly reaches this point as alerts show
//alert('got here');
//position the header row to the same as the scroll position
$("tr[name='headerrow']").offset({ top: scrollY, left: headleft });
}
}
I can't get the row to move. There are no error message to be seen on the various browsers developer tools.
Any help would be appreciated.
EDIT: I tried calling the offset() function on the children of the row (i.e. all of the <th> elements) like this:
$("tr[name='headerrow']").children().offset({ top: scrollY, left: headleft });
This now works but of course, they're all pushed over to the left because I'm using the left value of the header row itself... I'll keep this updated with my progress but in the meantime any assistance is appreciated as always.
Solution:
Use the children() method on the table row to allow you to change the offset of each of the <th> elements. The left value can be omitted from the offset() method, i.e.
$("tr[name='headerrow']").children().offset({ top: scrollY });
You cannot set the offset to any element. You should use css method and set the top and left parameters.
I have an HTML document with images in a grid format using <ul><li><img.... The browser window has both vertical & horizontal scrolling.
Question:
When I click on an image <img>, how then do I get the whole document to scroll to a position where the image I just clicked on is top:20px; left:20px ?
I've had a browse on here for similar posts...although I'm quite new to JavaScript, and want to understand how this is achieved for myself.
There's a DOM method called scrollIntoView, which is supported by all major browsers, that will align an element with the top/left of the viewport (or as close as possible).
$("#myImage")[0].scrollIntoView();
On supported browsers, you can provide options:
$("#myImage")[0].scrollIntoView({
behavior: "smooth", // or "auto" or "instant"
block: "start" // or "end"
});
Alternatively, if all the elements have unique IDs, you can just change the hash property of the location object for back/forward button support:
$(document).delegate("img", function (e) {
if (e.target.id)
window.location.hash = e.target.id;
});
After that, just adjust the scrollTop/scrollLeft properties by -20:
document.body.scrollLeft -= 20;
document.body.scrollTop -= 20;
Since you want to know how it works, I'll explain it step-by-step.
First you want to bind a function as the image's click handler:
$('#someImage').click(function () {
// Code to do scrolling happens here
});
That will apply the click handler to an image with id="someImage". If you want to do this to all images, replace '#someImage' with 'img'.
Now for the actual scrolling code:
Get the image offsets (relative to the document):
var offset = $(this).offset(); // Contains .top and .left
Subtract 20 from top and left:
offset.left -= 20;
offset.top -= 20;
Now animate the scroll-top and scroll-left CSS properties of <body> and <html>:
$('html, body').animate({
scrollTop: offset.top,
scrollLeft: offset.left
});
Simplest solution I have seen
var offset = $("#target-element").offset();
$('html, body').animate({
scrollTop: offset.top,
scrollLeft: offset.left
}, 1000);
Tutorial Here
There are methods to scroll element directly into the view, but if you want to scroll to a point relative from an element, you have to do it manually:
Inside the click handler, get the position of the element relative to the document, subtract 20 and use window.scrollTo:
var pos = $(this).offset();
var top = pos.top - 20;
var left = pos.left - 20;
window.scrollTo((left < 0 ? 0 : left), (top < 0 ? 0 : top));
Have a look at the jQuery.scrollTo plugin. Here's a demo.
This plugin has a lot of options that go beyond what native scrollIntoView offers you. For instance, you can set the scrolling to be smooth, and then set a callback for when the scrolling finishes.
You can also have a look at all the JQuery plugins tagged with "scroll".
Here's a quick jQuery plugin to map the built in browser functionality nicely:
$.fn.ensureVisible = function () { $(this).each(function () { $(this)[0].scrollIntoView(); }); };
...
$('.my-elements').ensureVisible();
After trial and error I came up with this function, works with iframe too.
function bringElIntoView(el) {
var elOffset = el.offset();
var $window = $(window);
var windowScrollBottom = $window.scrollTop() + $window.height();
var scrollToPos = -1;
if (elOffset.top < $window.scrollTop()) // element is hidden in the top
scrollToPos = elOffset.top;
else if (elOffset.top + el.height() > windowScrollBottom) // element is hidden in the bottom
scrollToPos = $window.scrollTop() + (elOffset.top + el.height() - windowScrollBottom);
if (scrollToPos !== -1)
$('html, body').animate({ scrollTop: scrollToPos });
}
My UI has a vertical scrolling list of thumbs within a thumbbar
The goal was to make the current thumb right in the center of the thumbbar.
I started from the approved answer, but found that there were a few tweaks to truly center the current thumb. hope this helps someone else.
markup:
<ul id='thumbbar'>
<li id='thumbbar-123'></li>
<li id='thumbbar-124'></li>
<li id='thumbbar-125'></li>
</ul>
jquery:
// scroll the current thumb bar thumb into view
heightbar = $('#thumbbar').height();
heightthumb = $('#thumbbar-' + pageid).height();
offsetbar = $('#thumbbar').scrollTop();
$('#thumbbar').animate({
scrollTop: offsetthumb.top - heightbar / 2 - offsetbar - 20
});
Just a tip. Works on firefox only
Element.scrollIntoView();
Simple 2 steps for scrolling down to end or bottom.
Step1: get the full height of scrollable(conversation) div.
Step2: apply scrollTop on that scrollable(conversation) div using the value
obtained in step1.
var fullHeight = $('#conversation')[0].scrollHeight;
$('#conversation').scrollTop(fullHeight);
Above steps must be applied for every append on the conversation div.
After trying to find a solution that handled every circumstance (options for animating the scroll, padding around the object once it scrolls into view, works even in obscure circumstances such as in an iframe), I finally ended up writing my own solution to this. Since it seems to work when many other solutions failed, I thought I'd share it:
function scrollIntoViewIfNeeded($target, options) {
var options = options ? options : {},
$win = $($target[0].ownerDocument.defaultView), //get the window object of the $target, don't use "window" because the element could possibly be in a different iframe than the one calling the function
$container = options.$container ? options.$container : $win,
padding = options.padding ? options.padding : 20,
elemTop = $target.offset().top,
elemHeight = $target.outerHeight(),
containerTop = $container.scrollTop(),
//Everything past this point is used only to get the container's visible height, which is needed to do this accurately
containerHeight = $container.outerHeight(),
winTop = $win.scrollTop(),
winBot = winTop + $win.height(),
containerVisibleTop = containerTop < winTop ? winTop : containerTop,
containerVisibleBottom = containerTop + containerHeight > winBot ? winBot : containerTop + containerHeight,
containerVisibleHeight = containerVisibleBottom - containerVisibleTop;
if (elemTop < containerTop) {
//scroll up
if (options.instant) {
$container.scrollTop(elemTop - padding);
} else {
$container.animate({scrollTop: elemTop - padding}, options.animationOptions);
}
} else if (elemTop + elemHeight > containerTop + containerVisibleHeight) {
//scroll down
if (options.instant) {
$container.scrollTop(elemTop + elemHeight - containerVisibleHeight + padding);
} else {
$container.animate({scrollTop: elemTop + elemHeight - containerVisibleHeight + padding}, options.animationOptions);
}
}
}
$target is a jQuery object containing the object you wish to scroll into view if needed.
options (optional) can contain the following options passed in an object:
options.$container - a jQuery object pointing to the containing element of $target (in other words, the element in the dom with the scrollbars). Defaults to the window that contains the $target element and is smart enough to select an iframe window. Remember to include the $ in the property name.
options.padding - the padding in pixels to add above or below the object when it is scrolled into view. This way it is not right against the edge of the window. Defaults to 20.
options.instant - if set to true, jQuery animate will not be used and the scroll will instantly pop to the correct location. Defaults to false.
options.animationOptions - any jQuery options you wish to pass to the jQuery animate function (see http://api.jquery.com/animate/). With this, you can change the duration of the animation or have a callback function executed when the scrolling is complete. This only works if options.instant is set to false. If you need to have an instant animation but with a callback, set options.animationOptions.duration = 0 instead of using options.instant = true.
How can I get and set the current web page scroll position?
I have a long form which needs to be refreshed based on user actions/input. When this happens, the page resets to the very top, which is annoying to the users, because they have to scroll back down to the point they were at.
If I could capture the current scroll position (in a hidden input) before the page reloads, I could then set it back after it reloads.
The currently accepted answer is incorrect - document.documentElement.scrollTop always returns 0 on Chrome. This is because WebKit uses body for keeping track of scrolling, whereas Firefox and IE use html.
To get the current position, you want:
document.documentElement.scrollTop || document.body.scrollTop
You can set the current position to 1000px down the page like so:
document.documentElement.scrollTop = document.body.scrollTop = 1000;
Or, using jQuery (animate it while you're at it!):
$("html, body").animate({ scrollTop: "1000px" });
You're looking for the document.documentElement.scrollTop property.
Update 2021: browsers inconsistencies with scrollTop seem to have disappeared.
There are some inconsistencies in how browsers expose the current window scrolling coordinates. Google Chrome on Mac and iOS seems to always return 0 when using document.documentElement.scrollTop or jQuery's $(window).scrollTop().
However, it works consistently with:
// horizontal scrolling amount
window.pageXOffset
// vertical scrolling amount
window.pageYOffset
I went with the HTML5 local storage solution... All my links call a function which sets this before changing window.location:
localStorage.topper = document.body.scrollTop;
and each page has this in the body's onLoad:
if(localStorage.topper > 0){
window.scrollTo(0,localStorage.topper);
}
this will give you the px value of scroll from top
document.documentElement.scrollTop
Nowadays it seems like the get is working with: window.scrollX and window.scrollY. This could be an alternative way to solve it.
var stop = true;
addEventListener('drag', (event) => {
if (event.clientY < 150) {
stop = false;
scroll(-1)
}
if (event.clientY > ($(window).height() - 150)) {
stop = false;
scroll(1)
}
if (document.body.getBoundingClientRect().y === 0){
stop = true;
}
if ((window.innerHeight + window.scrollY) >= document.body.scrollHeight) {
stop = true;
}
});
addEventListener('dragend', (event) => {
stop = true;
});
var scroll = function (step) {
var scrollY = $(window).scrollTop();
$(window).scrollTop(scrollY + step);
if (!stop) {
setTimeout(function () { scroll(step) }, 20);
}
}
Now you can also use window.scrollTo({ top: 0, behavior: 'smooth' }); instead of using that jQuery solution above for the animation. Here is the documentation: https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo