이야기 정리

자바스크립트 없이 CSS로 네비게이션 애니메이션 만들기 본문

Project/HTML, CSS project

자바스크립트 없이 CSS로 네비게이션 애니메이션 만들기

jinhistory 2023. 2. 6. 13:51

자바스크립트 없이 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()
})

 

Comments