자바스크립트

자바스크립트>스크롤 위치에 따라 변하는 애니메이션 : Apple Music UI 만들기

연습노트 2024. 7. 10. 10:23

참고 사이트 : apple.com/apple-music

(사이트 레이아웃이 언제든 변경될 수 있기 때문에 밑 사진을 참고부탁드립니다)

 

 

(스크롤바를 일정부분 내리면 카드가 더 이상 올라가지 않고 정지합니다 ㄷㄷ)

 

 

 

 

 

 

 

위 UI를 만들기 위해 일단 HTML을 준비합니다. 

깨끗한 HTML 파일에 jQuery와 CSS 파일 하나를 첨부해준 후

이미지 3개를 다음과 같이 배치합니다.

이미지 파일은 하단에 첨부되어있습니다. 

 

설명하다
 
<div class="card-background">
  <div class="card-box">
    <img src="카드이미지1경로">
  </div>
  <div class="card-box">
    <img src="카드이미지2경로">
  </div>
  <div class="card-box">
    <img src="카드이미지3경로">
  </div>
</div>
설명하다
 
.card-background {
  height: 3000px;
  margin-top: 800px;
  margin-bottom: 1600px;
}

.card-box img {
  display: block;
  margin: auto;
  max-width: 80%;
}
.card-box {
  position: sticky;
  top: 400px;
  margin-top: 200px;
}

겁나 긴 배경에 카드를 세로로 3개 배치했고, 

position : sticky를 이용해서 스크롤시 화면에 고정되게 만들었습니다. 

여기까지만 해도 나름 봐줄만 한데

예제처럼 스크롤시 opacity가 점점 줄어드는 애니메이션도 첨가해보도록 합시다. 

 

 

 

 

 

 

스크롤 위치에 따라 opacity가 변하는 애니메이션 만들기

 

(일단 예제를 보면 스크롤을 내릴 때 카드가 1. opacity가 변하고 2. 사이즈가 줄어듭니다. 일단 1번 opacity만 구현해보도록 합시다)

 

여태까지 한 애니메이션은 one-way 애니메이션이었습니다. 

그냥 시작화면과 최종화면만 있었을 뿐인데, 지금은 스크롤 위치에 따라 opacity가 0에서 1까지 무수히 많은 중간단계가 존재합니다. 

이런 애니메이션을 어떻게 만들지 코드로 짜보도록 합시다. 

그 전에 일단 HTML 하단에 자바스크립트를 빨리 작성해보십시오. 

 

설명하다
 
$(window).scroll(function(){
    var 높이 = $(window).scrollTop();
    console.log(높이);
});

스크롤 애니메이션의 기본은 위와 같은 자바스크립트입니다. 

많이 보던 "스크롤시 내부 코드를 실행해주세요~" 라는 코드입니다. 

내부 코드엔 현재 창의 스크롤바 높이를 알려주는 (window).scrollTop(); 이라는 함수를 써본 뒤에

콘솔창에 출력을 해보았습니다. 

 

 

 

 

 

 

현재 창의 스크롤바 높이를 왜 출력해보는데여?

 

왜냐면 현재 스크롤바 높이에 따라 opacity가 변하니까 

스크롤바가 어디까지 스크롤 되면 opacity가 0이고

어디까지 스크롤 되면 opacity가 1인지 찾고 싶어서 그런거지 별 이유는 없습니다. 

 

그래서 콘솔창에 현재 스크롤바 높이를 출력하면서 측정해보았습니다. 

650px 쯤 스크롤하면 opacity를 1로,

900px 쯤 스크롤하면 opacity를 대충 0.5로,

1150px 쯤 스크롤하면 opacity를 0으로 설정하면 좋을 것 같습니다. 

이걸 코드로 표현해보도록 합시다. 

 

설명하다
 
$(window).scroll(function(){

  var 높이 = $(window).scrollTop();
  console.log(높이);
        
// 650~1150까지 스크롤바를 내리면,
// 첫째카드의 opacity 1~0으로 서서히변경해주셈
  $('.card-box').eq(0).css('opacity', ???);

});

스크롤바를 내릴 때, $('.card-box').eq(0).css('opacity', ???); 이렇게 코드가 동작하도록 설정했습니다. 

첫카드의 opacity를 ???로 변하게 해야되는데 ???는 0 이런 고정된 값으로 설정할 수 없을 것 같습니다. 

???부분은 

