Having trouble getting the scroll animation to not trigger the scroll event - javascript

I currently have a number of div tags that can be seen below that are each the height of the viewport.
<!-- .current represents the div the user is currently viewing -->
<div class="full-height current" id="id1">
<div class="container">
</div>
</div>
<div class="full-height" id="id2">
<div class="container">
</div>
</div>
<div class="full-height" id="id3">
<div class="container">
</div>
</div>
<div class="full-height" id="id4">
<div class="container">
</div>
</div>
<div class="full-height" id="id5">
<div class="container">
</div>
</div>
I am attempting to implement a feature where upon a user scrolling, the window will scroll to the next div tag, always having only one div in view at a time. The way I implemented it works great, except for the fact that the animation triggers the scroll event again, resulting in an endless loop of the page scrolling once the user scrolls at all. I attempted to fix this by having a variable that will stop the event from triggering if the animation is in progress, but it does not seem to work. I am aware that I didn't do it for the scroll up, but I just wanted to see if it worked for the down first.
$(window).scroll(function(event) {
var scrollTop = $(this).scrollTop();
// If user scrolls down
if ((scrollTop > lastScrollTop) && $(".current").next("div").length > 0) {
if (animating == false) {
console.log("down");
$(".current").next("div").addClass("current");
$(".current").first().removeClass("current");
animating = true;
$("html, body").animate({
scrollTop: $(".current").offset().top
}, 1000, function() {animating = false});
}
// If user scrolls up
} else {
if ($(".current").prev("div").length > 0) {
console.log("up");
$(".current").prev("div").addClass("current");
$(".current").last().removeClass("current");
$("html, body").animate({
scrollTop: $(".current").offset().top
}, 1000);
}
}
lastScrollTop = scrollTop;
});
CSS included just in case. The 100vh - 111px is due to a fixed navbar at the top that is 111px high
/* Makes the element take up the entire height of the screen */
.full-height{
height: -o-calc(100vh - 111px); /* opera */
height: -webkit-calc(100vh - 111px); /* google, safari */
height: -moz-calc(100vh - 111px); /* firefox */
}
#id1 {
background-color: red;
}
#id2 {
background-color: blue;
}
#id3 {
background-color: yellow;
}
#id4 {
background-color: green;
}
#id5 {
background-color: purple;
}
If anyone could give me any ideas for fixing my problem, that would be great.

You'll want to stop the event and preventDefault. Here is some code from a current landing page:
$(document).ready(function () {
$('a.page-scroll').on('click', function(event) {
var link = $(this);
$('html, body').stop().animate({
scrollTop: $(link.attr('href')).offset().top - 50
}, 500);
event.preventDefault();
});
$('body').scrollspy({
target: '.navbar-fixed-top',
offset: 80
});
});
It uses bootstrap scrollspy so just ignore that. But notice that it stops any scroll animation that could be running and then also calls event.preventDefault() to stop the scroll event from bubbling and thus becoming recursive.
EDIT:
O.k. so I've a better look and the basic problem re: infinite scrolling is the code doesn't check if the scrollTop is already at 'where it needs to be'. You need an additional check to short circuit the scroll:
if (animating == false) {
if ($(this).scrollTop() == lastScrollTop) return;
if (($(this).scrollTop() > lastScrollTop) && $(".current").next("div")) {
console.log("down");
$(".current").next("div").addClass("current");
$(".current").first().removeClass("current");
animating = true;
$("html, body").stop().animate({
scrollTop: $(".current").offset().top
}, 1000,
function () { lastScrollTop = $(this).scrollTop(); animating = false; });
// If user scrolls up
} else {
if ($(".current").prev("div").length > 0) {
console.log("up");
$(".current").prev("div").addClass("current");
$(".current").last().removeClass("current");
$("html, body").stop().animate({
scrollTop: $(".current").offset().top
}, 1000, function () { lastScrollTop = $(this).scrollTop(); animating = false; });
}
}
}
Otherwise as it stands it will always either scroll up or down and never settle. That said with that "working" it's a terrible user experience. It will jump about since your scroll to code will fight the user on current scrollTop if they keep scrolling. i.e. your code will make it jump back to a previous position.

