Bài này áp dụng kiến thức đã học để tự xây các thành phần giao diện thường gặp chỉ bằng HTML và CSS: nút nhiều kiểu, thanh điều hướng, menu thả xuống, tooltip, phân trang, ô nhập liệu và công tắc. Hiểu cách tự làm giúp bạn dùng Bootstrap, Tailwind sau này chủ động hơn.
- Tạo hệ thống nút: chính, phụ, viền, kích thước
- Làm thanh điều hướng và dropdown bằng :hover/:focus-within
- Làm tooltip, badge, phân trang
- Định dạng form: ô nhập, select, checkbox dạng công tắc
Một số khái niệm
Một thành phần tốt có: trạng thái đầy đủ (bình thường, hover, focus, active, disabled), kích thước theo hệ (sm, md, lg), dùng biến để đổi màu, và trợ năng (focus nhìn thấy, vùng bấm đủ lớn, nhãn rõ ràng).
Hệ thống nút
<style>
.btn { --c: #2e7d32; display: inline-flex; align-items: center; gap: 6px; padding: .55rem 1rem; border-radius: 8px; border: 2px solid var(--c); background: var(--c); color: #fff; font: 600 14px system-ui; cursor: pointer; transition: .2s; margin: 3px; }
.btn:hover { filter: brightness(1.1); } .btn:focus-visible { outline: 3px solid #ffb300; outline-offset: 2px; }
.btn-vien { background: transparent; color: var(--c); }
.btn-do { --c: #c62828; } .btn-xanh { --c: #1565c0; }
.btn-sm { padding: .3rem .6rem; font-size: 12px; } .btn-lg { padding: .8rem 1.4rem; font-size: 16px; }
.btn:disabled { opacity: .5; cursor: not-allowed; }
</style>
<button class="btn">Chính</button><button class="btn btn-vien">Viền</button><button class="btn btn-xanh">Xanh</button><button class="btn btn-do btn-sm">Xóa (nhỏ)</button><button class="btn btn-lg">Lớn</button><button class="btn" disabled>Vô hiệu</button>Thanh điều hướng có dropdown
<style>
.nav { display: flex; gap: 4px; background: #263238; padding: 6px; border-radius: 10px; font: 14px system-ui; }
.nav > li { list-style: none; position: relative; }
.nav a { display: block; padding: 8px 14px; color: #eceff1; text-decoration: none; border-radius: 6px; }
.nav a:hover, .nav li:focus-within > a { background: #37474f; }
.sub { position: absolute; top: 100%; left: 0; min-width: 170px; background: #fff; border-radius: 8px; box-shadow: 0 10px 24px rgb(0 0 0 / .18); padding: 6px; margin: 0;
opacity: 0; visibility: hidden; transform: translateY(6px); transition: .2s; z-index: 5; }
.nav li:hover > .sub, .nav li:focus-within > .sub { opacity: 1; visibility: visible; transform: none; }
.sub li { list-style: none; } .sub a { color: #263238; } .sub a:hover { background: #e8f5e9; }
</style>
<ul class="nav"><li><a href="#">Trang chủ</a></li>
<li><a href="#">Khóa học ▾</a><ul class="sub"><li><a href="#">HTML</a></li><li><a href="#">CSS</a></li><li><a href="#">Bootstrap 5</a></li></ul></li>
<li><a href="#">Liên hệ</a></li></ul>:focus-within giúp menu con mở cả khi dùng phím Tab, không chỉ chuột.
Tooltip, badge và phân trang
<style>
.tip { position: relative; border-bottom: 1px dotted; cursor: help; }
.tip::after { content: attr(data-tip); position: absolute; bottom: 130%; left: 50%; transform: translateX(-50%); white-space: nowrap; background: #263238; color: #fff; font-size: 12px; padding: 4px 8px; border-radius: 6px; opacity: 0; pointer-events: none; transition: .2s; }
.tip:hover::after { opacity: 1; }
.badge { background: #e53935; color: #fff; font-size: 11px; padding: 1px 7px; border-radius: 10px; margin-left: 4px; }
.trang { display: flex; gap: 4px; list-style: none; padding: 0; }
.trang a { display: grid; place-items: center; min-width: 34px; height: 34px; border: 1px solid #cfd8dc; border-radius: 8px; text-decoration: none; color: #263238; }
.trang a:hover { background: #eceff1; } .trang a[aria-current] { background: #2e7d32; color: #fff; border-color: #2e7d32; }
</style>
<p style="margin-top:30px">Rê chuột vào <span class="tip" data-tip="Cascading Style Sheets">CSS</span> · Thông báo <span class="badge">3</span></p>
<ul class="trang"><li><a href="#">‹</a></li><li><a href="#">1</a></li><li><a href="#" aria-current="page">2</a></li><li><a href="#">3</a></li><li><a href="#">›</a></li></ul>Form và công tắc
<style>
.f { display: grid; gap: 10px; max-width: 320px; font: 14px system-ui; }
.f label { display: grid; gap: 4px; font-weight: 600; }
.f input, .f select { padding: 9px 12px; border: 1px solid #b0bec5; border-radius: 8px; font: inherit; }
.f input:focus, .f select:focus { outline: none; border-color: #2e7d32; box-shadow: 0 0 0 3px rgb(46 125 50 / .2); }
.f input:user-invalid { border-color: #c62828; }
.sw { display: flex !important; align-items: center; gap: 10px; font-weight: 400 !important; }
.sw input { appearance: none; width: 42px; height: 24px; border-radius: 12px; background: #b0bec5; position: relative; cursor: pointer; transition: .2s; padding: 0; border: 0; }
.sw input::before { content: ""; position: absolute; top: 3px; left: 3px; width: 18px; height: 18px; border-radius: 50%; background: #fff; transition: .2s; }
.sw input:checked { background: #2e7d32; } .sw input:checked::before { transform: translateX(18px); }
.f { accent-color: #2e7d32; }
</style>
<form class="f" onsubmit="return false"><label>Email<input type="email" required placeholder="Địa chỉ email này đang được bảo vệ từ spam bots, bạn cần kích hoạt Javascript để xem nó. Bạn cần kích hoạt Javascript để xem nó. "></label>
<label>Ngành<select><option>Công nghệ thông tin</option><option>Sư phạm Tin học</option></select></label>
<label class="sw"><input type="checkbox" checked> Nhận thông báo bài mới</label></form>Đây chính là những gì Bootstrap và Tailwind làm sẵn cho bạn. Sau bài này, hãy mở mã nguồn class .btn của Bootstrap để so sánh với cách tự viết.
Dropdown chỉ dựa vào :hover không dùng được trên điện thoại cảm ứng và bàn phím; thêm :focus-within và với menu phức tạp nên bổ sung JavaScript cùng thuộc tính aria-expanded.
- Xây bộ nút 4 màu × 3 kích thước dùng biến --c.
- Làm menu ngang có dropdown hoạt động bằng bàn phím.
- Làm tooltip cho các thuật ngữ trong một đoạn văn.
- Làm form đăng ký có trạng thái lỗi và công tắc.
- Thành phần cần đủ trạng thái, kích thước, biến màu.
- :hover + :focus-within cho dropdown.
- attr() + ::after cho tooltip đơn giản.
- appearance: none để tự vẽ checkbox, công tắc; accent-color cho nhanh.