티스토리 뷰

토글 버튼 배경 색을 슬라이드처럼 가로로 미는 애니메이션을 주고 싶었다. 쉽지 않았다. 😨
react와 styled-components를 사용했다.

inner div 만들기

<ToggleContainer onClick={toggleHandler}>
    <div className={`toggle-container ${isOn ? "toggle--checked" : ""}`}>
    	<div className="toggle-inner" />
    </div>
    <div className={`toggle-circle ${isOn ? "toggle--checked" : ""}`} />
</ToggleContainer>

토글 자체에서 배경색에 변화를 주는 애니메이션을 주는 것이 아니라 일종의 눈속임을 하는 것이다. 토글 안에 div(.toggle-inner)를 하나 더 만든다. 그리고 토글을 on/off할 때마다 각각 .toggle--checked가 추가되거나 삭제된다.

 

overflow: hidden;

  > .toggle-container {
    width: 60px;
    height: 32px;
    border-radius: 30px;
    background-color: #8b8b8b;
    overflow: hidden;

    > .toggle-inner {
      display: block;
      width: 120px;
      height: 32px;
      margin-left: -100%;
      background-color: red;
      transition: margin-left 0.4s;
    }

    > .toggle-inner::before,
    > .toggle-inner::after {
      content: "";
      display: inline-block;
      width: 50%;
      height: 32px;
    }
    > .toggle-inner::before {
      background-color: var(--coz-purple-600);
    }
    > .toggle-inner::after {
      background-color: #8b8b8b;
    }

    &.toggle--checked .toggle-inner {
      margin-left: 0;
      transition: margin-left 0.4s;
    }
  }

토글 버튼의 배경색에 슬라이드 효과를 주는 것은 사실 위 이미지처럼 색이 50%씩 다른 div의 margin-left에 변화를 주고 transition을 사용하여 부드럽게 한 후, 마치 창문을 통해서 보는 것과 같이 실제로 사용할 토글(.toggle-container) 부분만 보는 것이다. 그래서 토글에 overflow:hidden을 주어 해당 버튼 요소 밖으로 삐져나오는 컨텐츠들을 숨겨야 한다.

한 편, 구현 중 한가지 실수가 있었다. 클래스 .toggle--checked가 추가되었을 때 .toggle-inner에 변화를 주는 것이므로 이 .toggle-inner 안에 &.toggle--checked를 주었었다. 안됐다. 리액트 컴포넌트를 보면 .toggle-inner가 아닌 .toggle-container에 .toggle-checked 클래스를 추가하는 것이므로 해당 .toggle-container을 &선택자로 선택하고 .toggle-inner에 스타일링을 해주는 게 맞는 것 같다.

 

p.s. 토글 배경색 슬라이드를 구현하기 위해 구글링을 했더니 참고자료가 딱 한개가 나왔다. 왜 가상선택자를 사용하는지 잘 모르겠지만 해당 자료를 참고하고 원하는대로 되었다. 완성하고나서 다음과 같이 가상선택자를 없애고 단순하게 div스타일링을 배경색이 반반씩 되도록 바꿔보았는데 정상적으로 기능을 했다. 👍

> .toggle-container {
    width: 60px;
    height: 32px;
    border-radius: 30px;
    background-color: #8b8b8b;
    overflow: hidden;

    > .toggle-inner {
      display: block;
      width: 120px;
      height: 32px;
      margin-left: -100%;
      background: linear-gradient(to right, var(--coz-purple-600) 50%, #8b8b8b 50%);
    }

    &.toggle--checked .toggle-inner {
      margin-left: 0;
      transition: margin-left 0.4s;
    }
  }

 

Reference

https://velog.io/@hyejeong/Toggle-SwitchReact

반응형
댓글