My script should scroll down to an element 2 seconds after the page is loaded. It should work only on mobiles.
window.HTMLElement.prototype.scrollIntoView = function() {};
if (window.innerWidth < 500) {
setTimeout(function() {
let toogleElement = document.getElementsByClassName('eapps-google-maps-bar-toggle');
toogleElement.scrollIntoView({
behavior: 'smooth'
});
}, 2000);
}
#padding { height: 1000px; }
<div id="padding"></div>
<div class="eapps-google-maps-bar-toggle" eapps-link="barToggle">Foo</div>
First, you need to remove window.HTMLElement.prototype.scrollIntoView = function() {}; because you don't need to define your own funciton.
Second, document.getElementsByClassName return HTML collection and you can access the element your want by using toogleElement[0].
Example below
if (window.innerWidth < 2000) {
setTimeout(function() {
let toogleElement = document.getElementsByClassName('eapps-google-maps-bar-toggle');
toogleElement[0].scrollIntoView({
behavior: 'smooth'
});
}, 2000);
}
#padding { height: 1000px; }
<div id="padding"></div>
<div class="eapps-google-maps-bar-toggle" eapps-link="barToggle">Foo</div>
Related
I can scroll to 200px using the following
btn.addEventListener("click", function(){
window.scrollTo(0,200);
})
But I want a smooth scroll effect. How do I do this?
2018 Update
Now you can use just window.scrollTo({ top: 0, behavior: 'smooth' }) to get the page scrolled with a smooth effect.
const btn = document.getElementById('elem');
btn.addEventListener('click', () => window.scrollTo({
top: 400,
behavior: 'smooth',
}));
#x {
height: 1000px;
background: lightblue;
}
<div id='x'>
<button id='elem'>Click to scroll</button>
</div>
Older solutions
You can do something like this:
var btn = document.getElementById('x');
btn.addEventListener("click", function() {
var i = 10;
var int = setInterval(function() {
window.scrollTo(0, i);
i += 10;
if (i >= 200) clearInterval(int);
}, 20);
})
body {
background: #3a2613;
height: 600px;
}
<button id='x'>click</button>
ES6 recursive approach:
const btn = document.getElementById('elem');
const smoothScroll = (h) => {
let i = h || 0;
if (i < 200) {
setTimeout(() => {
window.scrollTo(0, i);
smoothScroll(i + 10);
}, 10);
}
}
btn.addEventListener('click', () => smoothScroll());
body {
background: #9a6432;
height: 600px;
}
<button id='elem'>click</button>
$('html, body').animate({scrollTop:1200},'50');
You can do this!
I recently found this website that uses scroll snapping. I looked into it and found that CSS supports this. However, it looks like snapping happens after the user stops scrolling. The same applies with the answer to this question.
The next thing I tried was using window.scrollTo and react-scroll, but both of these weren't as smooth as the website I've linked as an example since the user could still "fight" the scrolling by scrolling in the other direction.
I want it to scroll snap when the user starts scrolling. How can I do this with CSS or JavaScript?
The developer you were looking at is using this js script if you ant to emulate it exactly https://alvarotrigo.com/fullPage/
If jQuery is an option, that would be the easiest solution with the best browser compatibility. You can use the "wheel" event listener to detect the direction of the scroll, and then use jQuery animate to scroll the window to the appropriate element. I've provided an example based on this GitHub repo: https://github.com/epranka/sections-slider.
(function($) {
var selector = ".section";
var direction;
var $slide;
var offsetTop;
var $slides = $(selector);
var currentSlide = 0;
var isAnimating = false;
var stopAnimation = function() {
setTimeout(function() {
isAnimating = false;
}, 300);
};
var bottomIsReached = function($elem) {
var rect = $elem[0].getBoundingClientRect();
return rect.bottom <= $(window).height();
};
var topIsReached = function($elem) {
var rect = $elem[0].getBoundingClientRect();
return rect.top >= 0;
};
document.addEventListener(
"wheel",
function(event) {
var $currentSlide = $($slides[currentSlide]);
if (isAnimating) {
event.preventDefault();
return;
}
direction = -event.deltaY;
if (direction < 0) {
// next
if (currentSlide + 1 >= $slides.length) {
return;
}
if (!bottomIsReached($currentSlide)) {
return;
}
event.preventDefault();
currentSlide++;
$slide = $($slides[currentSlide]);
offsetTop = $slide.offset().top;
isAnimating = true;
$("html, body").animate({
scrollTop: offsetTop
},
1000,
stopAnimation
);
} else {
// back
if (currentSlide - 1 < 0) {
return;
}
if (!topIsReached($currentSlide)) {
return;
}
event.preventDefault();
currentSlide--;
$slide = $($slides[currentSlide]);
offsetTop = $slide.offset().top;
isAnimating = true;
$("html, body").animate({
scrollTop: offsetTop
},
1000,
stopAnimation
);
}
}, {
passive: false
}
);
})(jQuery);
.section {
position: relative;
display: flex;
height: 100vh;
}
#section1 {
background: blue;
}
#section2 {
background: #ff8c42;
}
#section3 {
background: #6699cc;
}
#section4 {
background: #00b9ae;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="section1" class="section"></div>
<div id="section2" class="section"></div>
<div id="section3" class="section"></div>
<div id="section4" class="section"></div>
Iam using jquery to animate an image to make a mixed up image that scrolls different parts when clicked.
I thought of doing like this
$("#head").click(function () {
if (headclix < 9) {
$("#head").animate({
left: "-=367px"
}, 500);
headclix++;
} else {
$("#head").animate({
left: "0px"
}, 500);
headclix = 0;
}
});
$("#eyes").click(function () {
if (eyeclix < 9) {
$("#eyes").animate({
left: "-=367px"
}, 500);
eyeclix++;
} else {
$("#eyes").animate({
left: "0px"
}, 500);
eyeclix = 0;
}
});
$("#nose").click(function () {
if (noseclix < 9) {
$("#nose").animate({
left: "-=367px"
}, 500);
noseclix++;
} else {
$("#nose").animate({
left: "0px"
}, 500);
noseclix = 0;
}
});
$("#mouth").click(function () {
if (mouthclix < 9) {
$("#mouth").animate({
left: "-=367px"
}, 500);
mouthclix++;
} else {
$("#mouth").animate({
left: "0px"
}, 500);
mouthclix = 0;
}
});
I hope there is better way of doing it
I'm thinking I can do something with the class and each but not sure how to quite make it work. need to make it a click event and keep track of each image part
$(".face").each(function (i) {
if (i < 9) {
$(".face").parent().animate({
left: "-=367px"
}, 500);
i++;
} else {
$(".face").parent().animate({
left: "0px"
}, 500);
i = 0;
}
});
HTML:
<div id="pic_box">
<div id="head" class="face"><img src="images/headsstrip.jpg"></div>
<div id="eyes" class="face"><img src="images/eyesstrip.jpg"></div>
<div id="nose" class="face"><img src="images/nosesstrip.jpg"></div>
<div id="mouth" class="face"><img src="images/mouthsstrip.jpg"></div>
</div>
image in this link will give you an idea of the functionality
Thank you.
You can create a face object that holds the click counts of each face part and also a function to handle the click event (named clickHandler below). The clickHandler takes in an id and calls the appropriate animate function on the element that has that id.
Check below:
var face = {
"headClicks" : 0,
"eyesClicks" : 0,
"noseClicks" : 0,
"mouthClicks" : 0,
"clickHandler" : function(id) {
if(this[id+"Clicks"] < 9) {
animateLeft367(id);
this[id+"Clicks"]++;
} else {
animateLeft0(id);
this[id+"Clicks"] = 0;
}
}
}
function animateLeft367(id) {
$("#" + id).animate({left: "-=367px"}, 500);
console.log('animated ' + id + ' 367');
}
function animateLeft0(id) {
$("#" + id).animate({left: "0px"}, 500);
console.log('animated ' + id + ' 0');
}
$(".face").click(function() {
face.clickHandler(this.id);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="pic_box">
<div id="head" class="face"><img src="images/headsstrip.jpg"></div>
<div id="eyes" class="face"><img src="images/eyesstrip.jpg"></div>
<div id="nose" class="face"><img src="images/nosesstrip.jpg"></div>
<div id="mouth" class="face"><img src="images/mouthsstrip.jpg"></div>
</div>
I want to animate different sections of a web page only when they are scrolled into view using vanilla javascript. This is what my code looks like right now
<script>
let target = document.querySelector("#who-we-are");
let service = document.querySelector("#what-we-do");
function animateAboutUs() {
if (target.scrollIntoView) {
document.querySelector("#who").classList.add("fadeIn");
}
}
function animateServiceList() {
if (service.scrollIntoView) {
document.querySelector("#service").classList.add("fadeIn");
}
}
window.onscroll = function() {
animateAboutUs();
animateServiceList();
};
</script>
The problem with doing it like this is that once a user starts to scroll down the page the service section gets animated even when its yet to come into view.
What is the proper way to do animation only when the section is scrolled into view for multiple sections?
A modern solution would be to use Intersection Observer instead of listening to the scroll event.
First you define the observer:
var options = {
root: document.querySelector('#scrollArea'),
rootMargin: '0px',
threshold: 0.1
}
var observer = new IntersectionObserver(callback, options);
Threshold of .1 means that the callback() function gets called as soon as 10% (or more) are visible. Adjust this as you see fit obviously.
If you omit the root option the browser viewport is used.
Then you observe items:
var target = document.querySelector('.scrollItems');
observer.observe(target);
Now, whenever the target meets a threshold specified for the IntersectionObserver, the callback is invoked.
var callback = function(entries, observer) {
entries.forEach(entry => {
// this loops through each element that is visible, add your classes here
entry.addClass('fadeIn');
});
}
Note: If you also need to support older browsers, there is a polyfill available.
var $animation_elements = $('.animation-element');
var $window = $(window);
function check_if_in_view() {
var window_height = $window.height();
var window_top_position = $window.scrollTop();
var window_bottom_position = (window_top_position + window_height);
$.each($animation_elements, function() {
var $element = $(this);
var element_height = $element.outerHeight();
var element_top_position = $element.offset().top;
var element_bottom_position = (element_top_position + element_height );
//check to see if this current container is within viewport
if ((element_bottom_position >= window_top_position) &&
(element_top_position <= window_bottom_position)) {
$element.addClass('in-view');
} else {
$element.removeClass('in-view');
}
});
}
Here is an other generic solution using querySelectorAll, getBoundingClientRect and eventListeners.
See the comments on the example below:
document.querySelectorAll('.section').forEach(section => {
const rect = section.getBoundingClientRect(); // get position of section
if(rect.top < document.body.scrollTop + window.innerHeight){ // check initial if a section is in view
section.classList.add('fadeIn');
} else {
window.addEventListener("scroll", addClass(section, rect)); // add eventlistener
}
});
function addClass(element, rect) {
const offset = 100; // set an offset to the needed scrollposition (in px)
let handler = () => {
if(rect.top < document.body.scrollTop + window.innerHeight - offset){ // check if scrollposition is reached
element.classList.add('fadeIn');
window.removeEventListener('scroll', handler); // remove eventlistener
console.log(`reached section ${element.id}`);
}
};
return handler;
}
.section {
height: 100vh;
color: transparent;
text-align: center;
font-size: 100px;
}
.section.fadeIn {
color: #000 !important;
}
#one { background-color: yellow }
#two { background-color: green }
#three { background-color: orange }
#four { background-color: lightblue }
#five { background-color: grey }
<div class="section" id="one">Faded In!</div>
<div class="section" id="two">Faded In!</div>
<div class="section" id="three">Faded In!</div>
<div class="section" id="four">Faded In!</div>
<div class="section" id="five">Faded In!</div>
I have one rectangle, 2 functions that animates different this rectangle at different window widths, and im calling the functions with a click. it Must work when screen resizes as well.
Problems:
1- it seems like when I load one function then the other cant work, only the first.
2- It doesn't work on the first click.
3- I have to write the same code for when the document is ready and when the document resize.
How can I fix this 3 points. thx. code below.
$(document).ready(function () {
function lateralMove() {
$(".rectangle-1").off("click").click(function () {
$(this).animate({
left: "+=50"
}, 500);
})
}
function horizontalMove() {
$(".rectangle-1").off("click").click(function () {
$(this).animate({
top: "+=50"
}, 500);
})
}
$(window).resize(function () {
screenWidth = $(this).width()
})
$(".rectangle-1").click(function () {
if (screenWidth > 300) {
lateralMove()
} else if (screenWidth <= 300) {
horizontalMove()
}
})
screenWidth = $(window).width()
if (screenWidth > 300) {
blackMove()
} else if (screenWidth <= 300) {
horizontalMove()
}
})
.rectangle-1 {
position: relative;
background-color: #000;
height: 100px;
width: 100px;
margin-top: 20px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<!doctype html>
<html>
<head></head>
<body>
<div>
<div class="rectangle-1"></div>
</div>
</body>
</html>
just cal a different function depending n a screen width:
function do_mobile(){
//do
}
function do_desktop(){
//do
}
$(".rectangle-1").on("click", function(){
if( $(window).width() > 300 ){
do_desktop();
}
else{
do_mobile();
}
})
This was just a matter of cleaning up your code (you had a function call to a function called blackMove() that was undefined) and you also needed to wrap the "assign movement" portion of your code in a function and call it on document ready and on window resize.
Here's the code pen:
http://codepen.io/nhmaggiej/full/azXgqw/
$(document).ready(function () {
function verticalMove() {
$(".rectangle-1").off("click").click(function () {
$(this).animate({
left: "+=50"
}, 500);
})
}
function horizontalMove() {
$(".rectangle-1").off("click").click(function () {
$(this).animate({
top: "+=50"
}, 500);
})
}
function assignMovement() {
screenWidth = $(this).width()
if (screenWidth > 600) {
verticalMove()
} else if (screenWidth <= 600) {
horizontalMove()
}
};
$(window).resize(function () {
assignMovement();
})
assignMovement();
});
This will move the square onload, onresize and when the square is clicked.
jsFiddle
function lateralMove(elementX) {
elementX.animate({
left: "+=50"
}, 500);
}
function horizontalMove(elementX) {
elementX.animate({
top: "+=50"
}, 500);
}
function elementMove() {
screenWidth = $(window).width();
elementX = $(".rectangle-1");
if (screenWidth > 300) {
lateralMove(elementX);
} else if (screenWidth <= 300) {
horizontalMove(elementX);
}
}
//move on resize
//Use a Timeout to ensure that the resize event is only fired once per change.
$(window).resize(function () {
clearTimeout(this.id);
this.id = setTimeout(elementMove, 500);
});
//move on click
$(".rectangle-1").click(function () {
elementMove();
})
//move on load
elementMove();