웹 페이지의 사용자 경험을 높이기 위해 기본 UI 요소를 커스터마이징하는 것은 매우 중요합니다. 특히 설문조사나 선택 폼에서 흔히 쓰이는 라디오 버튼을 기본 스타일 대신 직관적인 체크(V)와 엑스(X) 아이콘으로 변경하면 디자인의 완성도를 훨씬 높일 수 있습니다. 별도의 JavaScript 없이 순수 HTML과 CSS의 상태 선택자만 활용하여 감각적인 라디오 버튼을 만드는 방법을 살펴봅니다.
1. HTML 구조 설계
라디오 버튼의 기능을 유지하면서 외형을 완전히 바꾸기 위해 label 태그 안에 실제 input을 숨기고, 아이콘 역할을 할 span 요소를 배치합니다. name 속성을 동일하게 맞추어 상호 배타적인 선택이 가능하도록 구성합니다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>커스텀 라디오 버튼</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="poll-wrapper">
<p class="question">진행하시겠습니까?</p>
<label class="option-item">
<input type="radio" name="choice-btn">
<span class="icon mark-v"></span>
네, 좋아요
</label>
<label class="option-item">
<input type="radio" name="choice-btn">
<span class="icon mark-x"></span>
아니요
</label>
</div>
</body>
</html>
2. CSS 스타일링 및 애니메이션
핵심 원리는 ::before와 ::after 가상 요소를 활용해 두 개의 직선을 만들고, :checked 상태에 따라 이 직선들의 각도와 위치를 조절하여 아이콘을 완성하는 것입니다.
/* 기본 스타일 초기화 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: #1a1a2e;
font-family: sans-serif;
}
.poll-wrapper {
display: flex;
flex-direction: column;
gap: 15px;
}
.question {
color: #efefef;
font-size: 1.8rem;
margin-bottom: 20px;
}
.option-item {
position: relative;
display: flex;
align-items: center;
cursor: pointer;
font-size: 1.5rem;
color: #fff;
user-select: none;
}
/* 기본 라디오 버튼 숨기기 */
.option-item input {
appearance: none;
-webkit-appearance: none;
}
/* 아이콘 컨테이너 */
.icon {
position: relative;
width: 30px;
height: 30px;
margin-right: 15px;
transition: all 0.4s ease;
}
/* 공통 라인 스타일 (가로/세로 막대기) */
.icon::before, .icon::after {
content: '';
position: absolute;
background: #444;
transition: 0.4s;
}
/* 가로축 라인 설정 */
.icon::before {
bottom: 0;
left: 0;
width: 100%;
height: 4px;
box-shadow: 0 -26px 0 #444;
}
/* 세로축 라인 설정 */
.icon::after {
bottom: 0;
left: 0;
width: 4px;
height: 100%;
box-shadow: 26px 0 0 #444;
}
/* 체크(V) 아이콘 활성화 상태 */
.option-item input:checked ~ .mark-v::before {
background: #4ade80;
box-shadow: 0 0 0 transparent;
}
.option-item input:checked ~ .mark-v::after {
height: 55%;
background: #4ade80;
box-shadow: 0 0 0 transparent;
}
.option-item input:checked ~ .mark-v {
transform: rotate(-45deg) translate(8px, -6px);
}
/* 엑스(X) 아이콘 활성화 상태 */
.option-item input:checked ~ .mark-x::before {
background: #fb7185;
box-shadow: 0 0 0 transparent;
transform: rotate(-45deg) translate(10px, -9px);
}
.option-item input:checked ~ .mark-x::after {
background: #fb7185;
box-shadow: 0 0 0 transparent;
transform: rotate(-45deg) translate(10px, 10px);
}
동작 원리 설명
작성된 코드의 핵심 메커니즘은 다음과 같습니다.
- 가상 요소 활용:
span요소 하나에::before와::after를 사용하여 사각형의 테두리 라인을 시뮬레이션합니다.box-shadow를 이용해 반대편 라인까지 그려냄으로써 초기 상태에서는 정사각 틀 모양을 유지합니다. - 인접 형제 선택자:
input:checked ~ .icon구문을 통해 라디오 버튼이 선택되는 순간, 옆에 있는 아이콘 요소의 스타일을 변경합니다. - 변형(Transform): 선택 시
rotate와translate속성을 부여하여 90도로 꺾여있던 라인들을 체크 표시의 각도나 X자 모양으로 교차시킵니다. 이때transition속성이 부드러운 전환 애니메이션을 만들어냅니다.
이 기법을 응용하면 체크박스나 토글 스위치 등 다양한 UI 구성 요소에 자신만의 독특한 피드백 애니메이션을 추가할 수 있습니다.