label과 input을 연결하는 방식엔 두 가지가 있다.
둘 다 알고 있었지만 정확히 어떤 차이가 있는지 몰라서 이번에 제대로 정리해보았다.
나는 주로 명시적 연결로만 사용해왔었는데, 상황에 따라 골라쓰면 될거 같다.
label 태그가 input 을 감싸는 방식. id/for 없이 자동 연결.
<label>
<input type="checkbox"> 가방
</label>
input 에 id 부여, label 의 for 속성으로 연결.
<input type="checkbox" id="cate_bag">
<label for="cate_bag">가방</label>
| 항목 | 암묵적 (감싸기) | 명시적 (id/for) |
|---|---|---|
| HTML5 표준 | 정식 | 정식 |
| 마크업 길이 | 짧음 | 길음 (id + for 필요) |
| id 관리 | 불필요 | 유일성 보장 필요 |
| 동적 생성 | 유리 (PHP/JS 루프에서 id 충돌 없음) | 불편 (id 를 매번 유니크하게 생성) |
| 레이아웃 자유도 | 낮음 (input 과 텍스트가 붙어있어야 함) | 높음 (떨어뜨려 배치 가능) |
| 스크린리더 | 대부분 정상 인식 | 구형 보조기기에서 더 확실 |
| 커스텀 체크박스 | 가능 (input + span 구조) | 가능 (input + label 구조) |
<!-- PHP 동적 생성 예시 -->
<?php while($row = fetch()) { ?>
<label>
<input type="checkbox" name="item_<?=$row['id']?>">
<?=$row['name']?>
</label>
<?php } ?>
<input type="checkbox" id="agree">
<label for="agree">동의합니다</label>
두 방식 모두 커스텀 체크박스 구현 가능. 원리는 동일 (CSS + 인접 형제 선택자).
<div class="custom-check">
<input type="checkbox" id="agree">
<label for="agree">동의합니다</label>
</div>
.custom-check input { display: none; }
.custom-check label::before {
content: '';
display: inline-block;
width: 18px; height: 18px;
border: 2px solid #ccc;
border-radius: 3px;
vertical-align: middle;
margin-right: 6px;
}
.custom-check input:checked + label::before {
background: #169dab;
border-color: #169dab;
}
<label class="custom-check">
<input type="checkbox">
<span>동의합니다</span>
</label>
.custom-check input { display: none; }
.custom-check span::before {
content: '';
display: inline-block;
width: 18px; height: 18px;
border: 2px solid #ccc;
border-radius: 3px;
vertical-align: middle;
margin-right: 6px;
}
.custom-check input:checked + span::before {
background: #169dab;
border-color: #169dab;
}
| 명시적 | 암묵적 | |
|---|---|---|
| CSS 셀렉터 | input:checked + label::before | input:checked + span::before |
| 구조 | input 과 label 이 형제 | label 안에서 input 과 span 이 형제 |
| 원리 | 동일 (+ 인접 형제 선택자) | 동일 |
CSS + 선택자는 뒤쪽 형제만 선택 가능. input 이 반드시 텍스트(span/label) 보다 앞에 와야 한다.
<!-- 올바름: input 먼저 -->
<label><input type="checkbox"><span>텍스트</span></label>
<!-- 안 됨: span 먼저 → CSS 제어 불가 -->
<label><span>텍스트</span><input type="checkbox"></label>
<!-- 잘못: label 안에 여러 input -->
<label>
<input type="checkbox"> 옵션A
<input type="checkbox"> 옵션B
</label>
<!-- 올바름: input 하나당 label 하나 -->
<label><input type="checkbox"> 옵션A</label>
<label><input type="checkbox"> 옵션B</label>
<!-- 잘못: id 중복 -->
<input type="checkbox" id="item"> <label for="item">A</label>
<input type="checkbox" id="item"> <label for="item">B</label>
<!-- 올바름: id 유일 -->
<input type="checkbox" id="item_1"> <label for="item_1">A</label>
<input type="checkbox" id="item_2"> <label for="item_2">B</label>
| 상황 | 추천 |
|---|---|
| 기본 폼, 동적 생성, 빠른 작업 | 암묵적 (감싸기) |
| 커스텀 디자인, 접근성 엄격, 복잡 레이아웃 | 명시적 (id/for) |
둘 다 표준이고 둘 다 접근성 충족. 커스텀 체크박스도 둘 다 가능. 프로젝트 상황에 맞게 선택하면 된다.