스크롤을 내리고 올릴 때 div가 커지는 애니메이션을 만들어보고 싶었다. 스크롤을 잘 안다루는 내 특성상 나중에 까먹을 것 같아 미래의 나를 위해 이렇게 글로 남긴다.
<div class="parent_div">
<div class="child_div">
</div>
</div>
<style>
.parent_div{
margin-left: auto;
margin-right: auto;
margin-top: 1000px;
width: 500px;
height: 500px;
background-color: grey;
box-shadow: 4px 4px 4px 3px rgba(0, 0, 0, 0.4);
}
.child_div{
margin: 0% auto;
width: 300px;
height: 300px;
background-color: black;
}
</style>
애니메이션 시작 위치는 viewport 가장 하단 부가 부모div를 만나는 시점이다.
우리가 스크롤을 내리면서 화면이 아래로 점점 내려갈 때 뷰포트부터 parent div까지의 높이
가 점점 작아진다. 그 높이가 뷰포트 높이
가 되었을 때 애니메이션을 시작한다고 생각하자.
<script>
const parentDiv = document.querySelector('.parent_div');
const viewportHeight = window.innerHeight;
const fromViewportToParentHeight = parentDiv.getBoundingClientRect().top;
const 스크롤이넘어간정도 = viewportHeight - fromViewpoerToParentHeight;
</script>
viewportHeight - fromViewportToParentHeight
가 0이 되면 시작인 것이다. 이를 스크롤이넘어간정도
변수에 저장해두자.
끝 위치는 자기가 정하는 나름대로이다. 일단 parent div가 내 화면에 다 보일때로 가정하겠다.
스크롤이내려간정도
가divHeight
와 같을 때 애니메이션이 끝난다
<script>
const divHeight = parentDiv.clientHeight;
</script>
애니메이션이 시작하고 싶은 위치까지 스크롤을 내리면 0%, 끝나는 지점에서는 100%를 출력하도록 코드를 짜보자
<script>
const scrollRate = 스크롤이넘어간정도/divHeight * 100;
</script>
재료준비는 끝났다.
이제 이 변수들을 활용해서 parent div
에 대한 스크롤 비율을 0~100사이의 퍼센트로 나타내보자
<script>
window.onscroll = ()=>{
const parentDiv = document.querySelector('.parent_div');
const viewportHeight = window.innerHeight;
const fromViewportToParentHeight = parentDiv.getBoundingClientRect().top;
const 스크롤이넘어간정도 = viewportHeight - fromViewportToParentHeight;
const divHeight = parentDiv.clientHeight;
let scrollRate = 스크롤이넘어간정도/divHeight * 100;
if(스크롤이넘어간정도/divHeight * 100 <0){
scrollRate = 0;
}else if(스크롤이넘어간정도/divHeight * 100 > 100){
scrollRate = 100;
}
console.log(scrollRate);
}
</script>
애니메이션 속도는 0~100이 선형으로 움직인다는 점을 이용해서 개발자 입맛대로 바꿔주면 된다. 2차함수나 3차함수... 등등
스타일 속성에 따라 음수가 되어야 할 수도 있으니 scrollRate를 입맛에 맞게 변형하자
scrollRate
를 그대로 사용할 것 이다.style 속성에 맞춰 값을 변형시켜줘야 한다.
scale은 0~1사이의 값이니 100으로 나눠주어 적용한다.
<script>
window.onscroll = ()=>{
const parentDiv = document.querySelector('.parent_div');
const viewportHeight = window.innerHeight;
const fromViewportToParentHeight = parentDiv.getBoundingClientRect().top;
const 스크롤이넘어간정도 = viewportHeight - fromViewportToParentHeight;
const divHeight = parentDiv.clientHeight;
let scrollRate = 스크롤이넘어간정도/divHeight * 100;
if(스크롤이넘어간정도/divHeight * 100 <0){
scrollRate = 0;
}else if(스크롤이넘어간정도/divHeight * 100 > 100){
scrollRate = 100;
}
//스타일 적용하는 부분
const childDiv = document.querySelector('.child_div');
childDiv.style.transform = `scale(${scrollRate/100})`;
}
</script>
팁은 크게 두가지로 나눈다.
1. 뷰포트의 height가 element의 height보다 작을경우의 팁
2. transform 애니메이션에 대한 팁
6-1 뷰포트의 height가 element의 height보다 작을경우
이 경우 애니메이션이 끝나지 않아 불편을 겪을 수도 있다. 이럴 때는 애니메이션 끝나는 지점을 바꿔주면 된다.
이미지로 이해해보자
이렇게 이미 parentDiv는 내 화면에 가득 찼다. 하지만 아직 애니메이션은 끝나지 않았다... 이런 경우에는 divHeight의 값을 수정해서 애니메이션이 끝나는 위치를 적절히 바꿔주면 된다.<script> window.onscroll = ()=>{ const parentDiv = document.querySelector('.parent_div'); const viewportHeight = window.innerHeight; const fromViewportToParentHeight = parentDiv.getBoundingClientRect().top; const 스크롤이넘어간정도 = viewportHeight - fromViewportToParentHeight; //parentDiv의 height가 뷰포트 높이보다 크면 뷰포트로, 아닐경우 parentDiv로 let divHeight = parentDiv.clientHeight>viewportHeight ? viewportHeight : parentDiv.clientHeight; let scrollRate = 스크롤이넘어간정도/(divHeight) * 100; if(스크롤이넘어간정도/divHeight * 100 <0){ scrollRate = 0; }else if(스크롤이넘어간정도/divHeight * 100 > 100){ scrollRate = 100; } //스타일 적용하는 부분 const childDiv = document.querySelector('.child_div'); childDiv.style.transform = `scale(${scrollRate/100})`; } </script>
6-2 childDiv의 커지는 위치 수정
꽤 간단하게 해결할 수 있다. transform-origin을 통해 기준 위치를 정해주면 된다.
<style> .child_div{ transform-origin: 50% 0%; } </style>
이렇게 부모 div 상단에 딱 붙어서 scale이 커진다.
애니메이션 시작과 끝을 정해 퍼센트로 나타낼 수만 있으면 나머지는 개발자 마음대로 조리할 수 있다.
추천 : sticky를 사용하면 더 맛깔난 웹사이트를 만들어볼 수도 있다.