일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- React
- javascript
- html
- mini_project
- stopwatch
- 웹사이트
- Timer
- Project
- darknode
- Calculator
- CSS
- DOM
- Typescript
- localStorage
- 브라우저
- todolist
- calender
- Today
- Total
이야기 정리
자바스크립트 없이 CSS로 네비게이션 애니메이션 만들기 본문
자바스크립트 없이 input의 radio 기능을 사용해 간단하게 클릭 애니메이션을 구현할 것이다.
만들어볼 애니메이션은 총 4종류다.
완성 코드는 아래와 같으며, 스크롤을 내리면 나머지 3종도 볼 수 있다.
See the Pen Navigation CSS by beren-105 (@beren-105) on CodePen.
0. 기본 레이아웃
기본 레이아웃을 기반으로 4가지를 모두 만들 것이기 때문에 span 태그는 기본적으로 display:none로 두고, 필요할 때만 block으로 사용했다.
보통이라면 label 안에 input을 넣어 코드를 간결하게 적었겠지만, 애니메이션 효과를 만들기 위해 둘을 따로 분리해서 작성했다. 색상 통일을 위해 :root로 기본 색상과 자주 쓰는 transition을 넣어주었다.
아이콘은 폰트어썸을 사용했다.
<article>
<input type="radio" name="radio1" id="Home1" class="first home">
<input type="radio" name="radio1" id="shopping1" class="shopping">
<input type="radio" name="radio1" id="user1" class="user">
<input type="radio" name="radio1" id="setting1" class="setting">
<div class="line">
<label for="Home1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M575.8 255.5c0 18-15 32.1-32 32.1h-32l.7 160.2c0 2.7-.2 5.4-.5 8.1V472c0 22.1-17.9 40-40 40H456c-1.1 0-2.2 0-3.3-.1c-1.4 .1-2.8 .1-4.2 .1H416 392c-22.1 0-40-17.9-40-40V448 384c0-17.7-14.3-32-32-32H256c-17.7 0-32 14.3-32 32v64 24c0 22.1-17.9 40-40 40H160 128.1c-1.5 0-3-.1-4.5-.2c-1.2 .1-2.4 .2-3.6 .2H104c-22.1 0-40-17.9-40-40V360c0-.9 0-1.9 .1-2.8V287.6H32c-18 0-32-14-32-32.1c0-9 3-17 10-24L266.4 8c7-7 15-8 22-8s15 2 21 7L564.8 231.5c8 7 12 15 11 24z"/></svg>
<span>Home</span>
</label>
<label for="shopping1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><path d="M0 24C0 10.7 10.7 0 24 0H69.5c22 0 41.5 12.8 50.6 32h411c26.3 0 45.5 25 38.6 50.4l-41 152.3c-8.5 31.4-37 53.3-69.5 53.3H170.7l5.4 28.5c2.2 11.3 12.1 19.5 23.6 19.5H488c13.3 0 24 10.7 24 24s-10.7 24-24 24H199.7c-34.6 0-64.3-24.6-70.7-58.5L77.4 54.5c-.7-3.8-4-6.5-7.9-6.5H24C10.7 48 0 37.3 0 24zM128 464a48 48 0 1 1 96 0 48 48 0 1 1 -96 0zm336-48a48 48 0 1 1 0 96 48 48 0 1 1 0-96z"/></svg>
<span>shopping</span>
</label>
<label for="user1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path d="M224 256c70.7 0 128-57.3 128-128S294.7 0 224 0S96 57.3 96 128s57.3 128 128 128zm-45.7 48C79.8 304 0 383.8 0 482.3C0 498.7 13.3 512 29.7 512H418.3c16.4 0 29.7-13.3 29.7-29.7C448 383.8 368.2 304 269.7 304H178.3z"/></svg>
<span>User</span>
</label>
<label for="setting1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M495.9 166.6c3.2 8.7 .5 18.4-6.4 24.6l-43.3 39.4c1.1 8.3 1.7 16.8 1.7 25.4s-.6 17.1-1.7 25.4l43.3 39.4c6.9 6.2 9.6 15.9 6.4 24.6c-4.4 11.9-9.7 23.3-15.8 34.3l-4.7 8.1c-6.6 11-14 21.4-22.1 31.2c-5.9 7.2-15.7 9.6-24.5 6.8l-55.7-17.7c-13.4 10.3-28.2 18.9-44 25.4l-12.5 57.1c-2 9.1-9 16.3-18.2 17.8c-13.8 2.3-28 3.5-42.5 3.5s-28.7-1.2-42.5-3.5c-9.2-1.5-16.2-8.7-18.2-17.8l-12.5-57.1c-15.8-6.5-30.6-15.1-44-25.4L83.1 425.9c-8.8 2.8-18.6 .3-24.5-6.8c-8.1-9.8-15.5-20.2-22.1-31.2l-4.7-8.1c-6.1-11-11.4-22.4-15.8-34.3c-3.2-8.7-.5-18.4 6.4-24.6l43.3-39.4C64.6 273.1 64 264.6 64 256s.6-17.1 1.7-25.4L22.4 191.2c-6.9-6.2-9.6-15.9-6.4-24.6c4.4-11.9 9.7-23.3 15.8-34.3l4.7-8.1c6.6-11 14-21.4 22.1-31.2c5.9-7.2 15.7-9.6 24.5-6.8l55.7 17.7c13.4-10.3 28.2-18.9 44-25.4l12.5-57.1c2-9.1 9-16.3 18.2-17.8C227.3 1.2 241.5 0 256 0s28.7 1.2 42.5 3.5c9.2 1.5 16.2 8.7 18.2 17.8l12.5 57.1c15.8 6.5 30.6 15.1 44 25.4l55.7-17.7c8.8-2.8 18.6-.3 24.5 6.8c8.1 9.8 15.5 20.2 22.1 31.2l4.7 8.1c6.1 11 11.4 22.4 15.8 34.3zM256 336c44.2 0 80-35.8 80-80s-35.8-80-80-80s-80 35.8-80 80s35.8 80 80 80z"/></svg>
<span>setting</span>
</label>
</div>
</article>
:root {
--color-white: #fff;
--color-grey: #D1D1D1;
--color-blue: #009EFF;
--color-sky: #82C3EC;
--color-article: #B9E0FF;
--transition: 0.3s;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
background-color: #F1F6F5;
}
article {
margin-top: 50px;
width: 350px;
height: 150px;
border-radius: 20px;
background-color: #B9E0FF;
display: flex;
align-items: flex-end;
box-shadow: 2px 2px 20px rgba(0 0 0 / 0.2);
overflow: hidden;
}
article input {
display: none;
}
article div {
width: 100%;
background-color: var(--color-white);
display: flex;
justify-content: space-around;
align-items: center;
position: relative;
}
article div label {
padding: 1rem;
display: inline-flex;
flex-direction: column;
align-items: center;
cursor: pointer;
position: relative;
transition: var(--transition);
}
article div label:hover svg {
fill: var(--color-sky);
}
article div label svg {
width: 24px;
height: 24px;
fill: var(--color-grey);
transition: var(--transition);
}
article div label span {
display: none;
transition: var(--transition);
}
article input:nth-child(1):checked~div label:nth-child(1) svg,
article input:nth-child(2):checked~div label:nth-child(2) svg,
article input:nth-child(3):checked~div label:nth-child(3) svg,
article input:nth-child(4):checked~div label:nth-child(4) svg {
fill: var(--color-blue);
}
1. 선추가
div.line::after {
content: '';
display: block;
position: absolute;
top: 0;
left: 0px;
width: 56px;
height: 3px;
margin: 0 1rem;
background-color: var(--color-blue);
transition: var(--transition);
}
article input#Home1:checked~div.line::after {
left: 0%;
}
article input#shopping1:checked~div.line::after {
left: 25%;
}
article input#user1:checked~div.line::after {
left: 50%;
}
article input#setting1:checked~div.line::after {
left: 75%;
}
가장 간단한 라인 이벤트다. 클릭 시 상단에 있는 선이 아이콘을 따라 움직인다.
불필요한 태그를 줄이기 위해 ::after를 사용하고 나머지는 각각 left를 움직여 만들었다.
2. 동그라미
article div.rounde label {
background-color: var(--color-white);
border-radius: 50%;
}
article div.rounde label::before {
content: '';
display: block;
width: 14px;
height: 14px;
border-bottom-right-radius: 60%;
border-bottom: 8px solid var(--color-white);
position: absolute;
top: 0px;
left: -7px;
}
article div.rounde label::after {
content: '';
display: block;
width: 14px;
height: 14px;
border-bottom-left-radius: 60%;
border-bottom: 8px solid var(--color-white);
position: absolute;
top: 0px;
right: -7px;
}
article input#Home2:checked~div label[for="Home2"],
article input#shopping2:checked~div label[for="shopping2"],
article input#user2:checked~div label[for="user2"],
article input#setting2:checked~div label[for="setting2"] {
transform: translateY(-25%);
}
단순히 배경을 동그랗게 만들어 위로 움직이는 것만으로는 양 옆이 일자로 딱 끊겨 어색함이 많다.
때문에 ::before과 ::after에서 border를 사용해 양 옆이 자연스럽게 라운드 되도록 만들었다.
3. 동그라미(2)
article div.rounde2 div {
position: absolute;
width: 68px;
height: 68px;
margin: 0 0.63rem;
background-color: var(--color-article);
border: 10px solid var(--color-article);
border-radius: 50%;
left: 0;
top: -20px;
transition: var(--transition);
}
article div.rounde2 div::before {
content: '';
display: block;
width: 14px;
height: 10px;
border-top-right-radius: 100%;
border-right: 15px solid var(--color-article);
position: absolute;
top: 8px;
left: -23px;
}
article div.rounde2 div::after {
content: '';
display: block;
width: 14px;
height: 10px;
border-top-left-radius: 100%;
border-left: 15px solid var(--color-article);
position: absolute;
top: 8px;
right: -23px;
}
article div.rounde2 label {
background-color: var(--color-white);
border-radius: 50%;
z-index: 1;
}
article input#Home3:checked~div.rounde2 div {left:0;}
article input#shopping3:checked~div.rounde2 div {left:25%;}
article input#user3:checked~div.rounde2 div {left:50%;}
article input#setting3:checked~div.rounde2 div {left:75%;}
article input#Home3:checked~div label[for="Home3"],
article input#shopping3:checked~div label[for="shopping3"],
article input#user3:checked~div label[for="user3"],
article input#setting3:checked~div label[for="setting3"] {
transform: translateY(-25%);
}
세번째는 2번의 변형이다.
먼저 label의 형제로 최하단에 div를 추가했다. 아이콘이 클릭하면 위로 올라오는 것은 그대로하되, 새로 만든 div가 좌우로 움직이며 뒷 배경이 투명화된 것 같은 효과를 주었다. 실제로는 배경색상으로 덮어씌운 것 뿐이기에 이 방법보단 svg를 사용하는 것이 효율적이라 생각한다.
4. nav 이름 추가하기
article div.name label {
padding-bottom: 0.25rem;
}
article div.name label span {
display: block;
font-size: 0.75rem;
font-weight: bold;
color: var(--color-blue);
transform: translateY(50px);
}
article input#Home4:checked~div label[for="Home4"] svg,
article input#shopping4:checked~div label[for="shopping4"] svg,
article input#user4:checked~div label[for="user4"] svg,
article input#setting4:checked~div label[for="setting4"] svg {
transform: translateY(-5px);
width: 15px;
height: 15px;
}
article input#Home4:checked~div label[for="Home4"] span,
article input#shopping4:checked~div label[for="shopping4"] span,
article input#user4:checked~div label[for="user4"] span,
article input#setting4:checked~div label[for="setting4"] span {
transform: translateY(-5px);
}
드디어 감추기만 했던 span 태그를 사용할 때가 왔다. 기본적인 원리는 2번에 했던 예제와 같다.
클릭하면 아이템들이 위로 올라가는데, span태그는 처음에는 보이지 않는 화면 아래에 위치해 있는 게 포인트다.
그래서 클릭하면 span 태그가 위로 올라가며 화면에 드러나는 것이다.
여기까지가 총 4가지 네비게이션을 만드는 방법이었다. 나의 경우 처음에 활성화된 모습을 보여주기 위해 다음과 같은 자바스크립트 코드를 사용했다.
const first = document.querySelectorAll('.first')
first.forEach((first) => {
first.click()
})