Try defining scroll event handler as named function ; defining lastScrollTop outside of scroll handler ; substituting .one() for .on() to allow animation to complete before re-attaching scroll event ; use .promise() which should be called at most once to avoid .animate() complete callback being called twice with selector "html, body" ; substituting single if to check for next or previous element .length and .animate() call for multiple if..else conditions and statements, animation function calls ; re-attach scroll event at .then() following animation completion .promise()
var lastScrollTop = 0;
function scroller(event) {
var scrollTop = $(this).scrollTop();
var direction = scrollTop > lastScrollTop ? "next" : "prev";
var el = $(".current")[direction](".full-height");
console.log(direction === "next" ? "down" : "up");
if (el.is("*")) {
$("html, body").animate({
scrollTop: el.offset().top
}, 1000).promise().then(function() {
console.log(this)
lastScrollTop = $(window).scrollTop();
$(".current")
.removeClass("current")[direction]("div")
.addClass("current")
setTimeout(function() {
$(window).one("scroll", scroller)
})
});
} else {
lastScrollTop = scrollTop;
$(window).one("scroll", scroller)
}
}
$(window).one("scroll", scroller);
/* Makes the element take up the entire height of the screen */
.full-height {
height: -o-calc(100vh - 111px);
/* opera */
height: -webkit-calc(100vh - 111px);
/* google, safari */
height: -moz-calc(100vh - 111px);
/* firefox */
}
#id1 {
background-color: red;
}
#id2 {
background-color: blue;
}
#id3 {
background-color: yellow;
}
#id4 {
background-color: green;
}
#id5 {
background-color: purple;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<!-- .current represents the div the user is currently viewing -->
<div class="full-height current" id="id1">
<div class="container">
</div>
</div>
<div class="full-height" id="id2">
<div class="container">
</div>
</div>
<div class="full-height" id="id3">
<div class="container">
</div>
</div>
<div class="full-height" id="id4">
<div class="container">
</div>
</div>
<div class="full-height" id="id5">
<div class="container">
</div>
</div>

If you define height 100vh ,scroll event wont trigger

Related

JavaScript smooth scroll not working in safari browser

I have created small menu order application, I have added 5 menu categories is Desserts, salad, thai noodles and more using horizontal scroll bar. if I click salad or any categories move left and right position working fine in chrome. I checking safari browser not working horizontal scroll. what I am missing. could you please check and let me know.
html:
<div class="menu" id="menu">
<div class="topnav sticky" id="stickyMenu"><span data-id="appetizers" id="nav1" class="cat-nav">Appetizers</span><span data-id="desserts" id="nav2" class="cat-nav">Desserts</span><span data-id="pizza--classic-11-inches-" id="nav3" class="cat-nav active">Pizza (Classic 11 inches)</span><span data-id="salad" id="nav4" class="cat-nav">Salad</span><span data-id="thai-noodles" id="nav5" class="cat-nav">Thai Noodles</span></div>
<!-- <div class="row filter">
<input type="text" id="gsearch" class="form-control gsearch" placeholder="Search within this Menu...">
</div> -->
</div>
js code:
$(document).on('click', ".topnav .cat-nav", function(e) {
$(".topnav .cat-nav").removeClass("active");
$(this).addClass("active");
var target = $(this).data("id");
$('html, body').animate({
scrollTop: ($("#"+target).offset().top - 50)
}, 500);
});
$(window).scroll(function() {
//get current sroll position
var scrollPosition = $(window).scrollTop();
//get the position of the containers
var s=["appetizers","desserts","pizza--classic-11-inches-","salad","thai-noodles"];
for (i=0; i<s.length; i++) {
if (scrollPosition >= ($("#"+s[i]).offset().top) - 190) {
$("#nav"+(i+1)).addClass("active");
$("#nav"+(i+1)).siblings().removeClass("active");
// $('.cat-nav').scrollLeft(myScrollPos);
var element = document.querySelector(".active");
element.scrollIntoView({behavior: "smooth" ,inline: "center"});
// $("#nav"+(i+1)).css({behavior: "smooth" ,inline: "center"});
}
}
});
Add overflow: auto to your sticky or topnav class:
.sticky {
overflow: none;
overflow-x: auto;
display: block;
}
This might work.

Smooth scrolling effect not working in Mozila and IE?

