본문 바로가기
html & css

@keyframes 를 써서 고양이 시선을 빼앗아 보자

by 왜 안되지 2022. 3. 3.

 

야옹이 모니터 안덮치게 조심

 

처음과 끝 상태만 있는 transition 말고 복잡한 애니메이션을 구현해야 한다면 @keyframes 를 써보자.

 

//index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="index.css" />
    <title>Document</title>
  </head>
  <body>
    <div class="btn-wrap">
      <button class="btn">고양이 조심</button>
    </div>
  </body>
</html>

 

//index.scss

.btn-wrap {
  width: 100vw;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  .btn {
    background-color: yellowgreen;
    width: 200px;
    height: 100px;
    border: 1px solid yellowgreen;
    border-radius: 5px;
    color: white;
    font-size: 30px;
    &:hover {
      animation-name: shake;
      animation-duration: 0.5s;
    }
  }
}

@keyframes shake {
  0% {
    transform: rotateX(0);
  }
  20% {
    transform: rotateZ(-10deg);
  }
  50% {
    transform: rotateZ(10deg);
  }
  80% {
    transform: rotateZ(-10deg);
  }
  100% {
    transform: rotateX(0);
  }
}

 

@keyframes 이름 {

}

으로 작성하고 그 안에 진행 상황별 상태를 정의해 놓는다.

그 안에 진행상황을 %로 입력하는데 순서만 잘 지키면 몇가지로 세분화 하든 상관없다.

 

만들어둔 keyframes를 가져다 쓸때는 

animation-name: 이름;

으로 가져다 쓰는데

여러가지 옵션들이 있다.

 

대표적으로 

  • animation-duration: 한 사이클이 돌때 애니메이션의 총 시간
    • 0으로 설정하면 애니메이션 재생되지 않음
    • 음수로 설정하면 애니메이션 재생되지않음
    • ex) animation-duration: .5s  // 전체 애니메이션 시간이 0.5초에 걸쳐 일어남 
  • animation-delay: 해당 엘리먼트가 로드되고 나서 언제 애니메이션이 시작될지 지정
    • 0: 기본값, 로드 되자마자 실행
    • now: 0으로 설정한 것과 같다. ios2.0부터 사용가능
    • 음수: 음수로 값을 설정하면 로드 되자마자 실행 하지만 지정한 시간 만큼이 지난 후부터의 장면부터 재생한다. 예를들어 animation-delay: -1s; 로 설정하면 1초가 지난 후의 장면부터 바로 재생된다.
    • ex) animation-delay: 1s  // 1초 후에 실행
  • animation-iteration-count: 애니메이션 재생 횟수를 정의한다.
    • 1: 기본값. 한번 실행.
    • infinite: 애니메이션 무한 반복
    • ex) animation-iteration-count: 2.8;  // 애니메이션이 2번 반복된 다음 전체 프레임의 8/10에 해당하는 프레임까지 재생됨.
  • animation-timing-function: 애니메이션 키프레임 사이의 재생속도를 지정.
    • ex) animation-timing-function: ease-in-out;  //시작 부분 재생속도를 점점 빠르게 하고 마지막 부분 재생속도를 점점 느리게

그런데 말입니다.

//예시 1 

@keyframes move {
  0% {
    transform: translateX(0);
  }
  50% {
    transform: translateX(20px);
  }
  100% {
    transform: translateX(0);
  }
}

 

// 예시 2

@keyframes move {
  0% {
    margin-left:0;
  }
  50% {
    margin-left:20px;
  }
  100% {
    margin-left:0;
  }
}

 

transform: translateX(20px);
굳이 이렇게 길게 쓰지않고

margin-left: 20px;

이렇게 짧게 쓰면 코드량도 줄고 좋지 않나요 ?

왜 굳이 transform: translateX(20px); 이렇게 길게 쓰나요 ?

 

이유는 transform 변경보다 margin 변경이 더 느려서 그렇습니다.

 

첫번째 이유

브라우저가 화면에 그림을 그리는 순서를 보면

1. render tree 만들기

2. layout 잡기  ( 네모 박스들 위치 잡기 )

3. paint 하기  ( 픽셀에 색칠하기 )

4. composite 처리하기 ( transform 이나 opacity 같은 애들 있으면 처리하기 )

순으로 합니다.

 

그런데 width, height, margin, padding 등의 애들은 변경이 되면 2번 layout 잡기 부터 2,3,4 순으로 다시 실행이 되고 

background-color 같은 색관련 애들은 변경이 되면 3번 paint 하기 부터 3,4 순으로 다시 실행,

transform, opacity 같은 애들 변경이 되면 4번만 재실행 됩니다.

 

그래서 2,3,4 를 다시 하는거보다 4번만 다시 하는 transform 을 쓴다~ 이말입니다.

 

한가지 이유가 더 있습니다.

 

두번째 이유

transform 이런거는 다른 쓰레드에서 처리해 줍니다.
웹 브라우저는 원래 쓰레드 1개만 사용하는데 ( 자바스크립트 실행, html, css 처리 전부 한 쓰레드에서 처리 )


이외에도 성능 잡을수 있는 두가지 방법이 있는데

 

방법1. will-change 를 쓴다.

.box {
  will-change: transform;
}

 

will-change: 애니메이션 줄 속성;

요고 쓰면 바뀔 내용을 미리 렌더링 해줌.

근데 뭔가 이상하게 버벅일 때만 쓰고 애니메이션이 스무스하게 잘 될때는 쓸필요 음슴.

이상하게 많이 쓰면 브라우저 오히려 더 느려질수도 있음.

 

방법 2.하드웨어 가속

.box {
  transform: translate3d(0, 0, 0);
}

 

transform: translate3d 를 쓰면 3D 이동이 되는데 이 속성은 GPU를 사용해서 연산함.

그래서 translate3d(0,0,0) 이런식으로 아무데도 움직이지 않는 3d 이동명령 주고 뒤에 필요한 transform 적용하면 GPU 이용해서 .box가 가진 transform 속성 연산을 하게 됨.

'html & css' 카테고리의 다른 글

Anti-aliasing  (1) 2023.10.23
화면 reflow 가 일어나는 경우  (0) 2022.11.22

댓글