[코딩애플] JavaScript 강의 정리 (Level3 15강 ~ 16강)

이언덕·2024년 5월 19일

코딩애플

목록 보기
21/37
post-thumbnail

15강 / position : sticky 활용하기

sticky란?


스크롤이 되었을 때 화면에 고정되는 요소를 만들고 싶을 때 사용할 수 있는 CSS 속성이다.
CSS - Position: Sticky 를 잘 적용 하려면?



position : sticky vs position : fixed

(Edge 이상에서 사용가능)
position : fixed는 항상 화면에 고정이 되는 요소를 만들 때 사용한다고 배웠었는데 이거랑 뭔 차이가 있냐면,
position : sticky 는 스크롤이 되어서 이 요소가 화면에 나오면 고정시킨다는 특성이 있다.

한번 예제를 만들어 활용해보자

<body style="background: grey; height: 3000px">
    <div class="grey">
      <div class="image">
        <img src="./assets/파워퍼프걸 썬구리.JPG" width="100%" />
      </div>

      <div style="clear: both"></div>
      <div class="text">Meet the first Triple Camera System</div>
    </div>

</body>
.grey {
  background: lightgrey;
  height: 2000px;
  margin-top: 500px;
}
.text {
  float: left;
  width: 300px;
}
.image {
  float: right;
  width: 400px;
  position: sticky;
  top: 100px;
}

이렇게 작성하면 검고 긴 화면에 텍스트와 이미지가 하나씩 보인다.
이미지에 position : sticky를 주면
1. 스크롤이 되어서 이미지가 보이는 순간
2. viewport의 맨 위에서부터 100px 위치에서 고정이 된다.
3. 그리고 부모 박스를 넘어서 스크롤 되면 이미지도 같이 사라진다.

(주의점) position : sticky
1. 스크롤을 할 만한 부모 박스가 있어야하고
2. top 등 좌표속성과 함께 써야 제대로 보인다.
응용하면 남들과는 다른 레이아웃을 만들 수 있다.




16강 / 스크롤 위치에 따라 변하는 애니메이션 : Apple Music UI 만들기


우리는 위와 같은 UI를 만들어볼 예정이다!

위 UI를 만들기 위해 일단 HTML을 준비하기

index파일에 준비된 HTMLCSS를 붙여넣을 것이다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <link
      href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
      rel="stylesheet"
      integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3"
      crossorigin="anonymous" />
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" type="text/css" href="./index.css" />
    <title>Level3</title>
  </head>
  <body>
    <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>

    <script src="./index.js"></script>
  </body>
</html>
.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 애니메이션이었다. (one-way 애니메이션이 기억이 나질 않는다면 아래사이트 참고)
one-way 애니메이션 1
one-way 애니메이션 2

그냥 시작화면과 최종화면만 있었을 뿐인데, 지금은 스크롤 위치에 따라 opacity가 0에서 1까지 무수히 많은 중간단계가 존재한다.
이런 애니메이션을 어떻게 만들지 코드로 짜보도록 해보자.

그 전에 일단 아래 자바스크립트를 빨리 작성해보자.

window.addEventListener("scroll", function() {
  let height = window.scrollY
  console.log(height);
});

스크롤 애니메이션의 기본은 위와 같은 자바스크립트이다.
많이 보던 "스크롤시 내부 코드를 실행해주세요~" 라는 코드이다.
내부 코드엔 현재 창의 스크롤바 높이를 알려주는 window.scrollY;; 이라는 함수를 써본 뒤에
콘솔창에 출력을 해보았다.

현재 창의 스크롤바 높이가 콘솔에 출력된다.

왜 현재 창의 스크롤바 높이를 출력할까?

왜냐면 현재 스크롤바 높이에 따라 opacity가 변하니까
스크롤바가 어디까지 스크롤 되면 opacity0이고
어디까지 스크롤 되면 opacity1인지 찾고 싶어서 출력해본 것이다.

650px 쯤 스크롤하면 opacity1로,
900px 쯤 스크롤하면 opacity를 대충 0.5로,
1150px 쯤 스크롤하면 opacity0으로 설정하면 좋을 것 같다.
이걸 코드로 표현해보자.

const cardBox = document.querySelectorAll(".card-box");

window.addEventListener("scroll", function () {
  let height = window.scrollY;
  console.log(height);

  // 650~1150까지 스크롤바를 내리면,
  // 첫째카드의 opacity 1~0으로 서서히변경해야함
  cardBox[0].style.opacity = ???
});

첫카드의 opacity???로 변하게 해야되는데 ???0 이런 고정된 값으로 설정할 수 없을 것 같다.
???부분은
"스크롤바높이가 650~1150이 될 때 1~0이 되는 가변적인 값"이 되어야할 것 같다.
그래서 일단 미지의 변수인 y라고 표현해두자.

const cardBox = document.querySelectorAll(".card-box");

window.addEventListener("scroll", function () {
  let height = window.scrollY;
  console.log(height);

  let y = ???

  // 650~1150까지 스크롤바를 내리면,
  // 첫째카드의 opacity 1~0으로 서서히변경해야함
  cardBox[0].style.opacity = y
});

y구하는 법

  1. "스크롤바높이가 650~1150이 될 때 1~0이 되는 가변적인 값"을 구하면 된다.
    그래프로 표현해보면 이렇다.

    그림으로 표현해보면 이럴 것이다.
    높이가 650~1150 이렇게 변할 때 1에서 0이 되는건 저런 그래프로 표현할 수 있을 것 같다.
    (여기서 높이라는건 아까 출력해본 높이 변수이다)
    이걸 수학용어로 치면 1차함수라고 부른다.

  2. 그럼 이걸 수식으로 표현해보자.
