[CSS애니메이션] clip-path animation

이 글에서는 clip-path 설정에 대해 설명하고, clip-path 애니메이션을 학습하며 만들고 싶었던 간단한 애니메이션 예제들을 소개하겠습니다.

clip-path

clip-path는 요소의 어느 영역을 표시할지 설정하는 CSS 속성입니다. 설정된 영역 내부는 표시되고 외부는 숨겨집니다.
clip-path는 다양한 모양을 지정할 수 있으며, 기본적으로 네 가지 모양(circleellipseinsetpolygon)을 지원합니다. 또한, SVG를 활용한 복잡한 형태도 사용할 수 있습니다.

모양 설정 방법

우선, 모양을 만드는 방법에 대해 살펴보도록 하겠습니다.
(아래 예시에서 회색은 부모 영역, 주황색은 clip-path가 설정된 영역입니다.)

  • circle
    원형을 만들 때 사용하며, 반지름 값과 위치를 설정해서 적용합니다.
    예를 들어, circle(10% at 10% 20%)로 설정하면, 요소의 짧은 쪽 기준 10% 길이의 반지름인 원을 요소의 가로 10%, 세로 20% 위치를 중심으로 그립니다. 위치 값을 지정하지 않으면 기본값인 중앙으로 설정됩니다.
.circle {
  clip-path: circle(10% at 10% 20%);
}
  • ellipse
    타원을 만들 때 사용하며, 가로 반지름, 세로 반지름, 위치를 설정해서 사용합니다.
    예를 들어, ellipse(10% 20% at right center)로 설정하면, 요소 가로 길이의 10%, 세로 길이의 20%의 반지름인 타원을 오른쪽 세로 중앙 지점을 중심으로 그립니다.
.ellipse {
  clip-path: ellipse(10% 20% at right center);
}
  • inset
    사각형을 만들 때 사용하며, 요소의 상하좌우로 떨어진 거리와 곡률을 설정해서 사용합니다.
    예를 들어, inset(20% 30% round 20px) 설정 시, 상하 20%, 좌우 30% 떨어진 사각형을 곡률 20px인 형태로 그립니다.
.inset {
  clip-path: inset(20% 30% round 20px);
}
  • polygon
    특정 다각형을 만들 때 사용하며, 꼭짓점 좌표들을 설정해서 사용할 수 있습니다. 좌표는 (x%, y%) 형식으로 작성되며, (0%, 0%)가 좌측 위, (100%, 100%)가 우측 아래를 의미합니다.
    예를 들어, polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)로 설정하면, 요소의 각 변의 중간 지점을 꼭짓점으로 하는 마름모를 만들 수 있습니다. polygon을 만들기 위한 좌표를 손쉽게 설정하기 위해 해당 링크를 활용할 수 있습니다.
.polygon {
  clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
}

transition , animation 활용

clip-path와 transitionanimation을 함께 사용해, :hover와 같은 상황에서 변화와 애니메이션을 만들 수 있습니다.

/* transition 활용 */
.box {
  width: 200px;
  height: 200px;
  background: #000;
  clip-path: circle(75%);
  transition: clip-path 1s;

  &:hover {
    clip-path: circle(25%);
  }
}

/* animation 활용 */
.box {
  width: 200px;
  height: 200px;
  background: #000;
  border-radius: 20px;
  animation: circle 3s infinite alternate;

  @keyframes circle {
    0% {
      clip-path: circle(75%);
    }
    100% {
      clip-path: circle(25%);
    }
  }
}
  • 예시 : transition 적용 (:hover)
  • 예시 : animation 적용

애니메이션 적용 시 고려사항

  • 렌더링되는 내부에만 영향을 미치며, 요소 자체의 크기는 변하지 않습니다.
  • clip 영역을 넘어서는 어떤 CSS 요소든 가려지게 됩니다. 예를 들어, box-shadow가 적용된 경우에도 그림자가 가려지게 됩니다.

모양 활용 예시

간단한 애니메이션 예시를 통해 clip-path의 다양한 변화들을 확인할 수 있습니다. 지금부터 안내될 애니메이션 예시들의 기본 HTML, CSS는 다음과 같습니다.

<div class="first">
  FIRST
</div>
<div class="second">
  SECOND
</div>
.first,
.second {
  position: absolute;
  top: center;
  left: center;
  width: 200px;
  padding: 75px 0;
  border-radius: 30px;
}

.first {
  background: gray;
  animation: 8s [애니메이션 이름] infinite alternate;
}

