Logo

CSS 라디오 버튼 스타일링 가이드

이번 포스팅에서는 CSS를 이용하여 라디오 버튼을 스타일하는 요령에 대해서 알아보겠습니다. 차근차근 따라오시다보면 아래와 같은 라디오 버튼을 만드실 수 있으실 거에요. 🍅😄

왜, 라디오 버튼을 스타일할까?

먼저 웹사이트를 만들 때 라디오 버튼(radio button)을 뭐하러 직접 스타일하는지에 대해서 잠깐 짚고 넘어가겠습니다.

일반적으로 웹사이트에서 라디오 버튼은 브라우저나 운영체제, 디바이스에 따라서 미묘하게 다르게 표현이 됩니다. 그래서 플랫폼에 구애받지 않고 일관적인 사용자 경험을 제공하기 위해서 라디오 버튼에 커스텀 스타일을 적용하는 경우가 많습니다.

예를 들어, 일반적으로 푸른색 계열로 칠해지는 라디오 버튼은 파란색을 브랜드 색상으로 사용하지 않는 이상 웹사이트의 통일감을 해치게 됩니다. 뿐만 아니라 기본 스타일을 적용된 라디오 버튼은 크기가 고정되어 있기 때문에 반응형 웹디자인을 할 때 걸림돌이 됩니다.

다른 스타일없이 단순히 브랜딩 색상을 적용하고 싶다면 css-accent-color 속성이 더 효과적인 선택이 될 수 있습니다. 이 부분에 대해서는 관련 포스팅을 참고 바랍니다.

HTML 코드

HTML 코드 상에서 라디오 버튼은 <input> 요소를 사용하며 바로 옆에 <label> 요소를 사용하는 레이블 텍스트가 오게 되는데요. 웹 접근성(accessibility) 측면에서 라디오 버튼 뿐만 아니라 레이블 텍스트를 클릭했을 때도 라디오 버튼이 눌리게 하는 게 매우 중요합니다.

<div>
  <input type="radio" id="mail" name="contact" value="mail" />
  <label for="mail">우편</label>
</div>

그런데 이렇게 <input> 요소와 <label> 요소를 나란히 배치하면 반드시 <input> 요소의 id 속성과 <label> 요소의 for 속성에 같은 값을 설정하여 이 두 요소를 명시적으로 연결해줘야 합니다. 뿐만 아니라 이 두 요소를 묶어서 스타일 하기 위해서 <div> 요소로 한 번 더 감싸줄 필요도 생깁니다.

하지만 라디오 버튼과 레이블을 좀 더 간단하게 암묵적으로 연결해줄 수도 있는데요. 바로 <label> 요소로 <input> 요소와 텍스트를 모두 감싸버리기만 하면 됩니다.

<label>
  <input type="radio" name="contact" value="mail" />
  <span>우편</span>
</label>

본 포스팅에서는 후자와 같은 형태로 라디오 버튼에 대한 HTML 코드를 작성하려고 합니다.

사용자가 네가지 연락 방법 중에서 하나를 선택하게 하기 위한 4개의 라디오 버튼을 마크업해보겠습니다. 초기 상태로 이메일이 선택되게 하고, 팩스는 선택이 불가능하게 하였습니다.

<fieldset>
  <label>
    <input type="radio" name="contact" value="email" checked />
    <span>이메일</span>
  </label>

  <label>
    <input type="radio" name="contact" value="phone" />
    <span>전화</span>
  </label>

  <label>
    <input type="radio" name="contact" value="fax" disabled />
    <span>팩스</span>
  </label>

  <label>
    <input type="radio" name="contact" value="mail" />
    <span>우편</span>
  </label>
</fieldset>

라디오 버튼과 레이블 텍스트 간 정렬

라디오 버튼과 레이블 텍스트는 한 줄에 배치되었을 때 텍스트가 커질수록 라디오 버튼이 아래로 내려오게 됩니다. 따라서 수직 방향으로 중앙 정렬을 맞추기 위해서 이 두 요소에 vertical-align: middle; 스타일을 적용해줍니다.

라디오 버튼과 레이블 텍스트를 감싸고 있는 레이블 요소에는 글꼴 크기와 줄 높이와 같은 기본적인 스타일을 해주겠습니다.

label {
  font-size: 18px;
  line-height: 2rem;
  padding: 0.2em 0.4em;
}

[type="radio"],
span {
  vertical-align: middle;
}

기본 스타일 제거

예전에는 라디오 버튼을 스타일하기 위해서 <input> 요소를 화면에서 숨기고 임의로 만든 요소를 보여주는 등 일종의 눈속임을 하기 위해서 별에 별짓을 다 했었는데요. 이러한 스타일 방식은 CSS 코드가 복잡해지고, 실수할 위험도 높으며, 자칫하면 웹 접근성(accessibility)도 해칠수 있기 때문에 요즘에는 피하는 추세입니다.

요즘에는 브라우저 호환성이 좋아진 CSS에 비교적 최근에 추가된 appearance 속성을 활용하여 <input> 요소를 직접 스타일을 하는 방식이 더 선호되는데요. 라디오 버튼에 appearance: none;을 적용하면 기본 스타일이 깔끔하게 제거되기 때문에 백지 상태에서 스타일이 가능해집니다.

