Giới thiệu
Tương tự radio button, appearance: none cho phép tùy biến hoàn toàn giao diện checkbox. Bài viết trình bày 3 style phổ biến: Checkmark, Switch/Toggle, và Animated Check.
Ví dụ 1: Checkbox Checkmark cơ bản (Cách 1: Background color change)
<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Custom Checkbox</title>
<style>
* { box-sizing: border-box; }
body { font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; padding: 2rem; display: flex; flex-direction: column; gap: 2rem; align-items: center; background: #fafafa; }
.checkboxItem {
display: flex; align-items: center; gap: 0.75rem;
cursor: pointer; font-size: 1.1rem; color: #333;
padding: 0.5rem 1rem; border-radius: 8px;
transition: background 0.2s;
}
.checkboxItem:hover { background: #f0f0f0; }
.checkboxItem input[type="checkbox"] {
appearance: none; -webkit-appearance: none; -moz-appearance: none;
width: 24px; height: 24px;
border: 2px solid #ddd; border-radius: 6px;
background: white; position: relative; cursor: pointer; flex-shrink: 0;
transition: all 0.2s;
}
.checkboxItem input[type="checkbox"]:hover { border-color: #27ae60; }
/* Checked: Background xanh + checkmark trắng */
.checkboxItem input[type="checkbox"]:checked {
background: #27ae60; border-color: #27ae60;
}
.checkboxItem input[type="checkbox"]:checked::after {
content: ""; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) rotate(45deg);
width: 6px; height: 10px; border: solid white; border-width: 0 3px 3px 0;
}
.checkboxItem input[type="checkbox"]:focus-visible {
outline: none; box-shadow: 0 0 0 3px rgba(39, 174, 96, 0.3);
}
.checkboxItem input[type="checkbox"]:disabled { opacity: 0.5; cursor: not-allowed; }
</style>
</head>
<body>
<h2 style="color:#2c3e50; text-align:center;">Custom Checkbox - Checkmark Style</h2>
<div style="display:flex; flex-wrap:wrap; gap:1.5rem; justify-content:center;">
<label class="checkboxItem"><input type="checkbox" checked> Đã hoàn thành</label>
<label class="checkboxItem"><input type="checkbox"> Chưa làm</label>
<label class="checkboxItem"><input type="checkbox" disabled> Vô hiệu</label>
<label class="checkboxItem"><input type="checkbox" disabled checked> Vô hiệu (checked)</label>
</div>
</body>
</html>
Ví dụ 2: Checkbox với Unicode Checkmark (Cách 2: ::before content)
<style>
.checkboxUnicode input[type="checkbox"] {
appearance: none; width: 24px; height: 24px;
border: 2px solid #ddd; border-radius: 6px; background: white;
position: relative; cursor: pointer;
}
.checkboxUnicode input[type="checkbox"]:checked {
background: #8e24aa; border-color: #8e24aa;
}
.checkboxUnicode input[type="checkbox"]:checked::before {
content: "\2713"; /* Unicode checkmark ✓ */
position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
color: white; font-size: 1rem; font-weight: bold; line-height: 1;
}
.checkboxUnicode input[type="checkbox"]:focus-visible {
outline: none; box-shadow: 0 0 0 3px rgba(142, 36, 170, 0.3);
}
</style>
<div class="checkboxUnicode" style="display:flex; gap:1.5rem; flex-wrap:wrap; justify-content:center;">
<label class="checkboxItem"><input type="checkbox" checked> Unicode Checkmark</label>
<label class="checkboxItem"><input type="checkbox"> Unchecked</label>
</div>
Ví dụ 3: Animated Checkbox (Checkmark vẽ bằng SVG/Path)
<style>
.checkboxAnimated input[type="checkbox"] {
appearance: none; width: 28px; height: 28px;
border: 2px solid #ddd; border-radius: 8px; background: white;
position: relative; cursor: pointer;
}
.checkboxAnimated input[type="checkbox"]::after {
content: ""; position: absolute; top: 50%; left: 50%;
width: 10px; height: 5px; border: solid #27ae60;
border-width: 0 3px 3px 0; transform: translate(-50%, -50%) rotate(45deg) scale(0);
opacity: 0; transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.1s;
}
.checkboxAnimated input[type="checkbox"]:checked {
border-color: #27ae60; background: #f0fff4;
}
.checkboxAnimated input[type="checkbox"]:checked::after {
transform: translate(-50%, -50%) rotate(45deg) scale(1); opacity: 1;
}
.checkboxAnimated input[type="checkbox"]:focus-visible {
outline: none; box-shadow: 0 0 0 3px rgba(39, 174, 96, 0.3);
}
</style>
<div class="checkboxAnimated" style="display:flex; gap:1.5rem; justify-content:center;">
<label class="checkboxItem"><input type="checkbox" checked> Animated Check</label>
<label class="checkboxItem"><input type="checkbox"> Click me</label>
</div>
Ví dụ 4: Toggle Switch (On/Off) - Phổ biến cho Settings
<style>
.toggleSwitch {
position: relative; display: flex; align-items: center; gap: 1rem;
}
.toggleSwitch input[type="checkbox"] {
appearance: none; width: 56px; height: 30px; border-radius: 15px;
background: #ddd; border: none; cursor: pointer; position: relative;
transition: background 0.3s;
}
.toggleSwitch input[type="checkbox"]::before {
content: ""; position: absolute; top: 3px; left: 3px;
width: 24px; height: 24px; border-radius: 50%;
background: white; box-shadow: 0 2px 6px rgba(0,0,0,0.2);
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.toggleSwitch input[type="checkbox"]:checked { background: #27ae60; }
.toggleSwitch input[type="checkbox"]:checked::before { transform: translateX(26px); }
.toggleSwitch input[type="checkbox"]:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(39, 174, 96, 0.3); }
/* Labels On/Off */
.toggleSwitch .labels { position: absolute; width: 100%; height: 100%; pointer-events: none; }
.toggleSwitch .labels::before { content: "OFF"; position: absolute; right: 8px; top: 50%; transform: translateY(-50%); font-size: 0.7rem; font-weight: 700; color: #999; }
.toggleSwitch .labels::after { content: "ON"; position: absolute; left: 8px; top: 50%; transform: translateY(-50%); font-size: 0.7rem; font-weight: 700; color: white; opacity: 0; transition: opacity 0.2s; }
.toggleSwitch input:checked + .labels::before { opacity: 0; }
.toggleSwitch input:checked + .labels::after { opacity: 1; }
</style>
<div style="display:flex; flex-direction:column; gap:1rem; align-items:center;">
<label class="toggleSwitch">
<input type="checkbox" checked>
<span class="labels"></span>
<span>Bật thông báo</span>
</label>
<label class="toggleSwitch">
<input type="checkbox">
<span class="labels"></span>
<span>Chế độ tối</span>
</label>
</div>
Ví dụ 5: Checkbox "To-Do List" với Strikethrough
<style>
.todoList { max-width: 400px; margin: 0 auto; }
.todoItem { display: flex; align-items: center; gap: 1rem; padding: 1rem; background: white; border-radius: 8px; margin-bottom: 0.5rem; box-shadow: 0 2px 8px rgba(0,0,0,0.05); transition: all 0.2s; }
.todoItem:hover { box-shadow: 0 4px 16px rgba(0,0,0,0.1); }
.todoItem input[type="checkbox"] {
appearance: none; width: 22px; height: 22px; border: 2px solid #ddd; border-radius: 4px;
background: white; cursor: pointer; flex-shrink: 0; position: relative;
transition: all 0.2s;
}
.todoItem input[type="checkbox"]:hover { border-color: #8e24aa; }
.todoItem input[type="checkbox"]:checked { background: #8e24aa; border-color: #8e24aa; }
.todoItem input[type="checkbox"]:checked::after {
content: ""; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) rotate(45deg);
width: 5px; height: 10px; border: solid white; border-width: 0 2px 2px 0;
}
.todoItem input[type="checkbox"]:focus-visible { outline: none; box-shadow: 0 0 0 3px rgba(142, 36, 170, 0.3); }
.todoText { flex: 1; font-size: 1.05rem; transition: all 0.2s; }
.todoItem input:checked + .todoText { text-decoration: line-through; color: #999; }
</style>
<div class="todoList">
<label class="todoItem"><input type="checkbox"><span class="todoText">Mua sắm tuần này</span></label>
<label class="todoItem"><input type="checkbox" checked><span class="todoText">Hoàn thành báo cáo</span></label>
<label class="todoItem"><input type="checkbox"><span class="todoText">Gọi điện cho khách</span></label>
<label class="todoItem"><input type="checkbox"><span class="todoText">Đọc sách 30 phút</span></label>
</div>
Accessibility & Best Practices
- Label wrapping:
<label><input> Text</label>- click vào text cũng toggle. - Focus visible: Bắt buộc cho keyboard user.
- Disabled state:
opacity: 0.5; cursor: not-allowed;. - Indeterminate state (JS):
input.indeterminate = true- style với:indeterminatepseudo-class. - High Contrast Mode: Test với Windows High Contrast - border/background vẫn hiển thị.
- Print stylesheet: Checkbox nên in ra checked/unchecked rõ ràng.