Smooth scrolling effect in JQuery not working in IE & Mozila Browsers, its fine in Chrome browser can any one help on this. iam using this code. some times working in mozila but in IE. please ignore stickit() function.
Thanks in Advance.
< script src = "https://ajax.googleapis.com/ajax/libs/jquery/1.10.0/jquery.min.js" > < /script> <
script src = "https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js" > < /script> <
script src = "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" > < /script> <
script src = "scroll_110.js" > < /script>
$(document).ready(function() {
// Add scrollspy to <body>
$('a').scrollspy({
target: "a",
offset: 50
});
// Add smooth scrolling on all links inside the navbar
$("a").on('click', function(event) {
// Make sure this.hash has a value before overriding default behavior
if (this.hash !== "") {
// Prevent default anchor click behavior
event.preventDefault();
// Store hash
var hash = this.hash;
// Using jQuery's animate() method to add smooth page scroll
// The optional number (800) specifies the number of milliseconds it takes to scroll to the specified area
$('body').animate({
scrollTop: $(hash).offset().top
}, 1200, function() {
// Add hash (#) to URL when done scrolling (default click behavior)
window.location.hash = hash;
});
} // End if
});
});
// Create a clone of the menu, right next to original.
jquery('.menu').addClass('original').clone().insertAfter('.menu').addClass('cloned').css('position', 'fixed').css('top', '0').css('margin-top', '0').css('z-index', '500').removeClass('original').hide();
scrollIntervalID = setInterval(stickIt, 10);
function stickIt() {
var orgElementPos = jquery('.original').offset();
orgElementTop = orgElementPos.top;
if (jquery(window).scrollTop() >= (orgElementTop)) {
// scrolled past the original position; now only show the cloned, sticky element.
// Cloned element should always have same left position and width as original element.
orgElement = jquery('.original');
coordsOrgElement = orgElement.offset();
leftOrgElement = coordsOrgElement.left;
widthOrgElement = orgElement.css('width');
jquery('.cloned').css('left', leftOrgElement + 'px').css('top', 0).css('width', widthOrgElement).show();
jquery('.original').css('visibility', 'hidden');
} else {
// not scrolled past the menu; only show the original menu.
jquery('.cloned').hide();
jquery('.original').css('visibility', 'visible');
}
}
#top,
#middle,
#bottom {
height: 1600px;
width: 900px;
background: green;
}
.menu {
background: #fffff;
color: #333;
height: 40px;
line-height: 40px;
letter-spacing: 1px;
width: 100%;
}
<div class="menu">
Top
Middle
Bottom
</div>
<div id="top">
Top</div>
<div id="middle">
Middle</div>
<div id="bottom">
Bottom</div>
the solution would be to use both html and body in JQ -> $('html,body').animate
see below ( i removed the scrollspy code as it's not relevant to this question, but you should keep it )
$(document).ready(function() {
// Add scrollspy to <body>
// Add smooth scrolling on all links inside the navbar
$("a").on('click', function(event) {
// Make sure this.hash has a value before overriding default behavior
if (this.hash !== "") {
// Prevent default anchor click behavior
event.preventDefault();
// Store hash
var hash = this.hash;
// Using jQuery's animate() method to add smooth page scroll
// The optional number (800) specifies the number of milliseconds it takes to scroll to the specified area
$('html,body').animate({
scrollTop: $(hash).offset().top
}, 1200, function() {
// Add hash (#) to URL when done scrolling (default click behavior)
window.location.hash = hash;
});
} // End if
});
});
div {
height: 500px;
width: 100%;
background: red;
border-top: 10px solid blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li>Section1</li>
<li>Section2</li>
<li>Section3</li>
</ul>
<div id ="section1">
</div>
<div id ="section2">
</div>
<div id ="section3">
</div>

Show next div on scroll Down/Up

First I use an library to animate going from #one to #two with this code:
$(function() {
$('a.page-scroll').bind('click', function(event) {
var $anchor = $(this);
$('html, body').stop().animate({
scrollTop: $($anchor.attr('href')).offset().top
}, 1500, 'easeInOutExpo');
event.preventDefault();
});
});
my html is:
<div id="indicators">
<a href="#one" class="btn page-scroll" style="border-radius: 50%;"><i class="fa fa-circle" aria-hidden="true"></i>
</a>
<a href="#two" class="btn page-scroll"><i class="fa fa-circle" aria-hidden="true"></i>
</a>
<a href="#three" class="btn page-scroll"><i class="fa fa-circle" aria-hidden="true"></i>
</a>
</div>
so now when I click on some indicator (circle icon) send me with animation to there div but what I want to do now is when user have focus on some div and when scroll down to show to them new #id with animation...
etc. user have focus in #two and when scroll down a little to show them #three with animation ...
var lastScrollTop = 0;
$(window).scroll(function(event){
var st = $(this).scrollTop();
if (st > lastScrollTop){
//down
} else {
// up
}
lastScrollTop = st;
});
How to find on which div user make scroll? Also what I need to do is like on this website: http://hotelgene.com/
I think it is not the question about how to find user is looking at which page.
Just make sure no matter how many times user scrolling, the scroll-height always keep in the right position. You just listen to the mouse event, if user scroll down too much, they will scroll up again.
Try this
$(document).scroll(function() {
var y = $(this).scrollTop();
//200 is the total height of divs before div with animation enters viewport
if (y > 200) {
$('.three').addClass("animation");
} else {
$('.three').removeClass("animation");
}
.one {
height: 100px;
}
.two {
height: 100px;
}
.three {
height: 100px;
}
.animation {
transition: all ease-in 0.2s /* or any transition you choose*/
}
<div class="one"></div>
<div class="two"></div>
<div class="three"></div>
This should help you out.

Temporarily disable scroll at position/element with JS

I'm trying to find a way to lock the scroll at at a specified height or element for a certain amount of scrolls.
So in this plnkr I want it to stop on the second slide for 2-3 scrolls, and then proceed.
http://plnkr.co/edit/BAlFMLBhzVaqWuwhGCu8?p=preview
<div class="slide s1">S.O. made me include some code with plnkr link</div>
<div class="slide s2">Title 2</div>
<div class="slide s3">Title 3</div>
I've tried the following:
How to disable scrolling temporarily?
But if the user scrolls fast enough, they can scroll past the title.
I imagine this is because the UI thread is busy, and then when the JS finally kicks in, the title in the slide is out of view.
A good working example of what I'm looking for is here (on the second slide): http://journey.lifeofpimovie.com/
How does one achieve this effect?
I think link you have added is using some personal javascript plugins , it doesn't disable scrolling temporarily . I'm not familiar with these plugins but you can search for scrolling webpages plugins like this one : http://alvarotrigo.com/fullPage/
it has some Examples like this one and some others you can try .
Try
var $w = $(window);
var $slides = $('.slide');
$.fx.interval = -100;
var scrollTiles = function scrollTiles(e) {
var el = $slides.filter(function (i, el) {
return el.getBoundingClientRect().bottom >
parseInt($(el).css("height")) + 10
}),
// select second tile
tileId = el.prev().is($slides)
? el.prev().index()
: $slides.eq(-1).index();
// do stuff at second tile
if (tileId === 2) {
$slides.not(":eq(" + (tileId - 1) + ")")
.hide(0, function () {
$w.off("scroll.tiles");
$(this).queue("tiles", function () {
$(this).show(0)
})
// delay scroll three seconds
}).delay(3000)
.dequeue("tiles")
.promise()
.done(function (elems) {
// after three second delay ,
// scroll to third tile
$("body").animate({
scrollTop: elems.eq(-1).offset().top
}, 500, "linear", function () {
// prevent delay at second tile
// until after scroll to first tile from third tile ,
// reset `scroll.tiles` event
$w.on("scroll.t", function (e) {
if (elems.eq(0)[0].getBoundingClientRect().bottom >
elems.eq(0).height()) {
$(this).off("scroll.t")
.on("scroll.tiles", scrollTiles)
}
})
})
})
}
};
$w.on("scroll.tiles", scrollTiles);
/* Styles go here */
html,
body {
height: 100%;
}
.slide {
height: 100%;
}
.s1 {
background: red;
}
.s2 {
background: orange;
}
.s3 {
background: yellow;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<body>
<div class="slide s1">Title 1</div>
<div class="slide s2">Title 2</div>
<div class="slide s3">Title 3</div>
</body>

How to scroll to an element inside a div?

I have a scrolled div and I want to have an event when I click on it, it will force this div to scroll to view an element inside.
I wrote its JavasSript like this:
document.getElementById(chr).scrollIntoView(true);
but this scrolls all the page while scrolling the div itself.
How to fix that?
I want to say it like this:
MyContainerDiv.getElementById(chr).scrollIntoView(true);
You need to get the top offset of the element you'd like to scroll into view, relative to its parent (the scrolling div container):
var myElement = document.getElementById('element_within_div');
var topPos = myElement.offsetTop;
The variable topPos is now set to the distance between the top of the scrolling div and the element you wish to have visible (in pixels).
Now we tell the div to scroll to that position using scrollTop:
document.getElementById('scrolling_div').scrollTop = topPos;
If you're using the prototype JS framework, you'd do the same thing like this:
var posArray = $('element_within_div').positionedOffset();
$('scrolling_div').scrollTop = posArray[1];
Again, this will scroll the div so that the element you wish to see is exactly at the top (or if that's not possible, scrolled as far down as it can so it's visible).
You would have to find the position of the element in the DIV you want to scroll to, and set the scrollTop property.
divElem.scrollTop = 0;
Update:
Sample code to move up or down
function move_up() {
document.getElementById('divElem').scrollTop += 10;
}
function move_down() {
document.getElementById('divElem').scrollTop -= 10;
}
Method 1 - Smooth scrolling to an element inside an element
var box = document.querySelector('.box'),
targetElm = document.querySelector('.boxChild'); // <-- Scroll to here within ".box"
document.querySelector('button').addEventListener('click', function(){
scrollToElm( box, targetElm , 600 );
});
/////////////
function scrollToElm(container, elm, duration){
var pos = getRelativePos(elm);
scrollTo( container, pos.top , 2); // duration in seconds
}
function getRelativePos(elm){
var pPos = elm.parentNode.getBoundingClientRect(), // parent pos
cPos = elm.getBoundingClientRect(), // target pos
pos = {};
pos.top = cPos.top - pPos.top + elm.parentNode.scrollTop,
pos.right = cPos.right - pPos.right,
pos.bottom = cPos.bottom - pPos.bottom,
pos.left = cPos.left - pPos.left;
return pos;
}
function scrollTo(element, to, duration, onDone) {
var start = element.scrollTop,
change = to - start,
startTime = performance.now(),
val, now, elapsed, t;
function animateScroll(){
now = performance.now();
elapsed = (now - startTime)/1000;
t = (elapsed/duration);
element.scrollTop = start + change * easeInOutQuad(t);
if( t < 1 )
window.requestAnimationFrame(animateScroll);
else
onDone && onDone();
};
animateScroll();
}
function easeInOutQuad(t){ return t<.5 ? 2*t*t : -1+(4-2*t)*t };
.box{ width:80%; border:2px dashed; height:180px; overflow:auto; }
.boxChild{
margin:600px 0 300px;
width: 40px;
height:40px;
background:green;
}
<button>Scroll to element</button>
<div class='box'>
<div class='boxChild'></div>
</div>
Method 2 - Using Element.scrollIntoView:
Note that browser support isn't great for this one
var targetElm = document.querySelector('.boxChild'), // reference to scroll target
button = document.querySelector('button'); // button that triggers the scroll
// bind "click" event to a button
button.addEventListener('click', function(){
targetElm.scrollIntoView()
})
.box {
width: 80%;
border: 2px dashed;
height: 180px;
overflow: auto;
scroll-behavior: smooth; /* <-- for smooth scroll */
}
.boxChild {
margin: 600px 0 300px;
width: 40px;
height: 40px;
background: green;
}
<button>Scroll to element</button>
<div class='box'>
<div class='boxChild'></div>
</div>
Method 3 - Using CSS scroll-behavior:
.box {
width: 80%;
border: 2px dashed;
height: 180px;
overflow-y: scroll;
scroll-behavior: smooth; /* <--- */
}
#boxChild {
margin: 600px 0 300px;
width: 40px;
height: 40px;
background: green;
}
<a href='#boxChild'>Scroll to element</a>
<div class='box'>
<div id='boxChild'></div>
</div>
Native JS, Cross Browser, Smooth Scroll (Update 2020)
Setting ScrollTop does give the desired result but the scroll is very abrupt. Using jquery to have smooth scroll was not an option. So here's a native way to get the job done that supports all major browsers. Reference - caniuse
// get the "Div" inside which you wish to scroll (i.e. the container element)
const El = document.getElementById('xyz');
// Lets say you wish to scroll by 100px,
El.scrollTo({top: 100, behavior: 'smooth'});
// If you wish to scroll until the end of the container
El.scrollTo({top: El.scrollHeight, behavior: 'smooth'});
That's it!
And here's a working snippet for the doubtful -
document.getElementById('btn').addEventListener('click', e => {
e.preventDefault();
// smooth scroll
document.getElementById('container').scrollTo({top: 175, behavior: 'smooth'});
});
/* just some styling for you to ignore */
.scrollContainer {
overflow-y: auto;
max-height: 100px;
position: relative;
border: 1px solid red;
width: 120px;
}
body {
padding: 10px;
}
.box {
margin: 5px;
background-color: yellow;
height: 25px;
display: flex;
align-items: center;
justify-content: center;
}
#goose {
background-color: lime;
}
<!-- Dummy html to be ignored -->
<div id="container" class="scrollContainer">
<div class="box">duck</div>
<div class="box">duck</div>
<div class="box">duck</div>
<div class="box">duck</div>
<div class="box">duck</div>
<div class="box">duck</div>
<div class="box">duck</div>
<div class="box">duck</div>
<div id="goose" class="box">goose</div>
<div class="box">duck</div>
<div class="box">duck</div>
<div class="box">duck</div>
<div class="box">duck</div>
</div>
<button id="btn">goose</button>
Update: As you can perceive in the comments, it seems that Element.scrollTo() is not supported in IE11. So if you don't care about IE11 (you really shouldn't, Microsoft is retiring IE11 in June 2022), feel free to use this in all your projects. Note that support exists for Edge! So you're not really leaving your Edge/Windows users behind ;)
Reference
To scroll an element into view of a div, only if needed, you can use this scrollIfNeeded function:
function scrollIfNeeded(element, container) {
if (element.offsetTop < container.scrollTop) {
container.scrollTop = element.offsetTop;
} else {
const offsetBottom = element.offsetTop + element.offsetHeight;
const scrollBottom = container.scrollTop + container.offsetHeight;
if (offsetBottom > scrollBottom) {
container.scrollTop = offsetBottom - container.offsetHeight;
}
}
}
document.getElementById('btn').addEventListener('click', ev => {
ev.preventDefault();
scrollIfNeeded(document.getElementById('goose'), document.getElementById('container'));
});
.scrollContainer {
overflow-y: auto;
max-height: 100px;
position: relative;
border: 1px solid red;
width: 120px;
}
body {
padding: 10px;
}
.box {
margin: 5px;
background-color: yellow;
height: 25px;
display: flex;
align-items: center;
justify-content: center;
}
#goose {
background-color: lime;
}
<div id="container" class="scrollContainer">
<div class="box">duck</div>
<div class="box">duck</div>
<div class="box">duck</div>
<div class="box">duck</div>
<div class="box">duck</div>
<div class="box">duck</div>
<div class="box">duck</div>
<div class="box">duck</div>
<div id="goose" class="box">goose</div>
<div class="box">duck</div>
<div class="box">duck</div>
<div class="box">duck</div>
<div class="box">duck</div>
</div>
<button id="btn">scroll to goose</button>
Code should be:
var divElem = document.getElementById('scrolling_div');
var chElem = document.getElementById('element_within_div');
var topPos = divElem.offsetTop;
divElem.scrollTop = topPos - chElem.offsetTop;
You want to scroll the difference between child top position and div's top position.
Get access to child elements using:
var divElem = document.getElementById('scrolling_div');
var numChildren = divElem.childNodes.length;
and so on....
If you are using jQuery, you could scroll with an animation using the following:
$(MyContainerDiv).animate({scrollTop: $(MyContainerDiv).scrollTop() + ($('element_within_div').offset().top - $(MyContainerDiv).offset().top)});
The animation is optional: you could also take the scrollTop value calculated above and put it directly in the container's scrollTop property.
We can resolve this problem without using JQuery and other libs.
I wrote following code for this purpose:
You have similar structure ->
<div class="parent">
<div class="child-one">
</div>
<div class="child-two">
</div>
</div>
JS:
scrollToElement() {
var parentElement = document.querySelector('.parent');
var childElement = document.querySelector('.child-two');
parentElement.scrollTop = childElement.offsetTop - parentElement.offsetTop;
}
We can easily rewrite this method for passing parent and child as an arguments
Another example of using jQuery and animate.
var container = $('#container');
var element = $('#element');
container.animate({
scrollTop: container.scrollTop = container.scrollTop() + element.offset().top - container.offset().top
}, {
duration: 1000,
specialEasing: {
width: 'linear',
height: 'easeOutBounce'
},
complete: function (e) {
console.log("animation completed");
}
});
None of other answer fixed my issue.
I played around with scrollIntoView arguments and managed to found a solution. Setting inline to start and block to nearest prevents parent element (or entire page) to scroll:
document.getElementById(chr).scrollIntoView({
behavior: 'smooth',
block: 'nearest',
inline: 'start'
});
There are two facts :
1) Component scrollIntoView is not supported by safari.
2) JS framework jQuery can do the job like this:
parent = 'some parent div has css position==="fixed"' || 'html, body';
$(parent).animate({scrollTop: $(child).offset().top}, duration)
Here's a simple pure JavaScript solution that works for a target Number (value for scrollTop), target DOM element, or some special String cases:
/**
* target - target to scroll to (DOM element, scrollTop Number, 'top', or 'bottom'
* containerEl - DOM element for the container with scrollbars
*/
var scrollToTarget = function(target, containerEl) {
// Moved up here for readability:
var isElement = target && target.nodeType === 1,
isNumber = Object.prototype.toString.call(target) === '[object Number]';
if (isElement) {
containerEl.scrollTop = target.offsetTop;
} else if (isNumber) {
containerEl.scrollTop = target;
} else if (target === 'bottom') {
containerEl.scrollTop = containerEl.scrollHeight - containerEl.offsetHeight;
} else if (target === 'top') {
containerEl.scrollTop = 0;
}
};
And here are some examples of usage:
// Scroll to the top
var scrollableDiv = document.getElementById('scrollable_div');
scrollToTarget('top', scrollableDiv);
or
// Scroll to 200px from the top
var scrollableDiv = document.getElementById('scrollable_div');
scrollToTarget(200, scrollableDiv);
or
// Scroll to targetElement
var scrollableDiv = document.getElementById('scrollable_div');
var targetElement= document.getElementById('target_element');
scrollToTarget(targetElement, scrollableDiv);
given you have a div element you need to scroll inside, try this piece of code
document.querySelector('div').scroll(x,y)
this works with me inside a div with a scroll, this should work with you in case you pointed the mouse over this element and then tried to scroll down or up. If it manually works, it should work too
User Animated Scrolling
Here's an example of how to programmatically scroll a <div> horizontally, without JQuery. To scroll vertically, you would replace JavaScript's writes to scrollLeft with scrollTop, instead.
JSFiddle
https://jsfiddle.net/fNPvf/38536/
HTML
<!-- Left Button. -->
<div style="float:left;">
<!-- (1) Whilst it's pressed, increment the scroll. When we release, clear the timer to stop recursive scroll calls. -->
<input type="button" value="«" style="height: 100px;" onmousedown="scroll('scroller',3, 10);" onmouseup="clearTimeout(TIMER_SCROLL);"/>
</div>
<!-- Contents to scroll. -->
<div id="scroller" style="float: left; width: 100px; height: 100px; overflow: hidden;">
<!-- <3 -->
<img src="https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-logo.png?v=9c558ec15d8a" alt="image large" style="height: 100px" />
</div>
<!-- Right Button. -->
<div style="float:left;">
<!-- As (1). (Use a negative value of 'd' to decrease the scroll.) -->
<input type="button" value="»" style="height: 100px;" onmousedown="scroll('scroller',-3, 10);" onmouseup="clearTimeout(TIMER_SCROLL);"/>
</div>
JavaScript
// Declare the Shared Timer.
var TIMER_SCROLL;
/**
Scroll function.
#param id Unique id of element to scroll.
#param d Amount of pixels to scroll per sleep.
#param del Size of the sleep (ms).*/
function scroll(id, d, del){
// Scroll the element.
document.getElementById(id).scrollLeft += d;
// Perform a delay before recursing this function again.
TIMER_SCROLL = setTimeout("scroll('"+id+"',"+d+", "+del+");", del);
}
Credit to Dux.
Auto Animated Scrolling
In addition, here are functions for scrolling a <div> fully to the left and right. The only thing we change here is we make a check to see if the full extension of the scroll has been utilised before making a recursive call to scroll again.
JSFiddle
https://jsfiddle.net/0nLc2fhh/1/
HTML
<!-- Left Button. -->
<div style="float:left;">
<!-- (1) Whilst it's pressed, increment the scroll. When we release, clear the timer to stop recursive scroll calls. -->
<input type="button" value="«" style="height: 100px;" onclick="scrollFullyLeft('scroller',3, 10);"/>
</div>
<!-- Contents to scroll. -->
<div id="scroller" style="float: left; width: 100px; height: 100px; overflow: hidden;">
<!-- <3 -->
<img src="https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-logo.png?v=9c558ec15d8a" alt="image large" style="height: 100px" />
</div>
<!-- Right Button. -->
<div style="float:left;">
<!-- As (1). (Use a negative value of 'd' to decrease the scroll.) -->
<input type="button" value="»" style="height: 100px;" onclick="scrollFullyRight('scroller',3, 10);"/>
</div>
JavaScript
// Declare the Shared Timer.
var TIMER_SCROLL;
/**
Scroll fully left function; completely scrolls a <div> to the left, as far as it will go.
#param id Unique id of element to scroll.
#param d Amount of pixels to scroll per sleep.
#param del Size of the sleep (ms).*/
function scrollFullyLeft(id, d, del){
// Fetch the element.
var el = document.getElementById(id);
// Scroll the element.
el.scrollLeft += d;
// Have we not finished scrolling yet?
if(el.scrollLeft < (el.scrollWidth - el.clientWidth)) {
TIMER_SCROLL = setTimeout("scrollFullyLeft('"+id+"',"+d+", "+del+");", del);
}
}
/**
Scroll fully right function; completely scrolls a <div> to the right, as far as it will go.
#param id Unique id of element to scroll.
#param d Amount of pixels to scroll per sleep.
#param del Size of the sleep (ms).*/
function scrollFullyRight(id, d, del){
// Fetch the element.
var el = document.getElementById(id);
// Scroll the element.
el.scrollLeft -= d;
// Have we not finished scrolling yet?
if(el.scrollLeft > 0) {
TIMER_SCROLL = setTimeout("scrollFullyRight('"+id+"',"+d+", "+del+");", del);
}
}
This is what has finally served me
/** Set parent scroll to show element
* #param element {object} The HTML object to show
* #param parent {object} The HTML object where the element is shown */
var scrollToView = function(element, parent) {
//Algorithm: Accumulate the height of the previous elements and add half the height of the parent
var offsetAccumulator = 0;
parent = $(parent);
parent.children().each(function() {
if(this == element) {
return false; //brake each loop
}
offsetAccumulator += $(this).innerHeight();
});
parent.scrollTop(offsetAccumulator - parent.innerHeight()/2);
}
I needed to scroll a dynamically loading element on a page so my solution was a little more involved.
This will work on static elements that are not lazy loading data and data being dynamically loaded.
const smoothScrollElement = async (selector: string, scrollBy = 12, prevCurrPos = 0) => {
const wait = (timeout: number) => new Promise(resolve => setTimeout(resolve, timeout));
const el = document.querySelector(selector) as HTMLElement;
let positionToScrollTo = el.scrollHeight;
let currentPosition = Math.floor(el.scrollTop) || 0;
let pageYOffset = (el.clientHeight + currentPosition);
if (positionToScrollTo == pageYOffset) {
await wait(1000);
}
if ((prevCurrPos > 0 && currentPosition <= prevCurrPos) !== true) {
setTimeout(async () => {
el.scrollBy(0, scrollBy);
await smoothScrollElement(selector, scrollBy, currentPosition);
}, scrollBy);
}
};
browser does scrolling automatically to an element that gets focus, so what you can also do it to wrap the element that you need to be scrolled to into <a>...</a> and then when you need scroll just set the focus on that a

Categories

Resources