How to animate the each box when scrolling down the box will be animate like fade-in,
if scroll to the .box pageYOffset 20 that box will be fade-in, I tried with AOS third-party library and its worked fine but i want to know how to do scroll down animation without any third-party library
myCode
#HostListener('window:scroll', ['$event'])
onWindowScroll(e) {
const box = document.querySelector('.box');
if (window.pageYOffset < box.clientHeight ) {
box.classList.add('colorChange');
} else {
box.classList.remove('colorChange');
}
}
.container{
text-align: center;
margin: auto;
padding-top: 768px;
}
.box{
background: #007aff;
width: 200px;
height: 200px;
display: block;
word-spacing: 30px;
line-height: 30px;
margin: 30px auto;
}
.colorChange{
background: #fcad2e;
animation: fade-in 1s ease-in-out;
}
#keyframes fade-in {
from{
opacity: 0;
transform: translateY(50px);
}
to{
opacity: 1;
transform: translateY(0);
}
}
<div class="container">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
This works by specifically adding a window scroll event listener.
import { Component, VERSION, HostListener } from "#angular/core";
#Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
name = "Angular " + VERSION.major;
constructor(){
window.addEventListener("scroll", (event)=>{
debugger;
const box = document.querySelector('.box');
if (window.pageYOffset < box.clientHeight ) {
box.classList.add('colorChange');
} else {
box.classList.remove('colorChange');
}
});
}
}
Here's link to working example
Related
I want to create an animation for an element with following properties:
it animates the element when it enters the viewport
if the element left the viewport and then enters it again it should be animated again
depending on the scroll direction/intersected side (from top or bottom) the animation should be different
For this purpose I use an IntersectionObserver and I came close to the desired outcome.
The only problem I am facing is, when I translate the element in the scroll direction (which is in this case transform: translateY) during the animation. This will cause the IntersectionObserver to trigger multiple or even infinite times.
function isIntersectingFromTop(entry){
return entry.boundingClientRect.bottom != entry.intersectionRect.bottom;
}
function isIntersectingFromBottom(entry){
return entry.boundingClientRect.top != entry.intersectionRect.top;
}
var count = 0;
function incrementCounter(entry){
document.querySelector(".counter").textContent += "intersectionRation (" + count + "): " + entry.intersectionRatio + "\n";
count++;
}
let observer = new IntersectionObserver(
function (entries, observer) {
entries.forEach(function(entry){
incrementCounter(entry)
if (entry.isIntersecting) {
if(isIntersectingFromTop(entry)){
entry.target.classList.add("animated--up-in");
} else if(isIntersectingFromBottom(entry)) {
entry.target.classList.add("animated--down-in")
}
} else {
/** element is not in viewport anymore
* this will be triggered right after the animation starts
* since the translate is moving the elment out of the view
* which is causing a new intersection (isIntersecting = false)
*/
entry.target.classList.remove("animated--up-in");
entry.target.classList.remove("animated--down-in");
}
});
});
observer.observe(document.querySelector(".to-animate"));
.container {
height: 1000px;
width: 100%;
}
.box{
position: static;
width: 100px;
height: 100px;
background: red;
margin-top: 10px;
}
.to-animate{
background: blue;
opacity: 0;
}
.animated--up-in {
animation: animateUpIn 1.5s forwards ease;
}
.animated--down-in {
animation: animateDownIn 1.5s forwards ease;
}
#keyframes animateUpIn {
from {
transform: translateY(100px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
#keyframes animateDownIn {
from {
transform: translateY(-100px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
.counter {
position: fixed;
top: 10%;
left: 30%;
color: black;
height: 80%;
width: 50%;
overflow-y: auto;
padding: 10px;
}
<div class="container">
<pre class="counter"></pre>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box to-animate"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
Question
How can I "tell" the IntersectionObserver to ignore translated position and just use the initial/original position to calculate intersections (with no extra element)? Is this even possible?
I think that in this case you need to track the position on the screen of the stationary containers in which the animated elements will be nested.
I have a similar problem with translateX on mobile device
Animation has translateX(-100% or 100%);
threshold: 0.1
Block has width 100%, but it should work with a visibility of 10% (threshold 0.1), therefore it cannot work, the animation switches back and forth, endlessly.
If it's 90%, then it will work
I have some texts in my site that I want to show only when the user clicks at the title and then the text appears with an animation, and when the user clicks again at the title the text disappears. I made this code bellow that is working awesome for "show more" but for some reason its not working for "show less"!
function showMore(resp) {
if (document.getElementById(resp).style.maxHeight == "400") {
document.getElementById(resp).style.animation = "showmore 2s ease-in-out reverse";
document.getElementById(resp).style.maxHeight = "0";
} else {
document.getElementById(resp).style.animation = "showmore 2s ease-in-out";
document.getElementById(resp).style.maxHeight = "400";
}
}
#keyframes showmore {
0% {
opacity: 0;
max-height: 0;
}
100% {
opacity: 1;
max-height: 400px;
}
}
.awr {
text-align: left;
margin-left: 10px;
font-size: 17;
color: dimgrey;
max-height: 0;
overflow: hidden;
}
<div class="question" onclick="showMore('awr1')">
<h3>How it Works?</h3>
</div>
<div class="awr" id="awr1">
<p>this is the text that must be hidden.</p>
</div>
Can anyone help me?
I implemented in jQuery but you can easily transform into Javascript.
You can simply add a class & toggle it.
function showMore(resp) {
$("#" + resp).toggleClass("show");
}
.awr {
text-align: left;
margin-left: 10px;
font-size: 17;
color: dimgrey;
height: 0px;
visibility: hidden;
transition: all 0.3s linear;
background-color: #F1F1F1;
}
.show {
visibility: visible;
height: 200px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="question" onclick="showMore('awr1')">
<h3>How it Works?</h3>
</div>
<div class="awr" id="awr1">
<p>this is the text that must be hidden.</p>
</div>
You can do this with css transition instead of animation. Transition basically watches the given properties for changes and animates it from one state to the next. You can also use the all keyword here if you just want everything to animate when it's changed.
.show {
opacity: 1;
max-height: 400px;
}
.awr {
/* your other styles here */
opacity: 0;
max-height: 0;
transition: all 2s;
}
If I'm not mistaken, easing is default behavior, too. Then toggle the class with JavaScript however you usually would. For example, this is my preferred method:
const showMore = resp => document.querySelector(`#${resp}`).classList.toggle('show')
I don't understand why there's having a problem with .toggle() when toggling class names with animations. Consider this experiment I made:
var query = document.querySelector.bind(document);
query('button').addEventListener('click', function() {
[].forEach.call(query('.container').children, function(box, i) {
setInterval(function() {
box.classList.toggle('popIn');
}, 300 * i);
})
})
.container > .box {
width: 100px;
height: 100px;
background: cyan;
display: inline-block;
transform: scale(0);
transition: all 0.3s ease-in-out;
}
.container > .box.popIn {
transform: scale(1);
}
<button>Click</button>
<div class="container">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
When I click the button, it toggles the class names of boxes indefinitely as if it's not sure if it adds or removes them. Is it because the .toggle() method is inside a forEach loop?
You're issue is in the setInterval function. You are saying, perform this event every 300ms. What you want is setTimeout, which is telling the event to stop after 300ms. See the below snippet where I have made the change.
See more information on setTimeout
See more information on setInterval
var query = document.querySelector.bind(document);
query('button').addEventListener('click', function() {
[].forEach.call(query('.container').children, function(box, i) {
setTimeout(function() {
box.classList.toggle('popIn');
}, 300 * i);
})
})
.container > .box {
width: 100px;
height: 100px;
background: cyan;
display: inline-block;
transform: scale(0);
transition: all 0.3s ease-in-out;
}
.container > .box.popIn {
transform: scale(1);
}
<button>Click</button>
<div class="container">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
I'm using the below; but the margin isn't nearly as approximate as text-align:center; is there anyway I could toggle text-align: center; to occur with a animation transition until it gets to the point of text-align: center; similar to that which is achieved with the below.
if ($(".resource-section").hasClass("resource-section--expanded")) {
$(".resources__header h2").animate({"marginLeft": "40%"}, "slow");
}
You can use a centering technique that allows you to horizontally center any element.
It can be animated using only CSS
.test {
position: absolute;
transform: translateX(0%);
left: 0%;
animation: center 2s infinite;
}
#keyframes center {
0%, 10% {
transform: translateX(0%);
left: 0%;
}
90%, 100% {
transform: translateX(-50%);
left: 50%;
}
}
<h1 class="test">TEST</h1>
You could animate center align using margin-left like this
var h1 = $('h1').width();
var parent = $('.container').width();
$('h1').animate({'margin-left':(parent/2-h1/2)}, 1500);
.container {
border: 1px solid black;
height: 100px;
}
h1 {
display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<h1>Text</h1>
</div>
From what i understood if you want to use the text-align:center property something like this could be of help to you, but the text-align property can't be animated
$(function(){
$('.resources_header h2').click(function(){
$(this).toggleClass('align-center');
});
});
.align-center{
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="resources_header">
<h2>HEADER</h2>
</div>
</div>
A problem with this is the animation so if what you want to achieve is to animate from left to center then why not:
$(function(){
$('.resources_header h2').click(function(){
var windowHalfWidth = $(window).width()/2;
$(this).css('position','absolute');
var elemHalfWidth = $(this).width()/2;
var left = windowHalfWidth - elemHalfWidth;
$(this).animate({
marginLeft: left
},"slow",function(){
$(this).css('position','static');
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="resources_header">
<h2>HEADER</h2>
</div>
</div>
This is my first post here. I'm looking for some help.
I have multiple div contents which should fade in out and out dynamically. I have got this jsfiddle and made it work for 2 divs, but need it to work for multiple, for example 5 different DIVs.
Is this jsfiddle the best way to go or is there a better option. Here is the code. Here is the jquery.
var fadeinBox = $("#box2");
var fadeoutBox = $("#box1");
function fade() {
fadeinBox.stop(true, true).fadeIn(2000);
fadeoutBox.stop(true, true).fadeOut(2000, function() {
// swap in/out
var temp = fadeinBox;
fadeinBox = fadeoutBox;
fadeoutBox = temp;
// start over again
setTimeout(fade, 1000);
});
}
// start the process
fade();
Here is the html
<div id="wrapper">
<div id="box1" class="box"></div>
<div id="box2" class="box"></div>
</div>
and the CSS
.box {
position: absolute;
height: 100px;
width: 100px;
}
#wrapper {position: relative;}
#box1 {background-color: #F00;}
#box2 {background-color: #00F; display: none;}
Thank you in advance, and the link is below.
Dynamically changing DIV jsfiddle
You could use the same code but make it dynamic instead of two static elements:
var $boxes = $(".box").hide();
var current = 0;
function fade() {
$boxes.eq(current).stop(true, true).fadeOut(2000);
current = (current + 1) % $boxes.length;
$boxes.eq(current).stop(true, true).fadeIn(2000, function(){
setTimeout(fade, 1000);
});
}
fade();
http://jsfiddle.net/3XwZv/637/
What about doing it with CSS3 animations? Depending on your target browsers, this should work well:
Simplify your markup to a single div like this:
<div id="box"></div>
and then the CSS handles all the animation:
#keyframes colorCycle
{
0% {background-color:red;}
20% {background-color:orange;}
40% {background-color:yellow;}
60% {background-color:green;}
80% {background-color:blue;}
100% {background-color:purple;}
}
#-webkit-keyframes colorCycle /* Safari and Chrome */
{
0% {background-color:red;}
20% {background-color:orange;}
40% {background-color:yellow;}
60% {background-color:green;}
80% {background-color:blue;}
100% {background-color:purple;}
}
#box {
height: 100px;
width: 100px;
animation: colorCycle 10s 0s infinite;
-webkit-animation: colorCycle 10s 0s infinite;
}
Here's a Fiddle You can play with the key stops, timings, and colors to get the effect you need.
Depending on your specific application, you could toggle the fade for all boxes and use jQuery's promise() to determine when all boxes have finished fading.
HTML:
<div class="wrapper">
<div class="box box1"></div>
<div class="box box2"></div>
</div>
<div class="wrapper">
<div class="box box1"></div>
<div class="box box2"></div>
</div>
<div class="wrapper">
<div class="box box1"></div>
<div class="box box2"></div>
</div>
CSS:
.box {
position: absolute;
height: 100px;
width: 100px;
}
.wrapper {
position: relative;
width:100px;
height:100px;
margin-bottom:10px;
}
.box1 {
background-color: #F00;
}
.box2 {
background-color: #00F;
display: none;
}
JS:
function fade() {
jQuery('.box').stop(true, true).fadeToggle(2000);
jQuery('.box').promise().done(function(){fade();});
}
fade();
http://jsfiddle.net/3XwZv/638/