.second {
  background: beige;
  animation: 8s [애니메이션 이름] -4s infinite alternate;
}

Circle

원형의 모양이 바뀌면서 애니메이션이 진행되는 것을 볼 수 있습니다. 앞서 살펴본 바와 같이, 75% 설정된 값은 요소 너비의 75%만큼을 반지름으로 가지게 되어, 요소보다 큰 형태의 원이 생기는 것을 볼 수 있습니다.
추가적인 설정이 없어, 원의 위치는 요소의 중앙으로 설정됩니다.

@keyframes circle {
  0%,
  100% {
    clip-path: circle(75%);
  }
  25%,
  75% {
    clip-path: circle(0%);
  }
}

Ellipse

타원의 모양이 바뀌면서 애니메이션이 진행됩니다. 현재 예시에서는 Circle과 동일하게 반지름이 50%를 넘겨 요소보다 큰 형태가 되었고, 줄어들 때에는 세로가 20%이지만 가로가 0%로 설정되어 세로로 긴 타원이 없어지는 형태로 진행됩니다.
현재도 추가적인 설정이 없어, 원의 위치는 중앙입니다.

@keyframes ellipse {
  0%,
  100% {
    clip-path: ellipse(80% 80%);
  }
  25%,
  75% {
    clip-path: ellipse(0% 20%);
  }
}

Inset

사각형 모양이 바뀌면서 애니메이션이 진행됩니다. 총 5가지 값을 설정하며, 앞의 네 가지는 각 변으로부터 멀어질 위치, 마지막 값은 ‘round’와 함께 설정해 곡률을 정할 수 있습니다(position: absolute와 함께 사용되는 inset과 동일).
아래 예시를 살펴보면, 0%로 설정되어 각 변으로부터 시작되며, 50%로 설정되어 중앙으로 이동하며, 중앙으로 이동 시에 곡률을 50%로 설정되어 원의 형태로 점점 없어지도록 설정된 것을 볼 수 있습니다. 다시 커질 때에는 기존과 동일한 사각형의 형태로 커지게 됩니다.

@keyframes inset {
  0%,
  100% {
    clip-path: inset(0% round 30px);
  }
  25%,
  75% {
    clip-path: inset(50% round 50%);
  }
}

Polygon

다각형의 모양이 바뀌는 애니메이션을 적용할 수 있습니다. 설정 시, 좌표들을 지정해 좌표들이 연결된 형태의 다각형을 만들게 되며, 이 때 부드러운 애니메이션을 위해서는 시작, 끝 지점의 애니메이션의 좌표값이 일치해야 합니다. 일치되지 않을 경우 끊어진 애니메이션이 만들어 집니다.
현재 예시에서 시작, 끝 지점에 동일하게 8개의 좌표가 사용되고 있으며, 해당 좌표들 중 일부를 가운데(50%, 50%)에 모이도록 설정하여, 요소가 접혔다가 펴지는 애니메이션을 만들어진 것을 볼 수 있습니다.

@keyframes polygon {
  0%, 100% { clip-path: polygon(0 0, 0 50%, 0 100%, 50% 100%, 100% 100%, 100% 50%, 100% 0, 50% 0); }
  25%, 75% { clip-path: polygon(0 0, 50% 50%, 0 100%, 50% 50%, 100% 100%, 50% 50%, 100% 0, 50% 50%); }
}

움직임 활용 예시

앞서 살펴본 모양을 활용한 예시를 토대로, 특별한 움직임들을 가져가는 애니메이션을 만들 수 있습니다.

Rotate

사각형이 회전하는 형태를 만드는 애니메이션입니다. polygon이 사용되며, 각 좌표들의 위치를 변경함으로써 사각형이 회전하는 형태를 만들어주게 됩니다.
아래 예시를 살펴보면, 10%일 때부터 네 개의 좌표를 지속적으로 설정해주게 되는데, 처음에 설정된 좌표를 시작으로 각 좌표의 순서에 입력된 값으로 이동하는 애니메이션을 만들면서 회전 효과를 주게 됩니다. 이러한 좌표값들의 설정을 통해 다양한 도형의 애니메이션들을 만들 수 있습니다.

