Pseudo-class chọn phần tử theo trạng thái (đang rê chuột, đang focus, là con đầu tiên...), pseudo-element tạo “phần ảo” của phần tử (dòng đầu, chữ đầu, nội dung chèn trước/sau). Đây là công cụ mạnh để làm giao diện tương tác mà không cần JavaScript.
Bạn sẽ học được
- Dùng :hover, :focus, :focus-visible, :active, :visited
- Chọn theo vị trí: :first-child, :nth-child(), :not()
- Dùng ::before, ::after, ::first-letter, ::selection, ::placeholder
- Dùng :has() làm “bộ chọn cha”
Thuật ngữ cần biết
- Pseudo-class
- Một dấu hai chấm, chọn theo trạng thái hoặc vị trí.
- Pseudo-element
- Hai dấu hai chấm, tạo phần ảo để định dạng.
- content
- Thuộc tính bắt buộc của ::before/::after.
Một số khái niệm
| Nhóm | Ví dụ | Ý nghĩa |
|---|---|---|
| Tương tác | :hover :focus :focus-visible :active | Rê chuột, đang nhập, dùng bàn phím, đang bấm |
| Liên kết | :link :visited | Chưa xem / đã xem |
| Vị trí | :first-child :last-child :nth-child(2n+1) :only-child | Theo thứ tự trong cha |
| Theo loại | :first-of-type :nth-of-type(3) | Theo thứ tự cùng thẻ |
| Form | :checked :disabled :required :invalid :placeholder-shown | Trạng thái ô nhập |
| Logic | :not() :is() :where() :has() | Phủ định, nhóm, chọn cha |
Công thức :nth-child(an+b): 2n hoặc even là chẵn, 2n+1 hoặc odd là lẻ, -n+3 là 3 phần tử đầu, 3n là mỗi phần tử thứ 3.
Trạng thái tương tác
<style>
.nut { padding: 10px 18px; border: 0; border-radius: 8px; background: #2e7d32; color: #fff; cursor: pointer; transition: .2s; }
.nut:hover { background: #1b5e20; transform: translateY(-2px); }
.nut:active { transform: translateY(1px); }
.nut:focus-visible { outline: 3px solid #ffb300; outline-offset: 2px; }
input:focus { border-color: #1565c0; box-shadow: 0 0 0 3px #bbdefb; outline: none; }
input { padding: 8px; border: 2px solid #ccc; border-radius: 6px; }
</style>
<button class="nut">Rê chuột, bấm, nhấn Tab</button>
<input placeholder="Bấm vào ô này">Kết quả hiển thị
Chọn theo vị trí và :not()
<style>
li:nth-child(odd) { background: #f1f8e9; }
li:first-child { font-weight: 700; }
li:last-child { color: #c62828; }
li:not(:last-child) { border-bottom: 1px solid #ddd; }
li { list-style: none; padding: 6px 10px; }
ul { padding: 0; max-width: 300px; }
</style>
<ul><li>Sơn La</li><li>Điện Biên</li><li>Lai Châu</li><li>Hòa Bình</li><li>Lào Cai</li></ul>Kết quả hiển thị
::before, ::after và các pseudo-element
<style>
.moi::after { content: "MỚI"; margin-left: 6px; font-size: 11px; background: #e53935; color: #fff; padding: 1px 6px; border-radius: 10px; }
.trich::before { content: "“"; font-size: 40px; color: #2e7d32; line-height: 0; vertical-align: -14px; margin-right: 4px; }
.dau::first-letter { font-size: 2.4em; float: left; line-height: 1; margin-right: 6px; color: #1565c0; font-weight: 700; }
::selection { background: #ffeb3b; }
</style>
<p class="moi">Loạt bài Tailwind CSS</p>
<p class="trich">Học đi đôi với hành.</p>
<p class="dau">Tây Bắc là vùng núi phía tây bắc Bắc Bộ, nổi tiếng với ruộng bậc thang và mùa hoa ban. Hãy bôi đen đoạn này.</p>Kết quả hiển thị
:has(): chọn phần tử cha
<style>
.the { border: 2px solid #ddd; border-radius: 10px; padding: 10px; margin: 6px 0; }
.the:has(input:checked) { border-color: #2e7d32; background: #e8f5e9; }
label:has(+ input:required)::after { content: " *"; color: red; }
</style>
<label class="the" style="display:block"><input type="checkbox"> Chọn gói Cơ bản</label>
<label class="the" style="display:block"><input type="checkbox"> Chọn gói Nâng cao</label>
<label for="e">Email</label> <input id="e" required>Kết quả hiển thị
Mẹo hay
Luôn giữ trạng thái focus nhìn thấy được cho người dùng bàn phím; nếu muốn bỏ viền khi bấm chuột, dùng :focus-visible thay vì xóa outline.
Lưu ý
::before/::after không hoạt động với phần tử rỗng như img, input, và bắt buộc có content (có thể là chuỗi rỗng "").
Thực hành
- Làm bảng kẻ sọc xen kẽ bằng tr:nth-child(even).
- Thêm biểu tượng ↗ sau liên kết ngoài bằng ::after.
- Tô viền xanh cho thẻ khi checkbox bên trong được chọn bằng :has().
- Làm chữ cái đầu đoạn văn to và nổi bật bằng ::first-letter.
Tóm tắt bài học
- :hover, :focus-visible, :active cho tương tác.
- :nth-child(), :first/last-child, :not() theo vị trí.
- ::before/::after cần content; ::first-letter, ::selection, ::placeholder.
- :has() chọn cha theo con.