Why does window.scrollTo() require setTimeout() in order to work? - javascript

Here's an HTML page that displays three square divs in the upper left corner:
window.addEventListener('load', function () {
console.log('load event has fired')
window.scrollTo(500, 0);
// setTimeout(function() { window.scrollTo(500, 0); }, 0);
})
body { height: 100vh }
.bigwidth {
width: 2000px;
display: block;
}
.square {
width: 100px;
height: 100px;
display: block;
position: absolute;
}
.greenish {
background-color: #75af99;
}
.redish {
background-color: #ff9b98;
}
.bluish {
background-color: #aabbff;
}
.whiteish {
background-color: #eaeaea;
}
* {
padding: 0;
margin: 0;
}
<div class="whiteish bigwidth" style="height:100%;">
<div class="square greenish" style="left:50px; top:50px;"></div>
<div class="square redish" style="left:70px; top:70px;"></div>
<div class="square bluish" style="left:90px; top:90px;"></div>
</div>
Right now the window.scrollTo(500, 0); command that occurs on page load has no effect (tested in safari and Chrome). But if we replace it instead by the line
setTimeout(function() { window.scrollTo(500, 0); }, 0);
(commented out in the above code), the scroll does happen. Why is this?

Related

Show/hide div or image when scrolling

Is there a way to show an image or a div when scrolling down a web page and hide it when not scrolling and vice versa?
So in the code below the red div would be displayed when not scrolling, and the green div would be displayed only when scrolling.
.square {
position: fixed;
width: 100px;
height: 100px;
}
.green {
background: green;
display: none;
}
.red {
background: red;
}
.container {
width: 100%;
height: 3000px;
}
<div class="container">
<div class="square green"></div>
<div class="square red"></div>
</div>
The end goal is to achieve something like this: https://mailchimp.com/annual-report/ where the character appears to be walking when the user scrolls, and stands still when the user stops. Is this easily achievable?
You just need an eventListener that listen to a scroll event. However this has the issue that it only recoginze when you scroll but not when you stop scrolling. For that you can use this answer that explains how to listen for a "scroll-stop"
To make the code shorter and easier, I removed your display: none from the green box. I added a new class d-none that contains this proeprty now instead. By default it is added to the green box.
With classList.toggle('d-none') I can toggle class within both boxes which makes it easier then to address and then add or remove the class for every box on its own.
var timer = null;
var box = document.querySelectorAll('.square');
window.addEventListener('scroll', function() {
if (timer !== null) {
clearTimeout(timer);
} else {
box.forEach(el => el.classList.toggle('d-none'));
}
timer = setTimeout(function() {
box.forEach(el => el.classList.toggle('d-none'));
}, 150);
}, false);
.d-none {
display: none;
}
.square {
position: fixed;
width: 100px;
height: 100px;
}
.green {
background: green;
/* display: none; */
/* removed */
}
.red {
background: red;
}
.container {
width: 100%;
height: 3000px;
}
<div class="container">
<div class="square green d-none"></div>
<div class="square red"></div>
</div>
You just need a setTimeout function:
(function($) {
$(function() {
$(window).scroll(function() {
$('.square.red').show()
$('.square.green').hide()
clearTimeout($.data(this));
$.data(this, setTimeout(function() {
$('.square.red').hide()
$('.square.green').show()
}, 250));
});
});
})(jQuery);
.square {
position: fixed;
width: 100px;
height: 100px;
}
.green {
background: green;
}
.red {
background: red;
display: none;
}
.container {
width: 100%;
height: 3000px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="square green"></div>
<div class="square red"></div>
</div>

animate to right on scroll down and animate back to the left on scroll up

I'm trying to do an animation on page scroll where selected element will animate from left to right on scroll down and if back to top then animate the selected element from right to left (default position), here's what I tried
$(document).ready(function() {
$(window).scroll(function() {
var wS = $(this).scrollTop();
if (wS <= 10) {
$("#test-box").animate({
'left': 100
}, 500);
}
if (wS > 11) {
$("#test-box").animate({
'left': $('#main-container').width() - 100
}, 500);
}
});
});
#main-container {
width: 100%;
overflow: auto;
height: 500px;
}
#test-box {
background: red;
color: #ffffff;
padding: 15px;
font-size: 18px;
position: fixed;
left: 100;
top: 10;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="main-container">
<div id="test-box">test</div>
</div>
As you can see, on scroll down, the test box moves as I instruct but when scroll up, it does not go to the left as default, any ideas, help please?
You can add a global variable to control the animation. See the working snippet below please, where I've commented parts of the code that I added:
$(document).ready(function() {
var animated = false; //added variable to control the animation
$(window).scroll(function() {
var wS = $(this).scrollTop();
if (animated && wS <= 10) {
$("#test-box").animate({
'left': 100
}, 500);
animated = false; //animation ended
}
if (!animated && wS > 11) {
$("#test-box").animate({
'left': $('#main-container').width() - 100
}, 500);
animated = true; //it was animated
}
});
});
#main-container {
width: 100%;
overflow: auto;
height: 500px;
}
#test-box {
background: red;
color: #ffffff;
padding: 15px;
font-size: 18px;
position: fixed;
left: 100px;
top: 10;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="main-container">
<div id="test-box">test</div>
</div>
This should work, it also uses css for the animation.
$(document).ready(function() {
var box = document.querySelector('#test-box');
var stateClass = '-right';
window.addEventListener('scroll', function(event) {
box.classList.toggle(stateClass, document.body.scrollTop > 10);
});
});
#main-container {
width: 100%;
overflow: auto;
height: 2000px;
}
#test-box {
background: red;
color: #ffffff;
padding: 15px;
font-size: 18px;
position: fixed;
left: 100px;
top: 10;
transition: .5s linear;
}
#test-box.-right {
left: 100%;
transform: translateX(-100%) translateX(-100px)
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="main-container">
<div id="test-box">test</div>
</div>