@keyframes rotate {
  10% {
    clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 100%);
  }
  20% {
    clip-path: polygon(87.5% 12.5%, 87.5% 87.5%, 12.5% 87.5%, 12.5% 12.5%);
  }
  30% {
    clip-path: polygon(75% 75%, 25% 75%, 25% 25%, 75% 25%);
  }
  40% {
    clip-path: polygon(37.5% 62.5%, 37.5% 37.5%, 62.5% 37.5%, 62.5% 62.5%);
  }
  50%,
  100% {
    clip-path: polygon(50% 50%, 50% 50%, 50% 50%, 50% 50%);
  }
}

Spotlight

원이 생성되어 여러 지역을 보여준 뒤 사라지는 것을 반복하는 애니메이션입니다.
아래 예시를 살펴보면, 원을 생성하는 것이므로 circle이 사용되고, 원이 이동하는 효과를 주기 위해 circle 설정 중 at의 값을 변경함으로써 spotlight 효과를 주게 됩니다.

@keyframes spotlight {
  10% {
    clip-path: circle(100% at 50% 50%);
  }
  20% {
    clip-path: circle(20% at 50% 50%);
  }
  30% {
    clip-path: circle(20% at 20% 70%);
  }
  40% {
    clip-path: circle(20% at 90% 40%);
  }
  50%,
  100% {
    clip-path: circle(20% at -30% 20%);
  }
}

path() 활용하기

