HTML 데이터 속성(Data Attributes) 완전 가이드
HTML data 속성 활용법부터 CSS attr() 함수, JavaScript dataset까지. 실무 예제로 배우는 데이터 속성 완전 가이드
HTML 데이터 속성(Data Attributes) 가이드
웹 개발을 하다 보면 HTML 요소에 추가적인 정보를 저장해야 할 때가 자주 있습니다. 예를 들어 버튼을 클릭했을 때 어떤 동작을 할지, 특정 요소의 상태 정보는 무엇인지 같은 정보들을 말입니다.
이런 상황에서 매우 유용한 것이 바로 **HTML 데이터 속성(Data Attributes)**입니다. 이번 글에서는 데이터 속성의 개념부터 실제 활용 방법까지 상세하게 알아보겠습니다.
목차
- 데이터 속성이란 무엇인가?
- 데이터 속성을 사용하는 이유
- 데이터 속성 기본 문법
- HTML에서 데이터 속성 사용하기
- CSS로 데이터 속성 활용하기
- JavaScript로 데이터 속성 다루기
- 실무에서 바로 쓸 수 있는 예제들
- 알아두면 좋은 주의사항들
데이터 속성이란 무엇인가?
데이터 속성(Data Attributes)은 HTML 요소에 사용자 정의 정보를 저장할 수 있게 해주는 특별한 속성입니다.
이를 쉽게 비유하면, HTML 요소마다 작은 메모장을 하나씩 달아주는 것과 같습니다. 이 메모장에는 해당 요소와 관련된 다양한 정보를 저장할 수 있습니다.
데이터 속성의 주요 특징
- 모든 데이터 속성은 반드시
data-로 시작해야 합니다 - HTML 표준을 완전히 준수하면서도 사용자 정의 정보를 저장할 수 있습니다
- 화면에는 직접 표시되지 않지만, CSS와 JavaScript에서 활용할 수 있습니다
- 모든 최신 브라우저에서 지원되므로 안정적으로 사용할 수 있습니다
데이터 속성을 사용하는 이유
데이터 속성의 유용성을 이해하기 위해 간단한 예를 살펴보겠습니다. 학교 홈페이지에서 학생 목록을 만드는 상황을 가정해보겠습니다:
<!-- 기존 방식: 추가 정보가 없음 -->
<div class="student">김철수</div>
<!-- 데이터 속성 활용: 다양한 정보를 포함 -->
<div class="student" data-grade="3" data-class="A" data-number="15">김철수</div>
위 예제에서 볼 수 있듯이, 데이터 속성을 사용하면 학년, 반, 번호 같은 추가 정보를 HTML에 체계적으로 저장할 수 있습니다. 이러한 정보들은 나중에 JavaScript로 학생을 검색하거나 필터링할 때 매우 유용하게 활용됩니다.
데이터 속성 기본 문법
데이터 속성을 올바르게 사용하려면 몇 가지 간단한 규칙만 알면 됩니다.
속성 이름 작성 규칙
<!-- 이렇게 하면 완벽해요! ✅ -->
<div data-name="홍길동"></div>
<div data-user-id="123"></div>
<div data-product-price="25000"></div>
<div data-is-premium="true"></div>
<!-- 이런 건 안 됩니다 ❌ -->
<div data="value"></div>
<!-- data- 뒤에 이름이 없어요 -->
<div data-="value"></div>
<!-- 마찬가지로 이름이 없네요 -->
<div data-Name="value"></div>
<!-- 대문자는 권장하지 않아요 -->
주요 규칙:
data-뒤에는 반드시 의미 있는 이름을 작성해야 합니다- 이름은 소문자와 하이픈(-)을 사용하는 것이 좋습니다
- 여러 단어를 연결할 때는
data-user-name처럼 하이픈을 사용합니다
값 없는 데이터 속성
<!-- 속성의 존재 자체가 의미를 가지는 경우 -->
<div data-active></div>
<!-- 활성 상태를 나타냄 -->
<div data-selected></div>
<!-- 선택된 상태를 나타냄 -->
<div data-loading></div>
<!-- 로딩 중임을 나타냄 -->
HTML에서 데이터 속성 사용하기
이제 실제 프로젝트에서 데이터 속성을 어떻게 활용하는지 구체적인 예제를 통해 살펴보겠습니다.
실제 예제 1: 레벨바
다음은 시스템 리소스 사용량을 표시하는 레벨바 예제입니다:
<!DOCTYPE html>
<html>
<head>
<title>시스템 레벨바 예제</title>
<style>
/* 시스템 정보 컨테이너 스타일 */
#sys_info {
float: left;
background-color: white;
border-left: 4px solid #66a4df;
border-right: 4px solid #66a4df;
}
/* 리스트 기본 스타일 */
#sys_info .sys_info {
margin: 0;
padding: 0;
list-style: none;
height: 50px;
padding-right: 15px;
color: #83b7cb;
}
/* 리스트 아이템 스타일 */
#sys_info .sys_info li {
display: inline-block; /* 가로로 나열 */
height: 100%;
text-align: center;
font-size: 11px;
line-height: 50px;
}
/* 첫 번째 span (라벨) 스타일 */
#sys_info .sys_info > li > span:nth-child(odd) {
padding: 16px 2px;
}
/* 두 번째 span (레벨바 컨테이너) 스타일 */
#sys_info .sys_info > li > span:nth-child(even) {
background-color: cadetblue;
padding: 16px 3px;
color: #000000;
}
/* 레벨바 기본 스타일 */
.levelbar {
width: 49px;
height: 56%;
display: inline-block;
position: relative;
top: 2px;
left: -1px;
}
/* 퍼센트 표시 기본값 */
.levelbar:before {
content: "0%";
position: absolute;
left: 1px;
line-height: 44px;
width: 47px;
text-align: center;
font-size: 13px;
}
/* 레벨바 내부 요소들 스타일 */
.levelbar > * {
width: 100%;
height: 31%; /* 5개 요소이므로 각각 약 20% */
background-color: white;
border-top: 1px solid gray;
}
/* 활성화된 레벨 스타일 */
.levelbar > .active {
background-color: #5fef3c; /* 밝은 녹색 */
}
/* 데이터 속성 값을 CSS로 표시 - CPU */
#cpu.levelbar:before {
content: attr(data-cpu) "%"; /* data-cpu 속성값 + "%" 표시 */
}
/* 데이터 속성 값을 CSS로 표시 - 메모리 */
#mem.levelbar:before {
content: attr(data-mem) "%"; /* data-mem 속성값 + "%" 표시 */
}
/* 데이터 속성 값을 CSS로 표시 - 디스크 */
#disk.levelbar:before {
content: attr(data-disk) "%"; /* data-disk 속성값 + "%" 표시 */
}
</style>
</head>
<body>
<div id="sys_info">
<ul class="sys_info">
<li>
<span>CPU</span>
<!-- CPU 라벨 -->
<span>
<!-- CPU 사용률을 data-cpu 속성으로 저장 (현재 0%) -->
<div id="cpu" class="levelbar" data-cpu="0">
<div class="level5"></div>
<!-- 레벨 5 (최고) -->
<div class="level4"></div>
<!-- 레벨 4 -->
<div class="level3"></div>
<!-- 레벨 3 -->
<div class="level2"></div>
<!-- 레벨 2 -->
<div class="level1 active"></div>
<!-- 레벨 1 (최저, 현재 활성) -->
</div>
</span>
</li>
<li>
<span>MEM</span>
<!-- 메모리 라벨 -->
<span>
<!-- 메모리 사용률을 data-mem 속성으로 저장 (현재 30%) -->
<div id="mem" class="levelbar" data-mem="30">
<div class="level5"></div>
<!-- 레벨 5 (최고) -->
<div class="level4"></div>
<!-- 레벨 4 -->
<div class="level3"></div>
<!-- 레벨 3 -->
<div class="level2"></div>
<!-- 레벨 2 -->
<div class="level1 active"></div>
<!-- 레벨 1 (최저, 현재 활성) -->
</div>
</span>
</li>
<li>
<span>DISK</span>
<!-- 디스크 라벨 -->
<span>
<!-- 디스크 사용률을 data-disk 속성으로 저장 (현재 0%) -->
<div id="disk" class="levelbar" data-disk="0">
<div class="level5"></div>
<!-- 레벨 5 (최고) -->
<div class="level4"></div>
<!-- 레벨 4 -->
<div class="level3"></div>
<!-- 레벨 3 -->
<div class="level2"></div>
<!-- 레벨 2 -->
<div class="level1 active"></div>
<!-- 레벨 1 (최저, 현재 활성) -->
</div>
</span>
</li>
</ul>
</div>
</body>
</html>
실제 예제 2: 화면 비율
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Aspect Ratio 예제</title>
<style>
/* 16:9 비율 컨테이너 - data-ratio 속성으로 구분 */
.aspectratio[data-ratio="16:9"] {
width: 100vw;
height: 56.25vw; /* 9/16 = 0.5625 - 16:9 비율 계산 */
background: hotpink;
}
/* 4:3 비율 컨테이너 - 클래식 TV/모니터 비율 */
.aspectratio[data-ratio="4:3"] {
width: 100vw;
height: 75vw; /* 3/4 = 0.75 - 4:3 비율 계산 */
background: lightblue;
}
/* 1:1 정사각형 비율 - 인스타그램 스타일 */
.aspectratio[data-ratio="1:1"] {
width: 50vw;
height: 50vw;
background: lightgreen;
}
/* 모든 요소에 박스 사이징 적용 */
* {
box-sizing: border-box;
}
/* 페이지 전체 기본 스타일 */
body,
html {
margin: 0;
padding: 0;
height: 100vh; /* 뷰포트 높이 */
width: 100vw; /* 뷰포트 너비 */
}
/* 텍스트 스타일 */
p {
margin-top: 0;
padding: 20px;
font-size: 24px;
font-weight: bold;
}
</style>
</head>
<body>
<!-- data-ratio 속성으로 16:9 비율 지정 -->
<div class="aspectratio" data-ratio="16:9">
<p>16:9 비율 컨테이너 (와이드스크린)</p>
</div>
<!-- data-ratio 속성으로 4:3 비율 지정 -->
<div class="aspectratio" data-ratio="4:3">
<p>4:3 비율 컨테이너 (클래식 비율)</p>
</div>
<!-- data-ratio 속성으로 1:1 비율 지정 -->
<div class="aspectratio" data-ratio="1:1">
<p>1:1 정사각형 (인스타그램 스타일)</p>
</div>
</body>
</html>
실제 예제 3: 카운터 버튼
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>카운터 예제</title>
<style>
/* 카운터 span 기본 스타일 */
span {
border: 1px solid;
padding: 10px 20px;
background: #c0ffc0; /* 밝은 녹색 배경 */
cursor: pointer; /* 클릭 가능한 커서 */
display: inline-block;
margin: 5px;
font-size: 16px;
font-weight: bold;
border-radius: 5px; /* 둥근 모서리 */
}
/* 마우스 호버 시 색상 변경 */
span:hover {
background: #a0ffa0; /* 더 진한 녹색 */
}
/* 컨테이너 중앙 정렬 */
.counter-container {
text-align: center;
margin: 20px;
}
/* 라벨 스타일 */
.label {
display: block;
margin-bottom: 10px;
font-weight: bold;
}
</style>
</head>
<body>
<div class="counter-container">
<h2>클릭하여 숫자를 변경하세요:</h2>
<div class="label">5씩 증가:</div>
<!-- data-inc 속성에 증가값 저장 -->
<span data-inc="5">0</span>
<div class="label">7씩 증가:</div>
<!-- data-inc 속성에 증가값 저장 -->
<span data-inc="7">0</span>
<div class="label">1씩 증가:</div>
<!-- data-inc 속성에 증가값 저장 -->
<span data-inc="1">0</span>
<div class="label">1씩 감소:</div>
<!-- data-inc 속성에 음수값으로 감소 설정 -->
<span data-inc="-1">0</span>
</div>
<script>
// 요소들에 이벤트 리스너를 추가하는 헬퍼 함수
function addEventListeners(elements, event_n, attrib_n, func) {
var i = elements.length;
while (i--) {
// 속성 이름을 함수에 바인딩하여 이벤트 리스너 추가
elements[i].addEventListener(
event_n,
func.bind(elements[i], attrib_n)
);
}
}
// 모든 span 요소에 클릭 이벤트 추가
addEventListeners(
document.querySelectorAll("span"),
"click",
"data-inc",
function (attrib_n) {
// 현재 텍스트 값과 data-inc 속성값을 숫자로 변환하여 더함
// +this.textContent: 현재 표시된 숫자를 가져옴
// +this.getAttribute(attrib_n): data-inc 속성값을 가져옴
this.textContent = +this.textContent + +this.getAttribute(attrib_n);
}
);
</script>
</body>
</html>
CSS로 데이터 속성 활용하기
CSS에서 데이터 속성을 활용하면 매우 강력하고 유연한 스타일링을 구현할 수 있습니다. 다양한 활용 방법을 살펴보겠습니다.
속성 선택자: 데이터를 기반으로 스타일링하기
CSS에서 데이터 속성을 선택자로 사용하면 요소의 상태에 따라 다른 스타일을 적용할 수 있습니다.
/* data-status 속성이 있는 모든 요소를 굵게 보이게 */
[data-status] {
font-weight: bold;
}
/* 활성 상태일 때는 초록색 배경 */
[data-status="active"] {
background-color: #4caf50;
color: white;
padding: 8px 16px;
border-radius: 4px;
}
/* 우선순위가 높은 요소는 빨간색 테두리 */
[data-priority="high"] {
border: 2px solid #f44336;
box-shadow: 0 2px 4px rgba(244, 67, 54, 0.2);
}
/* 우선순위가 낮은 요소는 회색으로 */
[data-priority="low"] {
color: #666;
opacity: 0.7;
}
이런 방식으로 설정하면 JavaScript로 데이터 속성만 바꾸는 것만으로도 스타일을 동적으로 변경할 수 있습니다.
attr() 함수: 데이터 속성 값을 화면에 보여주기
CSS의 attr() 함수는 매우 유용한 기능입니다. 이 함수를 사용하면 데이터 속성의 값을 CSS 콘텐츠로 직접 표시할 수 있습니다.
/* 실제 레벨바 코드 */
#cpu.levelbar:before {
content: attr(data-cpu) "%"; /* data-cpu 값을 표시하고 % 붙이기 */
position: absolute;
right: 10px;
color: white;
}
#mem.levelbar:before {
content: attr(data-mem) "%"; /* data-mem 값을 표시하고 % 붙이기 */
}
/* 실제 활용 예제 */
.price-tag:after {
content: "₩" attr(data-price); /* 가격 표시 */
}
.user-badge:before {
content: "Level " attr(data-level); /* 레벨 표시 */
}
화면 비율 제어: 데이터 속성으로 레이아웃 관리하기
반응형 디자인에서 요소의 비율을 유지하는 것은 매우 중요합니다. 데이터 속성을 활용하면 이를 효율적으로 관리할 수 있습니다.
/* 16:9 비율 */
.aspectratio[data-ratio="16:9"] {
width: 100%;
padding-bottom: 56.25%; /* 9/16 = 0.5625 */
position: relative;
}
/* 4:3 비율 */
.aspectratio[data-ratio="4:3"] {
width: 100%;
padding-bottom: 75%; /* 3/4 = 0.75 */
position: relative;
}
/* 1:1 정사각형 비율 */
.aspectratio[data-ratio="1:1"] {
width: 100%;
padding-bottom: 100%;
position: relative;
}
UI 상태 관리: 사용자 인터랙션에 따른 스타일링
사용자의 인터랙션에 따라 UI가 동적으로 변경되어야 할 때 데이터 속성을 활용하면 효과적입니다.
/* 비활성화된 옵션 */
div.option[data-disabled] {
color: #999;
cursor: not-allowed;
background-color: #f5f5f5;
}
/* 선택된 옵션 */
div.option[data-checked] {
background-color: #2196f3;
color: white;
}
/* 열린 상태의 드롭다운 */
div.select[data-open] {
border-color: #2196f3;
box-shadow: 0 0 5px rgba(33, 150, 243, 0.5);
}
/* 여러 개 선택 가능한 셀렉트 박스 */
div.select[data-multiple] div.header {
min-height: 40px;
}
JavaScript로 데이터 속성 다루기
JavaScript에서 데이터 속성을 다루는 것은 웹 개발에서 매우 중요한 부분입니다. JavaScript를 통해 데이터 속성을 읽고, 수정하고, 삭제하는 다양한 방법들을 살펴보겠습니다.
dataset 속성: 가장 편리한 방법
JavaScript에서 데이터 속성을 다룰 때 가장 효율적인 방법은 dataset 속성을 사용하는 것입니다. 이 방법은 직관적이고 사용하기 간단합니다.
// HTML: <div id="player" data-name="김철수" data-score="100" data-level="5"></div>
const player = document.getElementById("player");
// 데이터 속성 값 읽기
console.log(player.dataset.name); // "김철수"
console.log(player.dataset.score); // "100"
console.log(player.dataset.level); // "5"
// 데이터 속성 값 수정
player.dataset.score = "150"; // 점수를 150으로 업데이트
player.dataset.rank = "1"; // 새로운 데이터 속성 추가
// 데이터 속성 삭제
delete player.dataset.level; // level 속성 제거
중요 사항: data-user-name처럼 하이픈이 포함된 속성명은 dataset.userName처럼 camelCase로 자동 변환됩니다.
getAttribute/setAttribute: 전통적인 방법
dataset이 더 편리하지만, 경우에 따라 전통적인 방법도 필요할 수 있습니다. 특히 동적으로 속성 이름을 생성해야 하는 경우에 유용합니다.
// 전체 속성 이름을 명시해야 함
const score = player.getAttribute("data-score"); // "150"
// 속성 값 수정
player.setAttribute("data-score", "200");
// 속성 제거
player.removeAttribute("data-rank");
// 동적 속성 이름 생성
const statType = "health";
player.setAttribute(`data-${statType}`, "100");
실전 예제: 카운터 구현
// 모든 카운터 span 요소 선택
const counters = document.querySelectorAll("span[data-inc]");
counters.forEach((counter) => {
counter.addEventListener("click", function () {
// 현재 값과 증가값 가져오기
const currentValue = parseInt(this.textContent);
const increment = parseInt(this.dataset.inc);
// 새로운 값 계산하고 표시
this.textContent = currentValue + increment;
});
});
실전 예제: 필터링 시스템
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>필터링 시스템 예제</title>
<style>
.filter {
margin: 10px 0;
padding: 0;
list-style: none;
}
.filter li {
display: inline-block;
margin: 5px;
}
.filter a {
display: block;
padding: 8px 16px;
background: #f0f0f0;
color: #333;
text-decoration: none;
border-radius: 4px;
border: 2px solid transparent;
}
.filter a.selected {
background: #2196f3;
color: white;
border-color: #1976d2;
}
.item {
display: inline-block;
width: 80px;
height: 80px;
margin: 5px;
border-radius: 8px;
line-height: 80px;
text-align: center;
color: white;
font-weight: bold;
}
.item.red {
background: #f44336;
}
.item.blue {
background: #2196f3;
}
.item.yellow {
background: #ffeb3b;
color: #333;
}
.item.small {
width: 60px;
height: 60px;
line-height: 60px;
}
.item.big {
width: 100px;
height: 100px;
line-height: 100px;
}
.item.hidden {
display: none;
}
</style>
</head>
<body>
<h2>필터링 시스템</h2>
<div class="filters">
<h4>색상</h4>
<!-- data-filter-group으로 필터 그룹 구분 -->
<ul class="filter" data-filter-group="color">
<!-- 빈 값("")은 모든 항목 표시 -->
<li><a href="#" data-filter-value="" class="selected">전체</a></li>
<!-- 각 필터 옵션의 CSS 클래스를 data-filter-value에 저장 -->
<li><a href="#" data-filter-value=".red">빨간색</a></li>
<li><a href="#" data-filter-value=".blue">파란색</a></li>
<li><a href="#" data-filter-value=".yellow">노란색</a></li>
</ul>
<h4>크기</h4>
<!-- 크기 필터 그룹 -->
<ul class="filter" data-filter-group="size">
<li><a href="#" data-filter-value="" class="selected">전체</a></li>
<li><a href="#" data-filter-value=".small">작은것</a></li>
<li><a href="#" data-filter-value=".big">큰것</a></li>
</ul>
</div>
<!-- 필터링될 아이템들 -->
<div class="items">
<!-- 각 아이템은 여러 클래스를 가져 다중 필터 조건에 적용됨 -->
<div class="item red small">빨강 작음</div>
<!-- red와 small 클래스 -->
<div class="item red big">빨강 큼</div>
<!-- red와 big 클래스 -->
<div class="item blue small">파랑 작음</div>
<!-- blue와 small 클래스 -->
<div class="item blue big">파랑 큼</div>
<!-- blue와 big 클래스 -->
<div class="item yellow small">노랑 작음</div>
<!-- yellow와 small 클래스 -->
<div class="item yellow big">노랑 큼</div>
<!-- yellow와 big 클래스 -->
<div class="item red">빨강</div>
<!-- red 클래스만 -->
<div class="item blue">파랑</div>
<!-- blue 클래스만 -->
<div class="item yellow">노랑</div>
<!-- yellow 클래스만 -->
</div>
<script>
// 현재 선택된 필터들을 저장하는 객체
const filters = {};
// 모든 필터 링크에 클릭 이벤트 추가
document.querySelectorAll(".filter a").forEach((link) => {
link.addEventListener("click", function (e) {
e.preventDefault(); // 기본 링크 동작 방지
// 같은 그룹의 다른 링크에서 selected 클래스 제거
this.closest(".filter")
.querySelectorAll("a")
.forEach((a) => {
a.classList.remove("selected");
});
// 현재 클릭된 링크에 selected 클래스 추가
this.classList.add("selected");
// data-filter-group 속성에서 필터 그룹 이름 가져오기
const filterGroup = this.closest(".filter").dataset.filterGroup;
// data-filter-value 속성에서 필터 값 가져오기
const filterValue = this.dataset.filterValue;
// 필터 객체에 현재 선택 상태 저장
filters[filterGroup] = filterValue;
// 필터 적용 함수 호출
applyFilters();
});
});
// 선택된 필터에 따라 아이템들을 표시/숨김 처리하는 함수
function applyFilters() {
const items = document.querySelectorAll(".item");
items.forEach((item) => {
let show = true; // 기본적으로 아이템을 보여줌
// 각 필터 그룹의 조건을 확인
for (let group in filters) {
const filterValue = filters[group];
// 필터 값이 있고, 아이템이 해당 클래스를 가지지 않으면 숨김
if (
filterValue &&
!item.classList.contains(filterValue.replace(".", ""))
) {
show = false;
break; // 하나라도 조건에 맞지 않으면 반복 중단
}
}
// 조건에 따라 아이템 표시/숨김
item.classList.toggle("hidden", !show);
});
}
</script>
</body>
</html>
kebab-case와 camelCase 변환
// HTML: <div data-user-name="홍길동" data-phone-number="010-1234-5678"></div>
const element = document.querySelector("div");
// kebab-case → camelCase 자동 변환
console.log(element.dataset.userName); // "홍길동"
console.log(element.dataset.phoneNumber); // "010-1234-5678"
// JavaScript에서 camelCase로 설정하면
element.dataset.homeAddress = "서울시 강남구";
// HTML에는 data-home-address="서울시 강남구"로 저장됨
실무에서 바로 쓸 수 있는 예제들
이제 지금까지 배운 내용을 바탕으로 실제 프로젝트에서 활용할 수 있는 완전한 예제들을 살펴보겠습니다. 이 예제들은 실무에서 바로 사용하거나 프로젝트에 응용할 수 있도록 구성했습니다.
예제 1: 할 일 목록 (Todo List)
<!DOCTYPE html>
<html>
<head>
<style>
.todo-item {
padding: 10px;
margin: 5px;
background: #f0f0f0;
cursor: pointer;
}
.todo-item[data-completed="true"] {
text-decoration: line-through;
background: #d0d0d0;
}
.todo-item[data-priority="high"] {
border-left: 5px solid red;
}
.todo-item[data-priority="medium"] {
border-left: 5px solid orange;
}
.todo-item[data-priority="low"] {
border-left: 5px solid green;
}
</style>
</head>
<body>
<div class="todo-list">
<div
class="todo-item"
data-id="1"
data-completed="false"
data-priority="high"
>
수학 숙제하기
</div>
<div
class="todo-item"
data-id="2"
data-completed="false"
data-priority="medium"
>
방 청소하기
</div>
<div
class="todo-item"
data-id="3"
data-completed="true"
data-priority="low"
>
책 읽기
</div>
</div>
<script>
// 클릭하면 완료 상태 토글
document.querySelectorAll(".todo-item").forEach((item) => {
item.addEventListener("click", function () {
const isCompleted = this.dataset.completed === "true";
this.dataset.completed = !isCompleted;
});
});
</script>
</body>
</html>
예제 2: 이미지 갤러리
<!DOCTYPE html>
<html>
<head>
<style>
.gallery {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
}
.gallery img {
width: 100%;
cursor: pointer;
transition: transform 0.3s;
}
.gallery img:hover {
transform: scale(1.05);
}
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
justify-content: center;
align-items: center;
}
.modal[data-visible="true"] {
display: flex;
}
.modal-info {
color: white;
text-align: center;
}
</style>
</head>
<body>
<div class="gallery">
<img
src="photo1.jpg"
data-title="서울 야경"
data-date="2024-01-15"
data-location="남산타워"
/>
<img
src="photo2.jpg"
data-title="부산 해변"
data-date="2024-02-20"
data-location="해운대"
/>
<img
src="photo3.jpg"
data-title="제주도 풍경"
data-date="2024-03-10"
data-location="한라산"
/>
</div>
<div class="modal" data-visible="false">
<div class="modal-content">
<img id="modal-img" src="" style="max-width: 80%;" />
<div class="modal-info">
<h2 id="modal-title"></h2>
<p id="modal-date"></p>
<p id="modal-location"></p>
</div>
</div>
</div>
<script>
const modal = document.querySelector(".modal");
const modalImg = document.getElementById("modal-img");
const modalTitle = document.getElementById("modal-title");
const modalDate = document.getElementById("modal-date");
const modalLocation = document.getElementById("modal-location");
// 이미지 클릭시 모달 열기
document.querySelectorAll(".gallery img").forEach((img) => {
img.addEventListener("click", function () {
modalImg.src = this.src;
modalTitle.textContent = this.dataset.title;
modalDate.textContent = `촬영일: ${this.dataset.date}`;
modalLocation.textContent = `장소: ${this.dataset.location}`;
modal.dataset.visible = "true";
});
});
// 모달 클릭시 닫기
modal.addEventListener("click", function () {
this.dataset.visible = "false";
});
</script>
</body>
</html>
예제 3: 동적 차트
<!DOCTYPE html>
<html>
<head>
<style>
.chart {
width: 300px;
margin: 20px;
}
.bar {
height: 30px;
background: #e0e0e0;
margin: 10px 0;
position: relative;
border-radius: 15px;
overflow: hidden;
}
.bar-fill {
height: 100%;
background: linear-gradient(to right, #4caf50, #8bc34a);
transition: width 1s ease;
width: 0;
}
.bar[data-category="cpu"] .bar-fill {
background: linear-gradient(to right, #2196f3, #03a9f4);
}
.bar[data-category="memory"] .bar-fill {
background: linear-gradient(to right, #ff9800, #ffc107);
}
.bar[data-category="disk"] .bar-fill {
background: linear-gradient(to right, #9c27b0, #e91e63);
}
.bar-label {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
font-weight: bold;
}
</style>
</head>
<body>
<div class="chart">
<h3>시스템 상태</h3>
<div class="bar" data-category="cpu" data-value="0">
<div class="bar-fill"></div>
<span class="bar-label">CPU: <span class="value">0</span>%</span>
</div>
<div class="bar" data-category="memory" data-value="0">
<div class="bar-fill"></div>
<span class="bar-label">메모리: <span class="value">0</span>%</span>
</div>
<div class="bar" data-category="disk" data-value="0">
<div class="bar-fill"></div>
<span class="bar-label">디스크: <span class="value">0</span>%</span>
</div>
</div>
<button onclick="updateChart()">차트 업데이트</button>
<script>
function updateChart() {
document.querySelectorAll(".bar").forEach((bar) => {
// 랜덤 값 생성 (0~100)
const randomValue = Math.floor(Math.random() * 101);
// 데이터 속성 업데이트
bar.dataset.value = randomValue;
// 막대 채우기
const fill = bar.querySelector(".bar-fill");
fill.style.width = randomValue + "%";
// 라벨 업데이트
const valueSpan = bar.querySelector(".value");
valueSpan.textContent = randomValue;
// 색상 변경 (위험 수준에 따라)
if (randomValue > 80) {
fill.style.background =
"linear-gradient(to right, #f44336, #e91e63)";
}
});
}
// 페이지 로드시 초기 업데이트
updateChart();
</script>
</body>
</html>
알아두면 좋은 주의사항들
데이터 속성을 효과적이고 올바르게 사용하기 위해 주의해야 할 사항들을 정리해보겠습니다.
이런 건 하지 마세요! ❌
이런 실수들은 초보자들이 자주 범하는 오류들입니다. 미리 알아두시면 시행착오를 줄일 수 있습니다.
<!-- 중요한 콘텐츠를 데이터 속성에 넣지 마세요 -->
<div data-title="중요한 제목"></div>
<!-- ❌ 잘못됨 -->
<div><h1>중요한 제목</h1></div>
<!-- ✅ 올바름 -->
<!-- 스타일 정보를 데이터 속성에 넣지 마세요 -->
<div data-color="red" data-size="large"></div>
<!-- ❌ 잘못됨 -->
<div class="text-red text-large"></div>
<!-- ✅ 올바름 -->
<!-- 민감한 정보를 데이터 속성에 넣지 마세요 -->
<div data-password="1234"></div>
<!-- ❌ 절대 안됨! -->
<div data-user-id="guest123"></div>
<!-- ✅ 괜찮음 -->
이렇게 하면 완벽해요! ✅
다음과 같이 사용하면 깔끔하고 유지보수하기 쉬운 코드를 작성할 수 있습니다.
<!-- 의미 있는 이름 사용하기 -->
<button data-action="delete" data-item-id="123">삭제</button>
<!-- 일관성 있는 네이밍 -->
<div
data-product-id="1"
data-product-name="노트북"
data-product-price="1000000"
></div>
<!-- 적절한 데이터 타입 고려하기 -->
<div data-items='["사과", "바나나", "오렌지"]'></div>
<!-- JSON 문자열 -->
성능도 생각해야죠
데이터 속성을 많이 사용할 때는 성능에 대한 고려도 필요합니다. 여러 개의 속성을 한 번에 처리하는 것이 효율적입니다.
// 데이터 속성이 많을 때는 한 번에 처리하기
const element = document.querySelector(".product");
// 비효율적 ❌
element.dataset.name = "노트북";
element.dataset.price = "1000000";
element.dataset.category = "전자제품";
// 효율적 ✅
Object.assign(element.dataset, {
name: "노트북",
price: "1000000",
category: "전자제품",
});
브라우저 호환성은 걱정 마세요!
다행히 데이터 속성은 오래전부터 대부분의 브라우저에서 지원되어 왔습니다.
데이터 속성은 모든 최신 브라우저에서 지원됩니다:
- Chrome ✅
- Firefox ✅
- Safari ✅
- Edge ✅
- Internet Explorer 11 ✅
마무리
이번 글에서는 HTML 데이터 속성의 개념부터 실제 활용 방법까지 자세히 살펴보았습니다.
HTML 데이터 속성은 웹 개발에서 매우 유용한 기능입니다. 핵심 내용을 정리해보면 다음과 같습니다:
📝 HTML에서 data-* 형식으로 구조화된 정보를 저장하고
🎨 CSS에서 속성 선택자와 attr() 함수를 활용해 동적인 스타일링을 구현하고
⚡ JavaScript에서 dataset 속성을 통해 효율적으로 데이터를 조작할 수 있습니다.
이러한 활용법을 잘 익혀두면 더욱 체계적이고 유지보수가 쉬운 웹 애플리케이션을 개발할 수 있습니다.