Javascript Slideshow Functions Not Working

I would please like an explanation to why the slideshow is not working. Below I have used an interval to perpetually change the slideshow, if userClick is false. The white and squared buttons (made of divs) are set to call upon two functions; slideRight() or slideLeft() and clicked(). When the buttons are clicked however, the clicked() function does not seem to change the variable, based on the data on top of the page.
<body>
<div class="page-wrapper">
<header>
<div class="headContent">
<h1 class="titleText">Slideshow</h1>
<h2 class="subTitleText">A slideshow made with JavaScript.</h2>
<p>userClick <span id="uc"></span></p>
</div>
<nav>
<ul>
<li>Home</li>
<li>About</li>
<li>Gallery</li>
</ul>
</nav>
</header>
<div class="body-wrapper">
<h1 class="titleText">Slideshow</h1>
<div id="slideshow">
<div id="leftSlide" onclick="leftSlide(); clicked()"></div>
<div id="rightSlide" onclick="rightSlide(); clicked()"></div>
</div>
<p>The image is not invoked by a tag, but invoked by the background property using Javascript.</p>
</div>
<footer>
<p id="footerText">© 2017 <br>Designed by JastineRay</p>
</footer>
</div>
<script language="javascript">
// Slide function
var slide = ["minivan", "lifeinthecity", "sunsetbodyoflove"];
var slideTo = 1;
window.onload = getSlide();
// Previous Image
function leftSlide() {
if (slideTo != 0) {
slideTo = slideTo - 1;
} else if (slideTo == 0) {
slideTo = slide.length - 1;
} else {
alert('SLIDE ERROR');
}
getSlide();
}
// Next Image
function rightSlide() {
if (slideTo != (slide.length - 1)) {
slideTo = slideTo + 1;
} else if (slideTo == (slide.length - 1)) {
slideTo = 0;
} else {
alert('SLIDE ERROR');
}
getSlide();
}
function getSlide() {
imageURL = 'url(images/' + slide[slideTo] + '.jpg)';
document.getElementById("slideshow").style.backgroundImage = imageURL;
}
// Interval Slideshow & Check if user clicked (timeout)
var userClick = false;
window.onload = slideInterval(5000);
// Start Slideshow
function slideInterval(interval) {
while (userClick = false) {
setInterval(function() {
rightSlide();
}, interval)
}
}
// Stop Slideshow and start timeout
function clicked() {
userClick = true;
setTimeout(function() {
userClick = false;
slideInterval();
}, 2000)
}
window.onload = function() {
setInterval(document.getElementById("uc").innerHTML = userClick), 100
}
</script>
</body>
CSS coding below.
* {
margin: 0;
padding: 0;
}
.page-wrapper {
width: 100%;
}
// Class Styling
.titleText {
font-family: monospace;
font-size: 40px;
}
.subTitleText {
font-family: monospace;
font-size: 20px;
font-weight: normal;
}
// Header Styling
header {
height: 500px;
}
.headContent {
margin: 30px 7%;
}
// Navigation Styling
nav {
overflow: hidden;
}
nav ul {
background: black;
background: linear-gradient(#595959, black);
list-style-type: none;
font-size: 0;
padding-left: 13.33%;
margin: 40px 0;
}
nav ul li {
padding: 15px 20px;
border-right: 1px solid #595959;
border-left: 1px solid #595959;
color: white;
display: inline-block;
font-size: 20px;
font-family: sans-serif;
}
// Body Styling
.body-wrapper {
}
.body-wrapper > .titleText {
text-align: center;
font-size: 50px;
}
#slideshow {
overflow: hidden;
margin: 20px auto;
border: 2px solid blue;
height: 350px;
max-width: 800px;
background-size: cover;
background-position: center;
position: relative;
}
#leftSlide {
position: absolute;
left: 40px;
top: 175px;
background-color: white;
height: 40px;
width: 40px;
}
#rightSlide {
position: absolute;
left: 100px;
top: 175px;
background-color: white;
height: 40px;
width: 40px;
}
// Footer Styling
Try changing the checking part to:
window.onload = function() {
setInterval(function () {
document.getElementById("uc").innerHTML = userClick;
}, 100);
}
The first argument of setInterval has to be a function (something that can be called), not a generic piece of code.