clip-path의 속성 중 path()를 사용하는 방법이 있습니다. 이 방법은 SVG를 사용하여 복잡한 곡선 모양을 제어할 수 있습니다.
하지만, 아래와 같은 제한점이 존재해 사용 시 주의가 필요합니다.

  • % 형태의 설정이 불가능해 요소의 크기에 맞는 SVG를 설정해주어야 합니다.
  • path 설정 시 각 지점들(C, L 등의 포인트들)을 같은 개수만큼 매칭해야 원하는 애니메이션이 구현됩니다.
  • 모든 브라우저에서 적용하는 데 어려움이 있을 수 있습니다. (Can I Use : https://caniuse.com/mdn-css_properties_clip-path_path)

예시 : 녹아내리는 모션

녹아내리는 듯한 모션을 주는 애니메이션입니다. path 내부에 곡선과 직선을 그리도록 설정되어 있으며, 앞서 언급했듯 애니메이션이 동작하기 위해서는 path 내에 그려진 초점들이 이어지는 흐름이 자연스러워야 합니다.
애니메이션의 시작부터 끝까지 각 지점들(C, L)이 동일한 개수 및 순서대로 설정된 것을 확인하실 수 있습니다.

.first {
  animation:
    4s melt-enter,
    4s melt-leave 4s;
}

@keyframes melt-enter {
  0% {
    clip-path: path(
      'M0 -0.12 C8.33 -8.46 16.67 -12.62 25 -12.62 C37.5 -12.62 35.91 0.15 50 -0.12 C64.09 -0.4 62.5 -34.5 75 -34.5 C87.5 -34.5 87.17 -4.45 100 -0.12 C112.83 4.2 112.71 -17.95 125 -18.28 C137.29 -18.62 137.76 1.54 150.48 -0.12 C163.19 -1.79 162.16 -25.12 174.54 -25.12 C182.79 -25.12 191.28 -16.79 200 -0.12 L200 -34.37 L0 -34.37 L0 -0.12Z'
    );
  }
  100% {
    clip-path: path(
      'M0 199.88 C8.33 270.71 16.67 306.13 25 306.13 C37.5 306.13 35.91 231.4 50 231.13 C64.09 230.85 62.5 284.25 75 284.25 C87.5 284.25 87.17 208.05 100 212.38 C112.83 216.7 112.71 300.8 125 300.47 C137.29 300.13 137.76 239.04 150.48 237.38 C163.19 235.71 162.16 293.63 174.54 293.63 C182.79 293.63 191.28 262.38 200 199.88 L200 0.13 L0 0.13 L0 199.88Z'
    );
  }
}

@keyframes melt-leave {
  0% {
    clip-path: path(
      'M0 0 C8.33 -8.33 16.67 -12.5 25 -12.5 C37.5 -12.5 36.57 -0.27 50 0 C63.43 0.27 62.5 -34.37 75 -34.37 C87.5 -34.37 87.5 -4.01 100 0 C112.5 4.01 112.38 -18.34 125 -18.34 C137.62 -18.34 138.09 1.66 150.48 0 C162.86 -1.66 162.16 -25 174.54 -25 C182.79 -25 191.28 -16.67 200 0 L200 200 L0 200 L0 0Z'
    );
  }
  100% {
    clip-path: path(
      'M0 200 C8.33 270.83 16.67 306.25 25 306.25 C37.5 306.25 36.57 230.98 50 231.25 C63.43 231.52 62.5 284.38 75 284.38 C87.5 284.38 87.5 208.49 100 212.5 C112.5 216.51 112.38 300.41 125 300.41 C137.62 300.41 138.09 239.16 150.48 237.5 C162.86 235.84 162.16 293.75 174.54 293.75 C182.79 293.75 191.28 262.5 200 200 L200 200 L0 200 L0 200Z'
    );
  }
}

실제 활용 예시

실제 서비스에서 활용 가능할만한 예시를 소개합니다.

See the Pen clip-path animation examples by WITBLOG (@witblog) on CodePen.

사진 넘기기

다음, 이전 버튼을 클릭 시 넘어가는 애니메이션과 함께 다음 또는 이전 사진을 보여줍니다. 해당 애니메이션 적용 시 clip-path의 속성 중 inset을 활용했으며, 겹쳐져 있는 여러 사진들 중, 현재 보여줄 사진에 대해서만 inset을 통해 보여주는 형태로 적용됐습니다.
이전 ∙ 다음 사진을 보여주기 위한 별도의 요소 이동없이 설정이 가능하다는 장점이 있습니다.

.picture.start {
  clip-path: inset(15% 15% -60% round 260px);
}

.picture.slideOutUp {
  animation-name: slideOutUp;
}

.picture.slideInUp {
  animation-name: slideInUp;
  animation-delay: 0.9s;
}

@keyframes slideInUp {
  0% {
    clip-path: inset(110% 35% -100% round 120px);
  }
  40% {
    clip-path: inset(5% 35% 15% round 120px);
  }
  55% {
    clip-path: inset(12% 35% 8% round 120px);
  }
  70% {
    clip-path: inset(10% 35% round 120px);
  }
  100% {
    clip-path: inset(15% 15% -60% round 260px);
  }
}

@keyframes slideOutUp {
  0% {
    clip-path: inset(15% 15% -60% round 260px);
  }
  40% {
    clip-path: inset(10% 35% round 120px);
  }
  60% {
    clip-path: inset(12% 35% 8% round 120px);
  }
  100% {
    clip-path: inset(-100% 35% 110% round 120px);
  }
}

뽀모도로 타이머

앞서 설명되었던 path()의 설정 중 간단한 형태인 원을 일부 활용한 애니메이션입니다. 애니메이션 생성 시 원을 원하는 만큼 채울 수 있는 점을 활용해 만들게 되며, 해당 애니메이션에서는 원이 생성되는 마지막 지점을 변경하는 방식으로 적용했습니다.
(A 설정의 마지막 지점 변경 : 287, 90 → 275, 232 → …)
현재 handRotate의 설정 중 20% → 100%로 바로 변경할 시, 원을 생성하는 마지막 지점이 바로 [287, 90 → 25, 67]로 이동하게 되어 자연스럽지 않은 애니메이션이 생성되기 때문에, 자연스러운 원의 움직임을 위해 20% 단위로 나눠서 적용했습니다.

.clock .hand {
  clip-path: path("M150,0 A150,150 0,1,1 163,1 L150,150 Z");
  animation: handRotate 3s linear 1s forwards;
}

@keyframes handRotate {
  20% {
    clip-path: path("M150,0 A150,150 0,1,1 287,90 L150,150 Z");
  }
  40% {
    clip-path: path("M150,0 A150,150 0,1,1 275,232 L150,150 Z");
  }
  60% {
    clip-path: path("M150,0 A150,150 0,1,1 136,300 L150,150 Z");
  }
  80% {
    clip-path: path("M150,0 A150,150 0,1,1 10,204 L150,150 Z");
  }
  100% {
    clip-path: path("M150,0 A150,150 0,1,1 25,67 L150,150 Z");
  }
}

마무리

clip-path를 활용해 요소의 특정 부분만 보여주는 방법을 이해하면, 원이나 사각형 같은 간단한 모양부터 polygonpath() 등 복잡한 모양까지 활용된 다양한 애니메이션을 연출할 수 있습니다.
이 글을 읽으신 분들 중 CSS 애니메이션과 관련된 설정에 어려움을 겪는 분이 계신다면, 앞서 소개한 clip-path의 간단한 예시들을 떠올려, CSS 애니메이션 적용에 조금이나마 도움이 되시기를 바랍니다!

출처


0개의 댓글

답글 남기기

아바타 플레이스홀더

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다