//수학
y = a * 높이 + b

y에 대한 1차함수는 우리가 뭐 기울기 이런걸 모를 때 일단 ax+b 이런 식으로 표현할 수 있다고 배웠다.
그럼 ab라는 미지수만 잘 구하면 y가 뭔지 알 수 있는 것이다.
a는 전문용어로 기울기, b는 전문용어로 y절편이라고 한다.
그건 너무 어려우니 우리는 대입법을 이용해보도록하자.


3. a,b를 구하는건 대입법을 이용한다.
위의 함수는
높이가 650일 때 y1,
높이가 1150일 때 y0이다.

//수학
1 = a * 650 + b
0 = a * 1150 + b

그럼 이렇게 대입해봐도 맞는 것 같다.
방정식이 두개고 미지수가 두개면 충분히 풀 수 있다.
그래서 연습장에 방정식을 잘 풀어보면

//수학
1 = a * 650 + b
0 = a * 1150 + b
a = -1/500
b = 115/50

이렇게 나온다.
그럼 ab값을 아까 y를 표현하던 수식에 대입하면

//다시 자바스크립트
let y = -1/500 * 높이 + 115/50

이렇게 된다.

이제 y를 구했으니 아까 코드를 이렇게 업데이트 할 수 있을 것 같다.

const cardBox = document.querySelectorAll(".card-box");

window.addEventListener("scroll", function () {
  let height = window.scrollY;
  console.log(height);

  let y = (-1 / 500) * height + 115 / 50;

  // 650~1150까지 스크롤바를 내리면,
  // 첫째카드의 opacity 1~0으로 서서히변경해야함
  cardBox[0].style.opacity = y;
});


스크롤바 내려보시면 opacity라는 값이 y에 의해서 결정됩니다.
y는 스크롤 높이가 변할 때마다 매번 바뀌기 때문에
아까와 같은 UI를 구현가능한 것이다.



숙제

카드 1만 투명도를 씌우지 않고 전체 다 씌우기

const cardBox = document.querySelectorAll(".card-box");

window.addEventListener("scroll", function () {
  let height = window.scrollY;
  console.log(height);

  let y = (-1 / 500) * height + 115 / 50;

  // 650~1150까지 스크롤바를 내리면,
  // 첫째카드의 opacity 1~0으로 서서히변경해야함
  cardBox.forEach((a, i) => {
    cardBox[i].style.opacity = y;
  });
});

forEach를 사용해서 순환하면서 투명도를 씌울 수 있도록 하였다.


투명도 뿐만 아니라 카드가 0.9배 정도로 서서히 작아지는 것도 똑같이 구현해봅시다.
지금까지 카드 투명도가 서서히 변하는걸 구현해 봤는데
현재 창을 650~1150만큼 스크롤 했을 때 카드의 크기가 1에서 0.9로 작아지도록 만들어주시면 됩니다.

사이즈를 줄이는 것은 transform : scale(0.9)이런 속성을 이용하면 된다.

const cardBox = document.querySelectorAll(".card-box");

window.addEventListener("scroll", function () {
  let height = window.scrollY;
  console.log(height);

  let y = (-1 / 500) * height + 115 / 50;
  // 650~1150까지 스크롤바를 내리면,
  // 모든카드가 opacity 1~0으로 서서히변경해야함
  cardBox.forEach((a, i) => {
    cardBox[i].style.opacity = y;
  });

  // 650~1150까지 스크롤바를 내리면,
  // 모든카드가 transform 1 ~ 0.9으로 서서히변경해야함
  let z = (-1 / 5000) * 높이 + 565 / 500;
  cardBox.forEach((a, i) => {
    cardBox[i].style.transform = `scale(${z})`;
  });
});



전체코드

index.html

<!DOCTYPE html>
<html lang="en">
 <head>
   <link
     href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
     rel="stylesheet"
     integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3"
     crossorigin="anonymous" />
   <meta charset="UTF-8" />
   <meta name="viewport" content="width=device-width, initial-scale=1.0" />
   <link rel="stylesheet" type="text/css" href="./index.css" />
   <title>Level3</title>
 </head>
 <body>
   <div class="card-background">
     <div class="card-box">
       <img src="./assets/파워퍼프걸 썬구리.JPG" />
     </div>
     <div class="card-box">
       <img src="./assets/파워퍼프걸 썬구리.JPG" />
     </div>
     <div class="card-box">
       <img src="./assets/파워퍼프걸 썬구리.JPG" />
     </div>
   </div>

   <script src="./index.js"></script>
 </body>
</html>

index.js
const cardBox = document.querySelectorAll(".card-box");

window.addEventListener("scroll", function () {
  let height = window.scrollY;
  console.log(height);

  let y = (-1 / 500) * height + 115 / 50;
  // 650~1150까지 스크롤바를 내리면,
  // 모든카드가 opacity 1~0으로 서서히변경해야함
  cardBox.forEach((a, i) => {
    cardBox[i].style.opacity = y;
  });

  // 650~1150까지 스크롤바를 내리면,
  // 모든카드가 transform 1 ~ 0.9으로 서서히변경해야함
  let z = (-1 / 5000) * 높이 + 565 / 500;
  cardBox.forEach((a, i) => {
    cardBox[i].style.transform = `scale(${z})`;
  });
});

index.css

.card-background {
  height: 3000px;
  margin-top: 800px;
  margin-bottom: 1600px;
}

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


0개의 댓글