Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> CSS

Tùy chỉnh Checkbox với CSS appearance Property

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 :indeterminate pseudo-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.