CSS border-image 애니메이션하기
요약
본 글은 CSS의 border-image 속성을 활용하여 일반적인 테두리 스타일을 넘어 이미지나 그라디언트를 적용하는 방법을 설명합니다. 특히 `border-image`와 그라디언트 애니메이션에 초점을 맞추어, 사용자 인터페이스(UI)를 위한 흥미로운 시각 효과 구현 방안을 제시하고 있습니다.
핵심 포인트
- CSS border-image로 이미지나 그라디언트를 테두리로 사용 가능합니다.
- 애니메이션 구현을 위해 `border-image`와 그라디언트 조합이 효율적입니다.
- `border-image-outset` 속성으로 테두리를 요소로부터 분리할 수 있습니다.
CSS border-image
속성은 우리가 당연하게 여기는 기능 중 하나입니다. 그리고 전혀 새로운 것이 아닙니다! 사실, Andy Clarke가 이 속성을 '재조명'하며 얼마나 창의적으로 활용할 수 있는지 보여주는 상당히 최근의 글이 있습니다. 그 글을 읽어보세요. 가치가 충분합니다.
요약하자면, 표준적인 (흠, 지루한) 스타일인 실선이나 점선 테두리 대신 이미지나 그라디언트를 테두리로 사용할 수 있다는 것입니다. 제가 하고 싶은 것은 이를 한 단계 더 발전시켜 더욱 흥미로운 사용자 인터페이스를 위해 border image를 애니메이션하는 방법을 보여주는 것입니다!
이렇게요:
애초에 border images가 필요한 이유?
border images에는 상당히 큰 제약 사항이 있습니다: 테두리 모양으로 휘어지지 않는다는 것입니다. 이는 우리가 여기서 하는 것처럼 요소 주변을 돌아다니는 애니메이션에는 큰 한계입니다. 하지만 이 예시를 위해 우회할 수 있습니다.
하지만 이것은 또 다른 질문을 던지게 합니다: “다른 접근 방식이 있는데 왜 우회해야 할까?” Temani Afif가 CSS mask를 사용한 접근 방식을 보세요 (그는 이에 대한 훌륭한 글을 작성했습니다):
저는 border-image가 좋아요
왜냐하면 특히 border image와 그라디언트를 애니메이션할 때 매우 효율적이기 때문입니다. 주로 모든 테두리에 걸쳐 디자인을 재현하기 쉽다는 점—자동적이라는 점—그리고 또한 border-image-slice 속성을 사용하여 이미지를 '슬라이스' 할 수 있다는 점 때문입니다. 이는 단일 이미지 조각을 사용할 수 있는 background-size와 background-position과 유사합니다. 하지만 border image 슬라이스는 전체 테두리에 걸쳐 실행될 수 있으며, 이를 애니메이션하면 보시다시피 아름다운 효과를 만들어냅니다.
HTML
우리는 여기서 별거 하는 것이 없습니다. 단순히 포맷된 텍스트가 포함된 div만 있습니다:
<div class=card><strong>Bruce Wayne</strong></div>
이미지는 어떻게 설정할까요? CSS 배경으로 설정되어 있으므로, 바로 그 부분부터 살펴보겠습니다.
기본 스타일
우리는 .card에 크기를 지정한 다음 배경 이미지를 적용합니다:
.card {
width: 150px;
aspect-ratio: 0.69;
...
멋지네요, 멋져요. 배경 위에 정확히 붙지 않도록 텍스트에도 약간의 스타일링을 추가하겠습니다:
테두리 이미지 (The border image)
저는 단일 색상 CSS 그라디언트를 사용할 것입니다. 왜냐하면 (1) 이것이 일종의 배경 이미지이고, (2) 애니메이션을 시연하기가 조금 더 쉽기 때문입니다.
또한 border-image의 모든 값을 개별적인 긴 속성(longhand properties)으로 설정하여, 어떤 값이 그라디언트에 어떻게 영향을 미치는지 명확하게 알 수 있도록 하겠습니다.
간단한 linear-gradient의 효과부터 시작해 보겠습니다:
.card {
/* ... */
/* 선형 색상 생성 (Creates a linear color) */
...
데모에서 애니메이션된 테두리와 이미지 사이에 약간의 간격이 있다는 것을 알아차리셨을 수 있습니다. border-image-outset 속성을 사용하여 테두리를 .card로부터 멀어지게 할 수 있습니다:
.card {
/* ... */
border-image-source: linear-gradient(-45deg, red 0%, transparent 0%);
...
테두리를 렌더링하려면 border-image-source와 border-image-width가 필요합니다. 초기에는 이미지 소스(그라디언트)가 완전히 투명합니다. red와 transparent 두 색상 모두 시작점이 0%로 설정되어 있기 때문에, 브라우저는 색상을 블렌딩할 공간이 없으며, transparent가 코드에서 두 번째에 오기 때문에 시작 위치를 0%로 가져가고 나머지 그라디언트를 채웁니다. 우리는 border-image-slice: 1을 사용하여 그라디언트의 1px 조각(slices)을 만들고, 이것이 전체 테두리에 걸쳐 부드러운 그라디언트 채우기를 만듭니다.
테두리 이미지 애니메이션하기 (Animating the border image)
그라디언트에 대해 기억해야 할 다른 점이 있습니다. 특히 애니메이션에 관한 것입니다: 기본적으로는 그라디언트를 애니메이션할 수 없습니다. 한 색상에서 다른 색상으로 전환(Transitioning 또는 Interpolating)하는 것은 어렵습니다. 왜냐하면 본질적으로 그라디언트의 시작점과 끝점을, 즉 백분율로 전환하기 때문입니다.
이때 우리가 직접 사용자 정의 속성(custom property)을 등록할 수 있다는 점이 중요해집니다. CSS 변수는 실제로 애니메이션할 수 있기 때문입니다:
@property --p {
syntax: "<percentage>";
initial-value: 0%;
...
그리고 이것을 우리의 그라디언트에서 사용할 수 있습니다:
이제 .card가 호버될 때 --p가 기본값인 0%에서 100%로 전환되도록 한다고 가정해 봅시다:
.card {
/* ... */
border-image-source: linear-gradient(-45deg, red var(--p), transparent 0%);
...
이 코드는 브라우저에게 빨간색이 100% 지점(가장 끝)에서 전환을 마쳐야 함을 알려줍니다. 그라디언트는 마치 테두리가 스스로 그려지는 것처럼 단색의 빨간색으로 커질 것입니다:
변형 (Variations)
마지막 예시에서 멈출 수도 있지만, 여기서 할 수 있는 것이 너무 많습니다! 방향을 바꾸거나, 더 빠르거나 느리게 하거나, 다른 위치에 멈추거나, 심지어 다른 유형의 그라디언트를 사용할 수도 있습니다. 정말 재미있습니다.
대신 conic-gradient를 사용해 보는 것은 어떨까요? 우리는 border-image-slice 값을 애니메이션하고, border-image-repeat: round를 사용하여 테두리 내부의 슬라이스를 타일링할 수 있습니다. round 타일링은 테두리에 정수 개의 타일을 맞추려고 시도하며, 만약 불가능하다면 이미지가 적절한 개수가 맞춰질 때까지 약간 늘어나거나 줄어듭니다.
.card {
/* 사용자 정의 각도 변수를 사용하여 날카롭고 확장되는 컬러 휠 생성 */
border-image-source: conic-gradient(from 0deg, red 0deg, transparent 0%);
...
그라디언트를 움직이게 하려면 여전히 사용자 정의 속성을 등록해야 합니다. 이번에는 border-image-slice 값(우리는 이를 --n이라고 부를 것입니다)과 conic-gradient의 각도(우리는 이를 --a라고 부를 것입니다)를 전환하기 위함입니다:
참고: border-image-slice를 등록된 사용자 정의 속성을 통하지 않고 직접 애니메이션할 수도 있습니다. 이 경우 결과는 브라우저가 이러한 변경 사항을 처리하는 방식에 따라 약간 다를 수 있습니다.
/* border-image-slice를 위한 사용자 정의 속성 등록 */
@property --n {
syntax: "<number>";
...
이것들을 원래 CSS에 적용해 봅시다:
.card {
border-image-source: conic-gradient(from var(--a), red var(--a), transparent 0%);
border-image-width: 5px;
...
…그리고 CSS에 어떤 속성을 전환할지 정확히 알려주어 성능에 좋습니다:
.card {
border-image-source: conic-gradient(from var(--a), red var(--a), transparent 0%);
border-image-width: 5px;
...
…그리고 호버 시 속성을 전환합니다:
.card {
border-image-source: conic-gradient(from var(--a), red var(--a), transparent 0%);
border-image-width: 5px;
...
슬라이스 값(--n)은 처음에 1입니다.
호버 시에는 20까지 올라갑니다. 이는 슬라이스가 더 커진다는 것을 의미합니다 (최대 20px 두께). 테두리에서 끊기는 부분을 보면 이를 알 수 있습니다.
추가 예제!
앞서 말씀드렸듯이, 애니메이션 가능한 테두리 이미지로는 정말 많은 것을 할 수 있습니다. 여러 색상을 애니메이션하거나 반복 그라디언트를 사용할 수도 있습니다. 제가 모아온 예제들이 여기 있습니다.
여러분 숙제입니다: 이들을 분석해 보시고, 혹시 다른 효과를 만드셨다면 알려주세요! 보고 싶습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 CSS-Tricks의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기