CSS: Replacing a Fade Out Image

This code fades out an image on load after a delay. Is it possible to fade in a new image after the blue circle fades out? http://jsfiddle.net/gabrieleromanato/8puvn/
html
<div id="test"></div>
Javascript
(function($) {
$.fn.fadeDelay = function(delay) {
var that = $(this);
delay = delay || 3000;
return that.each(function() {
$(that).queue(function() {
setTimeout(function() {
$(that).dequeue();
}, delay);
});
$(that).fadeOut('slow');
});
};
})(jQuery);
$('#test').fadeDelay(4000);
CSS
#test {
margin: 2em auto;
width: 10em;
height: 10em;
background: #069;
border-radius: 50%;
}
do your fade in code inside fadeOut call back.
$(that).fadeOut('slow', function(){
//do fade in
});
sample
(function($) {
$.fn.fadeDelay = function(delay, awake) {
$(awake).hide();
var that = $(this);
delay = delay || 3000;
return that.each(function() {
$(that).queue(function() {
setTimeout(function() {
$(that).dequeue();
}, delay);
});
$(that).fadeOut('slow', function() {
$(awake).fadeIn('slow');
});
});
};
})(jQuery);
$('#test').fadeDelay(4000, "#test2"); //pass jquery selector, which element to show
.circle {
margin: 2em auto;
width: 10em;
height: 10em;
border-radius: 50%;
}
#test {
background: #069;
}
#test2 {
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="test" class="circle"></div>
<div id="test2" class="circle"></div>
Ofcourse it's possible, in jQuery animations second parameter is the function that runs after animation completes. More info
(function($) {
$.fn.fadeDelay = function(delay) {
var that = $(this);
delay = delay || 3000;
return that.each(function() {
$(that).queue(function() {
setTimeout(function() {
$(that).dequeue();
}, delay);
});
$(that).fadeOut('slow',function(){
$('#test2').fadeIn('slow');
});
});
};
})(jQuery);
$('#test').fadeDelay(4000);
#test {
margin: 2em auto;
width: 10em;
height: 10em;
background: #069;
border-radius: 50%;
}
#test2 {
margin: 2em auto;
width: 10em;
height: 10em;
background: #f69;
border-radius: 50%;
display:none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="test"></div>
<div id="test2"></div>
Here's jsFiddle

