Menu

Pseudo-class trong CSS: nth-child, not, first-child, focus

Pseudo-class chọn phần tử theo vị trí hoặc trạng thái: :nth-child(), :first-child, :not(), :focus, :checked, :has() và nhiều hơn nữa. Tìm hiểu cú pháp, công thức an+b với công cụ thử trực tiếp, và khác biệt giữa nth-child và nth-of-type.

Trang này có trình soạn thảo chạy trực tiếp. Sửa, chạy và xem đầu ra ngay lập tức.

Pseudo-class là gì

Pseudo-class là một từ khóa đứng sau dấu hai chấm, chọn phần tử theo vị trí trong tài liệu hoặc theo trạng thái của nó. Bạn gắn nó vào một selector thông thường: li:first-child, input:focus, a:hover.

Các pseudo-class trạng thái cho liên kết và chuột (:hover, :active, :visited) có trang riêng, CSS hover.

:nth-child() và công thức an+b

:nth-child() nhận một con số, một từ khóa, hoặc công thức an+b. Trình duyệt thử n = 0, 1, 2, ... và khớp với mọi vị trí mà công thức tạo ra (vị trí bắt đầu từ 1).

Công thứcKhớp vị tríÝ nghĩa
33Phần tử con thứ ba
odd hoặc 2n+11, 3, 5, ...Các hàng lẻ
even hoặc 2n2, 4, 6, ...Các hàng chẵn
3n3, 6, 9, ...Cứ ba phần tử lấy một
n+44, 5, 6, ...Từ phần tử thứ tư trở đi
-n+31, 2, 3Ba phần tử đầu tiên
3n+11, 4, 7, ...Cứ ba phần tử lấy một, bắt đầu từ phần tử đầu

Gõ một công thức và xem những mục nào khớp:

Hãy thử odd, even, 4, n+7, -n+5 và 2n+3. Công thức không hợp lệ sẽ không khớp gì cả.

Phiên bản đếm từ cuối là :nth-last-child(): li:nth-last-child(-n+2) chọn hai mục cuối cùng.

nth-child và nth-of-type

:nth-child() đếm mọi phần tử anh em, bất kể thẻ gì, rồi mới kiểm tra phần còn lại của selector. :nth-of-type() chỉ đếm các phần tử anh em cùng thẻ. Khác biệt lộ ra ngay khi các phần tử anh em có nhiều loại thẻ:

Các cặp tương tự cũng có cho hai đầu: :first-child / :first-of-type, :last-child / :last-of-type, :only-child / :only-of-type.

:not(), :is() và :where()

Pseudo-classVí dụKhớp với
:not(X)li:not(.done)Các phần tử không khớp X
:is(X, Y):is(h1, h2, h3) aCác phần tử khớp bất kỳ mục nào trong danh sách
:where(X, Y):where(ul, ol) liGiống :is(), nhưng độ ưu tiên bằng 0
:has(X)li:has(> input:checked)Các phần tử chứa một phần tử khớp X

:not() là cái được dùng hằng ngày, ví dụ để đặt dấu phân cách giữa các mục nhưng không đặt sau mục cuối:

Pseudo-class trạng thái: focus, checked, disabled, invalid

Pseudo-classKhớp với
:focusPhần tử đang được focus bằng bàn phím hoặc chuột
:focus-visibleĐang được focus, và trình duyệt quyết định cần hiện vòng focus (thường là khi focus bằng bàn phím)
:focus-withinPhần tử chứa phần tử đang được focus
:checkedCheckbox, nút radio đã được chọn hoặc <option> đã được chọn
:disabled / :enabledCác điều khiển biểu mẫu bị (hoặc không bị) vô hiệu hóa
:required / :optionalÔ nhập có hoặc không có required
:invalid / :validÔ nhập có giá trị không qua hoặc qua được kiểm tra hợp lệ
:user-invalidKhông hợp lệ, nhưng chỉ sau khi người dùng đã tương tác với nó
:placeholder-shownÔ nhập đang hiện placeholder
:emptyPhần tử không có phần tử con nào, kể cả chữ
:targetPhần tử có id khớp với #fragment của URL

