100 DAYS CSS CHALLENGE #DAY19

everdeer·2025년 7월 7일

100 days CSS challenge

목록 보기
19/22
post-thumbnail

DAY #19

- 문제

👉 문제 바로가기

Slider with Radio Buttons: Why use JavaScript when you can use CSS? Selectors can be wildly combined with each other.

라디오 버튼이 있는 슬라이더: CSS를 사용할 수 있는데 왜 JavaScript를 사용해야 할까요? 선택자는 서로 자유롭게 조합할 수 있습니다.

버튼을 클릭하면 버튼의 active된 동그라미가 이동되고, 배경도 같이 스르륵 슬라이딩 되게 하는 문제!
근데 이제 당연하게 문제만 보고 자바스크립트를 이용하겠지? 했지만 설명을 보니..
CSS를 사용할 수 있는데 왜 JavaScript를 사용해야 할까요? 라 되어있었다 ㅋㅋ

자바스크립트를 사용하지 않는 방법으로 풀라고 만든 문제여서,,, 다시 조정!



설명 안보고 당연히 자바스크립트 써야지~ 하고 문제만 보면서 마크업 했을때는
당연히 저 버튼 (input) 태그를 하나의 block 태그로 감싸서 만들었었다...

<ul>
  <li>
    <input type="radio" id="btn1" name="btn" />
    <label for="btn1"></label>
  </li>
  <li>
    <input type="radio" id="btn2" name="btn" />
    <label for="btn2"></label>
  </li>
  <li>
    <input type="radio" id="btn3" name="btn" />
    <label for="btn3"></label>
  </li>
</ul>

뭐 이렇게... 해서 flex 정렬 써서 해야지~ 했는데...

배경이랑 active 버튼이랑 다 만들고 나서 보니 문제가 생겨버렸다...

라디오 버튼으로만 움직이려면 input 태그랑 움직이고자 하는 요소랑 형제관계에 있어야 한다는 것...!
(아니면 움직이고자 하는 요소가 input 하위에 자식요소로 있어야 한다)
그래야 선택자로 제어가 가능하다...

근데 저렇게 ul li 구조로 만들어버리면 .bg.activeinput이랑
형제는 무슨 아예 이라서
CSS 선택자만으로는 움직일 수가 없는 구조가 되어 버린다 ㅠㅠㅠㅠ

<div class="frame">
  <div class="bg">
    <div class="bg1"></div>
    <div class="bg2"></div>
    <div class="bg3"></div>
  </div>
  <div class="center">
    <ul>
      <li>
        <input type="radio" id="btn1" name="btn" />
        <label for="btn1"></label>
      </li>
      <li>
        <input type="radio" id="btn2" name="btn" />
        <label for="btn2"></label>
      </li>
      <li>
        <input type="radio" id="btn3" name="btn" />
        <label for="btn3"></label>
      </li>
    </ul>
    <div class="active"></div>
  </div>
</div>

이런식으로... 이렇게 하면 정렬하는건 쉽겠지만...
CSS와 input 만으로는 제어가 불가능한 구조라서 전면 수정했다.

<div class="frame">
  <div class="center">
    <input type="radio" id="btn1" name="btn" />
    <label for="btn1"></label>
    <input type="radio" id="btn2" name="btn" />
    <label for="btn2"></label>
    <input type="radio" id="btn3" name="btn" />
    <label for="btn3"></label>
    <div class="active"></div>
    <div class="bg">
      <div class="bg1"></div>
      <div class="bg2"></div>
      <div class="bg3"></div>
    </div>
  </div>
</div>

input 이랑 label을 하나로 묶지 않고,
.bg.active 와 형제관계에 있도록 수정 완료!


자 이제 그럼 CSS를 작성할 차례~✨

일단 .center 안에 input, label, .bg, .active 를 다 넣어두고
그 상위 요소에 display: grid; place-items: center; 를 준다.

그러면 .center 가 중앙에 정렬될것임. 하지만 내가 중앙에 정렬하고싶은 것은 label 만 이니까...

저렇게 그냥 냅두면 안되고!
중앙에 배치하고싶지 않은 것들은 position: absolute; 로 띄워놓아야 한다!
(input은 어차피 label을 사용해서 커스터마이징 할거라 display: none; 처리 되어서 따로 작업이 필요하지 않당)


📍 active 버튼 배치하기

이 버튼을 어떻게 배치할까 고민을 하다가...
(왜냐하면 .activeinput이랑 따로 묶여있는것도 아니고 position:relative; 를 줄수 있는 범위가 .center여서 한참 고민했음)

에융융 고냥 자바스크립트 쓰지

어떻게 했냐면!

$frameWH: 400px; //프레임 너비,높이
$labelWH: 50px; //라벨 너비,높이
$activeWH: 40px; //active 너비,높이
$gap: 10px; //라벨 간격
$baseLeft: ($frameWH - ($labelWH * 3) - ($gap * 2)) / 2 + (($labelWH - $activeWH) / 2); //active 위치 초기화