How do I check whether the right/left edge of an element is overlapping the side of it's container?

I'm trying to display a right / left navigation arrow within a container (the arrows replace the existence of a scrollbar) when the corresponding edge of the content overlaps the container's sides.
Also, when the content is scrolled all the way to the end and can't scroll any further, the arrow should disappear.
My problem is, I'm confused as to how I write the function to check whether the element's contents are overlapping one edge or the other to hide one arrow or the other.
I started writing logic like this:
function setArrows(elem){
if (elem.scrollLeft() > 0) { //scroll position is greater than zero
// show left arrow
}
if () { //scroll position is less than zero
//show right arrow
}
}
but that doesn't seem to be the right logic. It sounded simpler in my head before I went to actually write the function.
How do I check whether the right/left edge of an element is overlapping the side of it's container?
Here's a Stack Snippet:
$('#wrapper').scroll(function(){
//check edges
});
div {
padding: 0px;
margin: 0px;
}
#wrapper {
width: 500px;
height: 100px;
background-color: blue;
overflow-x: scroll;
overflow-y:hidden;
}
#content {
width: 1000px;
height: 100px;
background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div id="wrapper">
<div id="content">
</div>
</div>
You need to check if the content width minus the scrollLeft is greater than the wrapper width. If it is show the right scroller..
Something like this
$(function() {
var content = $('#content'),
arrows = $('.arrow'),
wrapper = $('#wrapper').scroll(function() {
//check edges
// handle left arrow
if (this.scrollLeft > 0) {
arrows.filter('.left').addClass('visible');
} else {
arrows.filter('.left').removeClass('visible');
};
// handle right arrow
if (content.outerWidth() - this.scrollLeft > wrapper.width()) {
arrows.filter('.right').addClass('visible');
} else {
arrows.filter('.right').removeClass('visible');
};
});
arrows.on('click', function() {
if ($(this).is('.left')) {
wrapper[0].scrollLeft -= 100;
} else {
wrapper[0].scrollLeft += 100;
}
return false;
});
// initialize
wrapper.trigger('scroll');
});
div {
padding: 0px;
margin: 0px;
}
#wrapper {
width: 500px;
height: 100px;
background-color: blue;
overflow-x: hidden;
overflow-y: hidden;
position: relative;
}
#content {
width: 1000px;
height: 100px;
background: url('http://lorempixel.com/1000/100/abstract/2') 0 0 no-repeat;
}
#full-container {
position: relative;
display: inline-block;
}
.arrow {
position: absolute;
top: 0;
bottom: 0;
width: 40px;
background-color: black;
display: none;
z-index: 100;
cursor: pointer;
color: #fff;
text-align: center;
line-height: 100px;
}
.arrow.visible {
display: block;
}
.arrow.left {
left: 0
}
.arrow.right {
right: 0
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div id="full-container">
<div class="arrow left"><</div>
<div id="wrapper">
<div id="content"></div>
</div>
<div class="arrow right">></div>
</div>

Categories

Resources