이전 애니메이션 | 로딩 스피너
미리보기
현재 포스트를 따라오시면 다음과 같은 애니메이션을 구현할 수 있는 능력을 갖추게 되십니다.
HTML
이번 포스트는 HTML 을 직접적으로 생성할 일은 없습니다. 향후 JS 를 이용해 동적으로 생성할 것입니다.
CSS
CSS 초기화
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
우선 margin 과 padding 을 0 으로 지정하여 기본적으로 설정한 여백을 제거해 줍니다. box-sizing 을 border-box 로 지정하여 콘텐츠의 넓이를 계산 할 때 margin 과 padding 의 값도 포함되도록 해줍니다.
body 설정
body {
background: rgba(0, 0, 0, 0.8);
width: 100%;
height: 100vh;
}
뷰포트의 전체에 배경색을 입히기 위해서 width 와 height 을 각각 100%, 100vh 으로 지정하여 body 태그가 뷰포트의 전체를 채우도록 해줍니다.
그 후 background를 rgba(0,0,0,0.8) 을 지정하고, 마지막 알파(투명도)를 0.8 로 지정함으로써 다음과 같은 색상이 되도록 해줍니다.
.spark 설정
.spark {
position: absolute;
}
우선 스파크 애니메이션의 몸체가 되는 요소가 현재의 DOM 흐름과 별개의 레이어를 구성하도록 position을 absolute 로 지정해줍니다. 이 속성을 지정해두지 않으면, 불필요한 오버플로우(뷰포트를 요소가 벗아나 스크롤이 생기는) 문제가 발생하므로 꼭 해줍시다. 차라리 해당 요소의 부모 요소에 overflow: hidden 을 지정하면 되는 것 아니냐고 하실 수 있는데, 본인이 생각하기에 좋은 방법이 있으시다면 그 방법을 채택하셔서 구현해셔도 좋습니다. 무엇이든 응용이 중요하니까요.
.spark 의 자식 요소로 추가할 span 태그 설정
여기서 span 은 .spark 요소의 자식 요소로 추가될 것입니다. 또한 span 은 실질적인 스파크 애니메이션을 나타내는데 사용되는 요소이므로 주요 로직이 포함됩니다. 명확한 지정을 위해서 별도의 클래스를 부여하여 사용해도 상관 없습니다.
span {
overflow: hidden;
position: absolute;
width: 2px;
height: 40px;
}
우선 overflow 를 hidden 으로 지정하여, 기존 .spark 요소의 바깥으로 span 태그가 벗어나면 보이지 않도록 설정 해줍니다. 이 부분은 향후 바깥으로 퍼지는 애니메이션 시 자연스럽게 스파크가 사라지는 연출을 위해서 필요한 속성입니다.
그리고 position을 absolute 로 하여 향후 마우스무브 이벤트를 적용 시 절대좌표를 기준으로 움직일 수 있도록 설정해줍니다.
width 와 height는 각각 2px, 40px 로 지정하였습니다. 이는 다음의 ::before 가상선택자를 통해 생성한 실제 스파크 애니메이션이 적용된 요소가 span 의 바깥으로 서서히 사라지는 범위를 지정하기 위해서 설정합니다.
span::before 설정
이 부분이 실제적으로 스파크 애니메이션이 일어나는 부분입니다.
span::before {
content: "";
position: absolute;
width: 100%;
background: gold;
height: 15px;
animation: spread 1 0.8s both;
}
우선 position 을 absoulte 로 지정하여 생성된 요소가 span 태그와 동일하게 절대좌표를 기준으로 독립된 레이어에서 동작하도록 설정해줍니다.
그 후 width 을 100% 으로 지정하여 기존 span에 지정한 2px 크기 만큼 가득차도록 설정해주고, height를 15px 정도로 지정하여 ' - ' 와 같은 모양이 되도록 설정해줍니다.
그 다음 background 의 경우 gold 로 지정하였는데, 향후 filter의 hue-rotate 값을 지정할 때 알록달록한 색감을 주기 위해서 지정하였습니다. 나중에 애니메이션 구현 후 여러 색상으로 바꿔보시면서 알맞는 색감을 찾아보시면 좋을 것 같습니다.
마지막으로 animation 속성에 sprea 1 0.8s both 를 지정해줍니다. spread 는 키프레임이름이고, 1 은 애니메이션 동작 횟수, 0.8s 는 애니메이션이 1회 동작할 때 실행되는 총 시간을 나타 냅니다.
both 는 애니메이션 적용 시 진행 방향이 양방향으로 확장되는 옵션인데, forwards 로 지정하여도 해당 애니메이션에서는 동일하게 동작합니다. 참고로 이 옵션들은 애니메이션이 종료되고 나서 종료된 위치에서 요소가 위치되도록 해줍니다.
키프레임 설정
@keyframes spread {
0% {
transform: translateY(0%);
}
100% {
transform: translateY(-200%);
}
}
마지막으로 앞서 설정한 애니메이션을 동작시키기 위해 키프레임을 설정해줍니다. 여기서 0%(시작지점)에서 transform 을 translateY(0%) 으로 지정하여 처음에는 요소의 중앙 지점에서 애니메이션이 시작되도록 하고, 100%(끝지점) 에서는 -200% 로 지정하여 중앙에서 바깥 방향으로 요소가 이동하도록 설정해줍니다.
JS
이제 자바스크립트를 사용하여 보다 동적이고 자연스러운 애니메이션을 적용해줄 차례입니다.
body 태그 가져오기
const body = document.querySelector("body");
우선 mousemove 이벤트 핸들러를 등록할 대상인 body 태그를 가져와 줍니다.
body 태그에 mousemove 이벤트 등록하기
body.addEventListener("mousemove", (e) => { }
그 다음에는 mousemove 이벤트를 body 를 대상으로 등록해줍니다. 이렇게 되면 body 태그가 차지하는 영역에서 마우스 이동 이벤트가 감지되면 이에 따라 콜백함수가 호출되게 됩니다.
.spark 요소 생성을 위한 Div 태그 생성 및 hue-rotate 조작을 위한 random 변수 설정
body.addEventListener("mousemove", (e) => {
const spark = document.createElement("div");
const random = Math.random() * 365;
} // 이후 부터 추가되는 모든 요소들도 해당 이벤트 리스너 콜백함수 내부에서 추가됩니다.
mousemove 이벤트가 감지될 때 마다 스파크 효과가 지속적으로 발생해야 하므로 이를 위한 div 태그를 document.createElement() 메소드를 호출하여 만들어줍니다.
그 다음에는 filter 속성의 hue-rotate 옵션의 값(deg) 으로 전달할 random 변수를 선언하고, Math.random() * 365 를 입력해 줍니다. 이렇게 되면 매번 마우스무브 이벤트가 감지될 때 마다 콜백함수가 호출되면서 0~364 사이의 값이 random 변수에 담기게 됩니다.
div 요소에 class ='spark ' 추가 및 body 태그의 자식으로 div 태그 추가하기
spark.classList.add("spark");
body.appendChild(spark);
이제 실제 DOM 트리에 생성한 요소를 반영해주기 위해서 div 태그에 .spark 를 class 속성의 값으로 지정해주고, 이를 body 태그의 마지막 자식요소로 추가하는 appendChild() 메소드의 인자로 전달해줍니다.
.spark 요소가 동적으로 움직이도록 설정 및 알록달록한 스파크 효과 입혀주기
spark.style.cssText = `
transform: translate(${e.clientX - 1}px,${e.clientY - 20}px);
filter: hue-rotate(${random}deg);
`;
이제 동적으로 생성되는 spark 요소를 동적으로 움직일 수 있도록 transform 의 translate 메소드에 x,y 값을 설정해줍니다.
여기서 이벤트 객체(e) 의 속성인 clientX 는 사용자가 브라우저를 바라볼 때의 innerWidth 가 동적으로 변경되는 값을 나타내며, clientY 도 innerHeight 가 동적으로 변경되는 값을 나타냅니다.(참고로 -1, -20 을 추가로 넣어준 이유는 요소의 width 와 height 의 절반값을 빼주어야 요소의 중앙에 마우스의 초점이 모이기 때문입니다.)
즉, 여기서 clientX 와 clientY 는 스크롤 된 높이와 상관없이 무조건 좌측 상단을 x=0, y=0 을 기준으로 측정합니다. 다시 말해 스크롤된 높이가 0px 이든 5000px 이든 좌측 상단은 무조건 (0,0) 좌표를 기준으로 합니다. |
https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/clientY
실제 스파크 애니메이션이 적용되는 span 태그 추가 및 360도로 퍼지는 효과 입혀주기
for (let i = 0; i < 8; i++) {
const span = document.createElement("span");
spark.append(span);
span.style.transform = `rotate(${i * 45}deg)`;
}
이번에 해야 하는 구현 동작은 대략 365도 를 기준으로 ' - ' 모양의 스파크가 요소의 중심을 기준으로 원형을 그리며 퍼지도록 하는 것입니다. 그러기 위해서는 우선적으로 span 요소를 생성해줍니다.
그후 해당 span 태그를 .spark 클래스가 부여된 div 요소의 자식요소로 추가해줍니다.
마지막으로 해당 span 태그에 transform 속성의 rotate 를 넣어주는데 해당 메소드의 인자로 i * 45 deg 가 되어 i 가 0 부터 7 까지 각각 45를 곱하여 계산된 값이 생성된 각 span 요소에 지정되도록 해줍니다. 여기 까지만 구현해도 아래와 같은 애니메이션이 적용되는데, 여기서 한 가지 문제가 남아 있습니다. .spark 요소가 계속 생성이 되므로 어느 순간 DOM 트리가 겉잡을 수 없을 정도로 무거워 진다는 점입니다.
setTimeout 메소드를 호출하여 body 태그 내에서 spark 요소 제거해주기
앞서 끝없이 생성되는 div 태그를 제거하기 위해서 setTimeout 메소드를 적용해줍니다.
setTimeout(() => {
body.removeChild(spark);
}, 1000);
이렇게 되면 1초 마다 .spark 클래스가 부여된 div 태그가 제거되므로 DOM 트리가 무거워지는 문제를 해결할 수 있게 됩니다.
구현결과
여기 까지 따라오셨다면, 아래와 같이 알록달록한 스파크 애니메이션을 보실 수 있게 되었습니다. 정말 고생 많으셨습니다.
See the Pen 스파크 by youngwan2 (@youngwan2) on CodePen.
다음 애니메이션 | 써클 프로그래스
'UI 디자인 애니메이션 연구소' 카테고리의 다른 글
HTML+CSS+JS로 초간단 무한 슬라이드 만들기 [1탄] (0) | 2024.05.28 |
---|---|
HTML+CSS+JS 를 이용한 써클 프로그래스 애니메이션을 만들어 봅시다 (0) | 2024.05.20 |
HTML/CSS 를 이용한 로딩 스피너 만들기 (0) | 2024.05.06 |
HTML/CSS 를 이용하여 실제 같은 페이퍼 만들기 (1) | 2024.05.05 |
바닐라 JS/HTML/CSS 로 재밌는 애니메이션 효과 만들기 (3탄) (0) | 2024.05.05 |