보이세요? 보이세요!? 👀
전체를 기준으로 label이 3개, gap이 2개니까

: frame 너비 - label너비 x 3 - gap너비 x 2 를 해주고 / 2

: label너비 - .active너비 / 2

이렇게 + 해서 초기화 했다 ㅋ...

$baseLeft: ($frameWH - ($labelWH * 3) - ($gap * 2)) / 2 + (($labelWH - $activeWH) / 2);
이렇게까지 하는게 맞나? 싶지만... 위치만 정확하다면 ㅠㅠ


두번째, 세번째 버튼 위치는 이제 여기서 갭너비, 라벨너비를 각 1번, 2번씩 더해주면 된다...
$baseLeft + $gap + $labelWH; // 두번째 버튼 위치
$baseLeft + ($gap * 2)+ ($labelWH * 2); // 새번째 버튼 위치

그럼 이제 버튼 위치는 다 구했으니 제어를 할 차례!


🎯 active 버튼 제어하기

일단 inputchecked 되었을때 그 형제관계에 있는~ .bg.active 를 제어하려면!

input[type="radio"] {
...
  &#btn1:checked ~ .active {
    ...
  }
  &#btn2:checked ~ .active {
    ...
  }
  &#btn3:checked ~ .active {
    ...
  }

  &#btn1:checked ~ .bg {
    ...
  }
  &#btn2:checked ~ .bg {
    ...
  }
  &#btn3:checked ~ .bg {
    ...
  }
}

요렇게 작성!
선택자 하나하나 중요한게 저기서 ~를 안적어주면 안먹는다. 형제 요소인 부분을 꼭 명시해줘야함.
안그러면 자식요소라고 생각하고 못찾는다!

이렇게 형제요소까지는 선택이 되는데, 부모요소는 선택이 안되는 CSS...




와 근데 글을 작성하면서 찾아보다 보니까,
굳이 inputlabel을 바로옆에 같이 쓸 필요가 없었다는걸 깨달았다! ;;

<div class="center">
  <input type="radio" id="btn1" name="btn" hidden />
  <input type="radio" id="btn2" name="btn" hidden />
  <input type="radio" id="btn3" name="btn" hidden />

  <ul>
    <li><label for="btn1">1</label></li>
    <li><label for="btn2">2</label></li>
    <li><label for="btn3">3</label></li>
  </ul>

  <div class="active"></div>
  ...
</div>

어차피 input은 숨김처리되니까, 굳이 label 옆에 꼭 붙여놓지 않았어도 되는거였음!
input으로 제어하는거니까 얘랑만 형제이면 되는 것인데...

이걸 이제야 알다니... 알았다면 label 배치하기 훨씬 편했을 테지만~~
일단 해뒀기에 이런 방법도 있다는 것만 참고하고!!

다음부터는 이렇게 써봐야 겠다 ㅋㅋ




다시 돌아와서 계속 하자면,
&#btn1:checked ~ .active {
  left: $baseLeft;
}
&#btn2:checked ~ .active {
  left: $baseLeft + $gap + $labelWH;
}
&#btn3:checked ~ .active {
  left: $baseLeft + ($gap * 2)+ ($labelWH * 2);
}

위에서 말한대로 두번째, 세번째 버튼 위치를 잡아주면... 된다...
그리고 .activetransition까지 걸어주면 스-윽 하고 움직이는 모션 까지 완료!


🎨 배경 제어하기

배경을 보면 버튼을 누르면 슉-슉- 하고 넘어가는 모션을 보인다.

<div class="bg">
  <div class="bg1"></div>
  <div class="bg2"></div>
  <div class="bg3"></div>
</div>

배경 1,2,3 을 만들었으니 .bg의 넓이는 .frame의 3배인 300%로 설정, flex 정렬,
버튼이 체크될 때, left를 기준으로 0%, -100%, -200%로 설정해 주면 된다!

&#btn1:checked ~ .bg {
  left: 0;
}
&#btn2:checked ~ .bg {
  left: -100%;
}
&#btn3:checked ~ .bg {
  left: -200%;
}

물론 .bg 에도 transition 걸어줘서 슉-슉 효과 주기!




- 내가 만든 SCSS Code


- 결과물


풀면서 굉장히 의문을 가졌던 부분...
Jquery나 Javascript 쓰면 선택자 딱 잡아서 이벤트 딱 주고 간단하게 할 수 있을텐데...🤔

CSS만으로도 충분히 할 수 있는건 맞지만 상황에 따라서 더 적절한 방법이 있는건데ㅠ
정말 이렇게 했어야 할까?? 라는 생각이 계속 들었지만🙃

선택자 연습했다고 생각하기로 하고! 다음 문제로 고고링~



profile
진귀한 웹 퍼블리셔

0개의 댓글