Bấm vào ô email: nhãn của nó chuyển sang màu xanh nhờ :focus-within. Gõ thứ gì đó không phải email rồi rời ô: :user-invalid đổi viền sang màu hổ phách. Nếu chỉ dùng :invalid, ô bắt buộc còn trống đã bị tô màu hổ phách trước cả khi bạn chạm vào.

Dù bạn làm gì với :focus, hãy luôn giữ một kiểu focus nhìn thấy được. Xóa outline mà không có gì thay thế khiến người dùng bàn phím không biết mình đang ở đâu.

:has(), selector cho phần tử cha

:has() khớp với một phần tử dựa trên những gì nó chứa. Đây chính là "selector cho phần tử cha" được mong đợi từ lâu, và nó hoạt động trong Chrome, Firefox và Safari hiện nay.

Chọn gói còn lại: cả thẻ thay đổi theo nút radio, không cần JavaScript.

Lỗi thường gặp

  • Có dấu cách trước dấu hai chấm. li :first-child nghĩa là "phần tử con đầu tiên bên trong một li". Hãy viết li:first-child.
  • Nghĩ rằng p:nth-child(1) là "thẻ p đầu tiên". Nó nghĩa là "phần tử con đầu tiên, nếu đó là thẻ p". Dùng :first-of-type để chọn thẻ p đầu tiên.
  • Đếm từ 0. Vị trí bắt đầu từ 1: :nth-child(0) không khớp gì cả.
  • Xóa outline khi focus. :focus { outline: none } mà không có gì thay thế sẽ làm hỏng việc điều hướng bằng bàn phím.
  • Nhầm : với ::. :before là cách viết cũ của pseudo-element ::before; pseudo-class luôn dùng một dấu hai chấm.

Câu hỏi thường gặp

Pseudo-class trong CSS là gì?

Là một từ khóa đứng sau dấu hai chấm, chọn phần tử theo trạng thái hoặc vị trí chứ không theo tên, ví dụ a:hover, li:first-child hoặc input:focus. Nó được gắn vào một selector thông thường, và phần lớn pseudo-class được tính độ ưu tiên như một class (:where() tính bằng 0).

nth-child trong CSS hoạt động thế nào?

:nth-child(an+b) khớp với các phần tử có vị trí trong nhóm anh em là a×n+b với n = 0, 1, 2 và cứ thế, đếm từ 1. :nth-child(3) là phần tử con thứ ba, :nth-child(odd) hay 2n+1 là mọi phần tử ở vị trí lẻ, còn :nth-child(n+4) là từ phần tử thứ tư trở đi.

nth-child và nth-of-type khác nhau thế nào?

:nth-child() đếm mọi phần tử anh em, rồi mới kiểm tra phần còn lại của selector; :nth-of-type() chỉ đếm các phần tử anh em cùng loại thẻ. Trong một danh sách gồm một h2 rồi đến các đoạn văn, p:nth-child(1) không khớp gì cả, còn p:nth-of-type(1) khớp với đoạn văn đầu tiên.

Dùng :not() trong CSS thế nào?

Đặt selector cần loại trừ vào trong ngoặc: li:not(.done) khớp với mọi mục danh sách không có class done. Nó cũng nhận một danh sách, input:not([type="checkbox"], [type="radio"]).

Pseudo-class và pseudo-element khác nhau thế nào?

Pseudo-class (một dấu hai chấm, :hover) chọn cả một phần tử có sẵn ở một trạng thái nào đó. Pseudo-element (hai dấu hai chấm, ::before) nhắm vào một phần của phần tử hoặc tạo ra nội dung được sinh thêm.

Hình minh họa các ngôn ngữ lập trình của Coddy

Học lập trình cùng Coddy

Bắt đầu