[type="radio"] {
  vertical-align: middle;
  appearance: none;}

이제 라디오 버튼이 화면에서 완전히 사라진 것처럼 보일 텐데요. 사실은 라디오 버튼의 크기가 0px x 0px로 완전히 쪼그라들어버린 것입니다.

라디오 버튼 스타일

이제부터 본격적으로 라디오 버튼을 우리가 원하는데로 스타일해볼까요?

우선 체크되지 않은 기본 상태부터 시작할건데요. 테두리를 튀지않는 회색으로 주겠습니다.

오랜 시간 학습의 결과로 수많은 인터넷 사용자들이 무의식적으로 라디오 버튼은 둥근 모양이라고 인식하고 있습니다. 따라서 border-radius 속성을 50%로 설정하여 라디오 버튼이 완전히 동그란 형태로 표시되게 하는 것이 무엇보다 중요하겠습니다.

라디오 버튼의 너비와 높이는 레이블 요소에 설정된 폰트 크기에 따라 상대적으로 커지거나 줄어들 수 있도록 em 단위를 사용하였습니다. 그리고 max() 함수를 활용하여 테두리의 두께가 2px보다는 얇아지지 않는 선에서 폰트 크기에 비례해서 늘어나거나 줄어들도록 해주었습니다.

[type="radio"] {
  vertical-align: middle;
  appearance: none;
  border: max(2px, 0.1em) solid gray;  border-radius: 50%;  width: 1.25em;  height: 1.25em;}

체크 상태 스타일

사용자가 선택을 하여 체크가 된 상태의 라디오 버튼은 도드라져 보여야하겠죠? 이 때는 :checked라는 가상 클래스(pseudo class)를 사용하면 됩니다.

테두리를 두툼하게 늘려주고, 토마토 색으로 테투리를 강조해주겠습니다.

[type="radio"]:checked {
  border: 0.4em solid tomato;
}

포커스 상태 스타일

웹 접근성(accessibility) 측면에서 마우스 사용자 뿐만 아니라 키보드 사용자도 고려하는 것이 상당히 중요한데요. 현재 키보드 포커스가 어느 라디오 버튼에 있는지를 알려줘야지 키보드 사용자도 큰 어려움 없이 원하는 라디오 버튼을 선택할 수 있을 것입니다.

키보드로 선택된 라디오 버튼에서는 점선의 포커스 링(ring)이 나타날 수 있도록 :focus-visible 가상 클래스에 스타일을 추가해주겠습니다.

[type="radio"]:focus-visible {
  outline: max(2px, 0.1em) dotted tomato;
  outline-offset: max(2px, 0.1em);
}

CSS에서 포커스 관련 가상 클래스 사용법에 대해서는 별도 포스팅에서 자세히 다루고 있습니다.

호버 상태 스타일

이번에는 마우스 사용자를 위해서 마우스 포인터가 라디오 버튼 위에 있을 때 그림자 효과를 살짝 주겠습니다. 그리고 라디오 버튼이나 레이블 텍스트 위로 마우스 커서가 왔을 때 포인터 모양이 나타나도록 해주면 사용자에게 도움이 되겠죠?

:hover 가상 클래스와 인접 형제 결합자(adjacent sibling combinator)을 활용하면 됩니다.

[type="radio"]:hover {
  box-shadow: 0 0 0 max(4px, 0.2em) lightgray;
  cursor: pointer;
}

[type="radio"]:hover + span {
  cursor: pointer;
}

위에서 사용하고 있는 + 기호는 인접 형제 결합자(adjacent sibling combinator)인데요. 관련 내용은 별도 포스팅에서 자세히 다루고 있습니다.

불능 상태 스타일

선택이 불가능한 라디오 버튼은 굳이 사용자가 여러 번 클릭해보지 않아도 바로 알아챌 수 있도록 스타일해주는 것이 바람직하겠죠?

:disabled 가상 클래스를 통해서 배경색을 회색톤으로 바꿔주고 불투명도를 살짝 낮춰주겠습니다. 마우스 커서를 통해서도 체크가 불가능하다고 표시해주면 좋을 것 같네요.

[type="radio"]:disabled {
  background-color: lightgray;
  box-shadow: none;
  opacity: 0.7;
  cursor: not-allowed;
}

[type="radio"]:disabled + span {
  opacity: 0.7;
  cursor: not-allowed;
}

애니메이션 효과

마지막으로 약간의 애니메이션 효과까지 첨가해주면 금상첨화겠죠? 😁

[type="radio"] {
  vertical-align: middle;
  appearance: none;
  border: max(2px, 0.1em) solid gray;
  border-radius: 50%;
  width: 1.25em;
  height: 1.25em;
  transition: border 0.5s ease-in-out;}

전체 코드

본 포스팅에서 작성한 코드는 아래에서 확인하고 직접 실행해보실 수 있습니다.

마치면서

지금까지 CSS로 다양한 커스텀 스타일을 적용하면서 웹사이트에 적용할 수 있는 간단한 라디오 버튼을 함께 구현해보았습니다.

UI 개발하다 보면 아무래도 시각적인 부분에 치중하기 쉬운데요. 웹 접근성(accessibility)도 어느 정도 염두하셔서 좀 더 많은 사용자를 배려한 스타일을 하실 수 있으셨으면 좋겠습니다.