I'm trying to implement an animation set up by keyframes when a div enters the screen. So basically whilst the user scrolss, I have several animations that so far work but they are based on singles transforms (opacity, translation in axis).
What I have so far
import React, {useState, useRef, useLayoutEffect} from 'react'
import AboutMeIcon from "./AboutMeIcons"
import iconsArray from "../iconsArray"
import styled, {keyframes} from "styled-components";
const bouncing = keyframes`
0% { transform: scale(1,1) translateY(0); }
10% { transform: scale(1.1,.9) translateY(0); }
30% { transform: scale(.9,1.1) translateY(-100px); }
50% { transform: scale(1.05,.95) translateY(0); }
57% { transform: scale(1,1) translateY(-7px); }
64% { transform: scale(1,1) translateY(0); }
100% { transform: scale(1,1) translateY(0); }
`
const DivTitleWrapper = styled.div `
transform: translateX(${({animate}) => (animate ? "0" : "-100vw")});
transition: transform 1s;
width: 100vw;
display: flex;
justify-content: center;
height: 120px;
border-radius: 0 0 100px 100px;
margin-bottom: 30px;
`;
const ImageWrapper = styled.div `
height: 400px;
position: relative;
animation: ${({animation}) => (animation ? bouncing : null)} cubic-bezier(0.280, 0.840, 0.420, 1);
&::before {
content: "";
width: 100%;
height: 0;
transition: 0.4s ease;
background-color: #283647;
opacity: 0.5;
position: absolute;
top: 0;
left: 0;
}
h2{
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
position: absolute;
margin:0;
opacity:0;
transition-delay:0.3s;
transition: 1s ease;
font-family: 'Raleway', sans-serif;
color: #f5f5f5;
z-index: 20;
width: 100%;
text-align: center;
}
&:hover {
h2 {
opacity: 1;
}
}
&::after {
content: "";
width: 100%;
height: 0;
opacity: 0.5;
transition: 0.4s ease;
background-color: #283647;
position: absolute;
bottom: 0;
left: 0;
}
&:hover::before{
height: 50%;
}
&:hover::after{
height: 50%;
}
`
On use LayoutEffect
hook I set the state for each of the elements I want to animate (for the purpose of this question I will only add two)
const [show, doShow] = useState({
itemOne: false,
itemSix: false
})
const ref = useRef(null),
refTwo = useRef(null),
refThree = useRef(null),
refFour = useRef(null),
refFive = useRef(null),
refSix = useRef(null)
useLayoutEffect(() => {
const topPos = element => element.getBoundingClientRect().top
const divPos1 = topPos(ref.current),
imagesDiv = topPos(refSix.current)
const scrollHandler = () => {
const scrolPos = window.scrollY + window.innerHeight
if(divPos1 < scrolPos) {
doShow(state => ({...state, itemOne: true}))
}
if(imagesDiv < scrolPos) {
doShow(state => ({...state, itemSix:true}))
}
}
window.addEventListener("scroll", scrollHandler)
return () => {
window.removeEventListener("scroll", scrollHandler)
};
}, [])
What my functional component returns (removed most of it to avoid cluttering of information)
return(
<section className="aboutMeSection">
<DivTitleWrapper animate={show.itemOne} ref={ref}>
<H1 className="aboutMeTitle" opacity={show.itemTwo} ref={refTwo}>About Me</H1>
</DivTitleWrapper>
<div className="me">
{imageArray.map((image, index) => {
return (
<ImageWrapper ref={refSix} animation={show.itemSix} className={"imageWrapper" + index}>
///some images being layed out
</ImageWrapper>
)
})}
</div>
</section>
)
My problem at the moment is that when the user scrolls to the point where the state is updated for the div with refSix
, the animation is not being triggering but for the div with refOne
I have no issues.
Am I missing something here?
Many thanks and happy new year
EDIT:
Added styled div that is currently working