잠깐! 혹시 svg로 gooey 애니메이션 만들자(1)을 보시지 않으셨나요?
(1)편에서 소개하는 svg로 효과를 만드는 법을 알아야 아래 내용을 이해하기 쉽습니다!
1. 미리보기
See the Pen gooey-menu-1 by KumJungMin (@kumjungmin) on CodePen.
2. 코드 분석
1) html
(1) 기본 구조
- html 구조는 아래 사진과 같다.
- 전체를 감싸는
wrap
안에 1개의button
과 4개의menu
가 존재한다. - 각각의
menu
에는icon
이 포함되어 있다.
<div class="wrap">
<div class="button"><img class="icon" src=""></div>
<div class="menu menu-1"><img class="icon" src=""></div>
<div class="menu menu-2"><img class="icon" src=""></div>
<div class="menu menu-3"><img class="icon" src=""></div>
<div class="menu menu-4"><img class="icon" src=""></div>
</div>
...
(2) svg 필터 효과 만들기
- 1편에서 얘기했듯이 svg를 사용하여 그래픽 효과를 만들 수 있다.
- 이번에 만들 효과는 사진처럼 menu가 서로 들러붙은 것처럼 보이게 하는
gooey
효과이다.
- 먼저
svg
에filter
를 추가하고,id="gooey"
로 지정한다.
...
<svg>
<filter id="gooey"></filter> <!--here!!-->
</svg>
feGaussianBlur
를 추가해 블러효과를 만든다.- 이 효과는 원본에 적용하며(
SourceGraphic
), 블러의 표준편차를 7로 지정한다. - 그 다음, 블러효과의 결과(result)를
blur
변수에 저장한다.
...
<svg>
<filter id="gooey">
<feGaussianBlur in="SourceGraphic" stdDeviation="7" result="blur" /> <!--here!-->
</filter>
</svg>
feColorMatrix
를 사용해 대조효과를 준다.- 블러를 한 대상(
blur
)에 대조효과를 주면 달라붙어있는 모습을 만들 수 있다. - 대조효과까지 준 결과(result)를
contrast
변수에 저장한다.
...
<svg>
<filter id="gooey">
<feGaussianBlur in="SourceGraphic" stdDeviation="7" result="blur" />
<feColorMatrix in="blur" type="matrix" values="1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 18 -7" result="contrast" /> <!--here!-->
</filter>
</svg>
- 마지막으로 원본(
SourceGraphic
)과 효과(contrast
)를 혼합하기 위해feBlend
를 사용한다.
...
<svg>
<filter id="gooey">
<feGaussianBlur in="SourceGraphic" stdDeviation="7" result="blur" />
<feColorMatrix in="blur" type="matrix" values="1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 18 -7" result="contrast" />
<feBlend in="SourceGraphic" in2="contrast" /> <!--here!-->
</filter>
</svg>
2) js
js에서는 버튼을 클릭했을 때 메뉴들이 나타나는 기능을 만든다.
원리는button
태그에click
이벤트가 발생시,button
에active
클래스를 추가하는 것이다. 한 번 코드를 살펴보자
const button = document.querySelector(".button"); //[1]
button.addEventListener("click", function() { //[2]
const isActive = this.classList.contains('active'); //[3]
if (isActive) this.classList.remove('active'); //[4]
else this.classList.add('active'); //[5]
})
[1] document.querySelector
를 사용해 class="button"
인 요소를 가져온다.
[2] addEventListener
를 사용해 button
에 클릭 이벤트가 발생할 시 함수를 정의한다.
[3] classList.contains
를 사용해 button
에 active
클래스가 존재하는지 체크한다.
[4] 만약 active클래스가 있다면, classList.remove
를 사용해 active
클래스를 제거한다.
[5] active클래스가 없다면, classList.add
로 active
클래스를 추가해준다.
3) scss
(1) 배경색 지정하기
body {
background: #1c1c1c; /*[1]*/
padding: 2rem 2rem;
}
[1] body에 background
속성을 사용해 배경색을 지정해준다.
(2) wrap에 svg효과 적용하기
.wrap { /*[0]*/
width: 30rem; /*[1]*/
height: 10rem; /*[1]*/
position: relative;
}
[0] wrap
은 버튼과 메뉴를 감싸는 부모 요소이다.
[1] 먼저 wrap
에 position과 width, height를 지정해준다.
.wrap {
...
filter: url("#gooey"); /*[2]*/
}
[2] 그 다음 (html에서) svg
로 생성한 gooey
효과를 적용한다.
[2] 방식은 위와 같이 filter
속성에 url("#filter의 id명")
를 적용하면 된다.
(3) button, menu의 기본 디자인 설정하기
.button,
.menu {
position: absolute; /*[1]*/
top: 0; /*[1]*/
left: 0; /*[1]*/
border-radius: 50%; /*[2]*/
cursor: pointer;
}
[1] button, menu의 position: absolute
로 두어 겹칠 수 있게 한다.
[1] 그 다음 top
, left
에 각각 0
을 주어 좌측 상단에 위치하게 한다.
[2] border-radius: 50%
을 주어 button
, menu
를 원 모양으로 만든다.
.button,
.menu {
...
display: flex; /*[3]*/
align-items: center; /*[3] 수직중앙*/
justify-content: center; /*[3] 수평중앙*/
}
[3] button
, menu
내부에 위치한 icon
이 수직, 수평 중앙 정렬이 되도록 속성을 지정해준다.
(4) button에 디자인 적용하기
.button { /*[1]*/
width: 5.3rem;
height: 5.3rem;
color: #1e1e1e;
font-weight: 700;
font-size: 1.7rem;
cursor: pointer;
background: linear-gradient(145deg, #323232, #3c3c3c);
box-shadow: 5px 5px 5px #272727,
-5px -5px -5px #494949;
...
}
[1] button
에 높이, 넓이, 배경색 등 기본적인 디자인을 적용한다.
.button {
...
&.active {
transform: rotate(90deg); /*[2]*/
}
}
[2] button
에 active
클래스가 추가될 경우, rotate(90deg)
를 주어 회전 효과를 준다.
.button {
...
.icon { /*[3]*/
width: 2.4rem;
height: 2.4rem;
}
}
[3] button
내부에 위치한 icon
의 높이, 넓이를 지정해준다.
(5) menu에 디자인 적용하기
.menu {
width: 4.5rem; /*[1]*/
height: 4.5rem; /*[1]*/
z-index: -1; /*[2]*/
transform: translate(0, 0) scale(0); /*[3]*/
...
}
[1] menu
의 높이, 넓이값을 설정한다.
[2] menu
의 경우 button
뒤에 숨겨져 있어야 하므로 z-index: -1
을 지정한다.
[3] button
을 클릭하기 전에는, menu
들의 위치는 (0, 0)
, 크기는 0
이어야 한다.
.menu {
...
.icon { /*[4]*/
width: 1.8rem;
height: 1.8rem;
}
}
[4] menu
내부에 위치한 icon
의 높이, 넓이를 지정해준다.
(6) menu별로 다른 색상 주기
$colors: #B980F0, #FE9898, #F5E79D, #E5FBB8; /*[1]*/
@for $i from 1 through length($colors) { /*[2]*/
.menu-#{$i} {
background-color: nth($colors, $i); /*[3]*/
}
}
[1] 총 4개의 menu
가 있으므로 $variable
을 선언하여 색상 list
를 만든다.
[2] scss에서 반복문이 가능한데, 1 ~ $colors의 길이
까지 반복한다.
[3] nth(list, $i)
를 하면 리스트(list)의 $i
번째 값에 접근가능하다.
(7) button 클릭시 menu나타나게 하기
js에서 확인했듯이
button
을 클릭하면button
에active
가 추가된다.
그렇다면button
에active
가 추가된 상태에서menu
들의 상태를 정의해야한다.
우리는menu
들이 숨겨지 있다가 나타나기를 바란다.
scss의 for문을 이용하여menu
들을 나타내고 원하는 위치로 이동시켜보자!
@for $i from 1 through 4 { /*[1]*/
$positionX: 4.2 * $i; /*[2]*/
.button.active ~ .menu-#{$i} { /*[3]*/
transition-delay: $i * 0.1s; /*[4]*/
transform: translate($positionX + rem , 4rem) scale(1); /*[5]*/
}
}
[1] menu의 개수는 4이므로 1~4까지 반복한다.
[2] 각 menu의 x축 위치가 4.2
, 8.4
, 12.6
, 16.8
이 되도록 변수(positionX
)를 만든다.
[3] .A ~ .B는, A클래스
다음에 위치한 B클래스
에 대해 css를 지정할 수 있다.
[4] transition-delay
를 줘서 메뉴들이 순차적으로 나타나게 한다.
[5] translate
를 사용해 위치를 변경하고, scale(1)
로 메뉴를 나타나게 한다.
'개발 기술 > css 애니메이션 (with js)' 카테고리의 다른 글
종이 글자 애니메이션 (with. clip-path) (2) | 2021.10.22 |
---|---|
버튼 커서 애니메이션 (with. js) (0) | 2021.10.20 |
wave 애니메이션(with. text-decoration) (0) | 2021.10.15 |
스크롤은 부드럽게, 글자에는 이미지를 넣어보자! (0) | 2021.10.13 |
글자가 그려지는 애니메이션(with, stroke-dashoffset) (0) | 2021.10.11 |
댓글