Hướng dẫn tạo công tắc bật/tắt hiện đại cho web/app

Bài này chỉ cho bạn cách làm một toggle switch kiểu iOS/Android: mượt, chuẩn truy cập, dễ tái sử dụng. Ta sẽ dùng HTML + CSS thuần để có bản tối giản, thêm một chút JavaScript để đồng bộ trạng thái khi cần. Tất cả đều sẵn sàng copy dán vào dự án.

Hướng dẫn tạo công tắc bật/tắt hiện đại cho web/app

Khi nào nên dùng công tắc

  • Thiết lập bật/tắt áp dụng ngay (không cần nút Lưu).
  • Tùy chọn nhị phân rõ ràng, không gây mơ hồ như radio/checkbox nhiều lựa chọn.
  • Hành động không phá vỡ ngữ cảnh (không điều hướng sang trang khác).

Tiêu chí UX/UI quan trọng

  • Phản hồi tức thì: trạng thái, màu sắc, chuyển động nhẹ.
  • Hit area đủ lớn: tối thiểu 40×24px.
  • Khả năng truy cập: điều khiển bằng bàn phím, hỗ trợ trình đọc màn hình.
  • Trạng thái đầy đủ: on, off, focus, hover, disabled, loading.

Cấu trúc HTML tối giản (khuyến nghị)

Sử dụng <input type="checkbox"> để giữ hành vi mặc định tốt cho bàn phím và truy cập. Ẩn thị giác, nhưng vẫn còn trong cây truy cập.

<div class="toggle">
  <input
    class="toggle__input"
    type="checkbox"
    id="notify"
    aria-label="Bật thông báo"
  />
  <label class="toggle__track" for="notify"><span class="toggle__thumb"></span></label>
</div>

Demo

CSS tạo kiểu hiện đại (mượt như app)

.toggle {
  --w: 46px;
  --h: 26px;
  --p: 3px;
  --bg-off: #d1d5db;
  --bg-on: #22c55e;
  --thumb: #fff;
  --ring: 0 0 0 3px rgba(34,197,94,.25);
  display: inline-flex;
  align-items: center;
}

.toggle__input {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; border: 0; padding: 0;
  clip: rect(0 0 0 0); clip-path: inset(50%);
  overflow: hidden; white-space: nowrap;
}

.toggle__track {
  position: relative;
  display: inline-block;
  width: var(--w); height: var(--h);
  background: var(--bg-off);
  border-radius: var(--h);
  cursor: pointer;
  transition: background-color .18s ease, box-shadow .18s ease;
  box-shadow: inset 0 1px 2px rgba(0,0,0,.06);
}

.toggle__thumb {
  position: absolute;
  top: var(--p); left: var(--p);
  width: calc(var(--h) - var(--p)*2);
  height: calc(var(--h) - var(--p)*2);
  background: var(--thumb);
  border-radius: 50%;
  box-shadow: 0 1px 2px rgba(0,0,0,.15), 0 3px 6px rgba(0,0,0,.12);
  transition: transform .18s ease;
}

.toggle__input:checked + .toggle__track {
  background: var(--bg-on);
}
.toggle__input:checked + .toggle__track .toggle__thumb {
  transform: translateX(calc(var(--w) - var(--h)));
}

.toggle__track:hover { filter: brightness(0.98); }
.toggle__input:focus-visible + .toggle__track { box-shadow: var(--ring); }

.toggle__input:disabled + .toggle__track {
  cursor: not-allowed;
  filter: grayscale(30%); opacity: .7;
}

Hiển thị nhãn On/Off khi cần

<div class="toggle toggle--labeled">
  <input class="toggle__input" type="checkbox" id="darkmode" aria-labelledby="darkmode-label" />
  <label class="toggle__track" for="darkmode"><span class="toggle__thumb"></span></label>
  <span id="darkmode-label" class="toggle__label">Giao diện tối</span>
</div>

<style>
.toggle--labeled { gap: .5rem; vertical-align: middle; }
.toggle__label { font-size: 14px; line-height: 1; user-select: none; }
</style>

Trạng thái disabled và lỗi

.toggle--error .toggle__track { background: #fecaca; }
.toggle--error .toggle__input:checked + .toggle__track { background: #ef4444; }

Đồng bộ state bằng JavaScript khi cần

<script>
document.addEventListener('change', function(e) {
  const el = e.target;
  if (!el.classList.contains('toggle__input')) return;

  const track = el.nextElementSibling;
  track.style.filter = 'brightness(0.9)';
  setTimeout(() => track.style.filter = '', 120);
});
</script>

Hỗ trợ dark mode và giảm chuyển động

@media (prefers-color-scheme: dark) {
  .toggle__track { background: #374151; }
  .toggle__input:checked + .toggle__track { background: #10b981; }
}

@media (prefers-reduced-motion: reduce) {
  .toggle__track, .toggle__thumb { transition: none; }
}

Biến thể kích thước nhanh

.toggle--sm { --w: 38px; --h: 22px; --p: 3px; }
.toggle--lg { --w: 56px; --h: 32px; --p: 4px; }

Khả năng truy cập chuẩn

  • Sử dụng input checkbox thật.
  • Dùng aria-label hoặc aria-labelledby.
  • Focus rõ ràng với :focus-visible.
  • Không cần role=”switch” nếu dùng input checkbox.

Checklist kiểm thử nhanh

  • Click và phím Space/Enter đều bật tắt được.
  • Tương phản màu đủ mạnh.
  • Disabled thể hiện rõ ràng.
  • Hoạt động tốt trên dark mode.

Bình luận


  • Không có bình luận.

Init Toolbox

Nhấn Ctrl + \ trên máy tính, hoặc vuốt sang trái ở bất kỳ đâu trên mobile.

Đăng nhập





Đang tải...