"스크롤바높이가 650~1150이 될 때 1~0이 되는 가변적인 값"이 되어야하겠죠? 

그래서 일단 미지의 변수인 y라고 표현합시다. 

 

 

 

설명하다
 
$(window).scroll(function(){

  var 높이 = $(window).scrollTop();
  console.log(높이);

  var y = 미지의 변수;
  $('.card-box').eq(0).css('opacity', y);

});

Q. "스크롤바높이가 650~1150이 될 때 1~0이 되는 가변적인 값"인 미지의 변수 y를 구해보십시오.

 

 

 

 

 

 

 

내가 수학전공도 아닌데 도대체 미지의 변수 y를 어떻게 구합니까?

 

잠깐 생각해본 후 펼쳐봅시다

 

 

 

 

그럼 y를 구했으니 아까 코드를 이렇게 업데이트 할 수 있겠군요 

 

쨔쟌 

설명하다
 
$(window).scroll(function(){

  var 높이 = $(window).scrollTop();
  console.log(높이);

  var y =  -1/500 * 높이 + 115/50;
  $('.card-box').eq(0).css('opacity', y);

});

스크롤바 내려보시면 opacity라는 값이 y에 의해서 결정됩니다. 

y는 스크롤 높이가 변할 때마다 매번 바뀌기 때문에 

아까와 같은 UI를 구현가능한 것입니다요. 

 

 

 

 

 

 

 

숙제 : 투명도 뿐만 아니라 카드가 0.9배 정도로 서서히 작아지는 것도 똑같이 구현해봅시다.  

 

지금까지 카드 투명도가 서서히 변하는걸 구현해 봤는데

현재 창을 650~1150만큼 스크롤 했을 때 카드의 크기가 1에서 0.9로 작아지도록 만들어주시면 됩니다. 

 

직접 짜본 후 펼쳐보지 않으면 머리가 슉슉 빠집니다.

 

사이즈를 줄이는건 transform : scale(0.9) 이런 속성을 이용하시면 되겠습니다. 

 

그런데 0.9를 그대로 박아넣는게 아니라

미지의 변수 z같은걸 만들어서 

z = a * 높이 + b 이렇게 수식을 세운 뒤 

높이가 650일 때 z는 1,

높이가 1150일 때 z는 0.9 

이니까

대입법으로 a와 b라는 상수를 구하시면 

 

 

 

쨔쟌 

설명하다
 
$(window).scroll(function(){

  var 높이 = $(window).scrollTop();
  console.log(높이);

  var y =  -1/500 * 높이 + 115/50;
  $('.card-box').eq(0).css('opacity', y);

  var z = (-1/5000) * 높이 + 565/500;
  $('.card-box').eq(0).css('transform', `scale( ${z} )`);

});

스크롤바 내려보시면 transform : scale(z) 이라는 값이 z에 의해서 결정됩니다. 

${} 이 기호는 HTML 생성 시간에 잠깐 배운 글자 중간중간에 변수 삽입 스킬입니다. 

 

그리고 화룡점정으로 더 부드러운 동작을 원하시면 

card-box라는 div에 transition : all 0.2s 같은걸 부여해주시면 되겠습니다.

 

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link href="../css/Apple Music UI.css" rel="stylesheet">
    <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
</head>
<body>
    <div class="card-background">
       <div class="card-box">
        <img src="../img/card1-150x150.png">
        </div>
        <div class="card-box">
        <img src="../img/card2-150x150.png">    
        </div>
        <div class="card-box">
        <img src="../img/card3-150x150.png">
        </div>
    </div>


    <script>

        $(window).scroll(function(){
            var 높이 = $(window).scrollTop();
            console.log(높이);
            // 780-1 1200-0 y=a*높이+b; y = -(1/420) * 높이 + 20/7
            var y = -(1/420) * 높이 + 20/7;

        $('.card-box').eq(0).css('opacity',y);    

            var z = -(1/21000) * 높이 + 740/777

         $('.card-box').eq(0).css('transform', `scale( ${z} )`);
       

        });
       
    </script>

 

.card-background{
    height: 3000px;
    margin-top: 800px;
    margin-bottom: 1600px;
}
.card-box{
    position:sticky;
    top: 400px;
    margin-top: 300px;
    transition : all 0.2s;
   
}
.card-box img{
    width: 80%;
    display: block;
    margin:auto;
    max-width: 80%;
    border-radius: 20px;
}