🎯 Bài 2: CSS Selectors

Cách chọn chính xác phần tử HTML để style

📖 1. CSS Selectors là gì?

Selector là cách để chọn (select) các phần tử HTML mà bạn muốn áp dụng CSS.

💡 Ví dụ dễ hiểu:
Selector giống như việc bạn chỉ định "Tôi muốn sơn màu xanh cho TẤT CẢ các cửa sổ" hoặc "Chỉ sơn màu đỏ cho cửa sổ ở phòng ngủ"
/* Selector chọn tất cả thẻ p */
p {
  color: blue;
}

/* Selector chọn thẻ có class="highlight" */
.highlight {
  background: yellow;
}

/* Selector chọn thẻ có id="header" */
#header {
  font-size: 24px;
}

🎯 2. Các loại Selectors cơ bản

📍 2.1. Universal Selector (*)

Chọn TẤT CẢ các phần tử trên trang.

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
📌 Khi nào dùng? Thường dùng để reset CSS mặc định của browser.

📍 2.2. Element Selector (Tag Selector)

Chọn tất cả các thẻ HTML cùng loại.

p {
  color: blue;
}

h1 {
  font-size: 32px;
}

div {
  background: lightgray;
}
📺 Demo:

Đoạn văn 1 - sẽ có màu chữ blue

Đoạn văn 2 - cũng có màu chữ blue

Div này có background lightgray

📍 2.3. Class Selector (.)

Chọn tất cả các phần tử có class cụ thể.

<p class="highlight">Đoạn văn được highlight</p>
<div class="highlight">Div cũng được highlight</div>
<p>Đoạn văn bình thường</p>
.highlight {
  background: yellow;
  font-weight: bold;
}
✅ Ưu điểm:
  • Có thể tái sử dụng cho nhiều element
  • Một element có thể có nhiều class
  • Khuyến nghị dùng trong thực tế!

📍 2.4. ID Selector (#)

Chọn phần tử có id cụ thể. ID phải là duy nhất trong trang.

<div id="header">Header</div>
<div id="footer">Footer</div>
#header {
  background: navy;
  color: white;
}

#footer {
  text-align: center;
}
⚠️ Lưu ý:
  • Mỗi ID chỉ dùng 1 lần trong trang
  • ID có độ ưu tiên cao → khó override
  • Nên ưu tiên dùng class thay vì ID

📍 So sánh Class vs ID

Tiêu chí Class (.) ID (#)
Cú pháp HTML class="menu" id="header"
Cú pháp CSS .menu { } #header { }
Tái sử dụng ✅ Nhiều lần ❌ Chỉ 1 lần
Độ ưu tiên 10 điểm 100 điểm
Nhiều giá trị ✅ Được (class="a b c") ❌ Không
Khuyến nghị ⭐ Khuyên dùng Dùng cho JS hoặc anchor link

🚀 3. Selectors nâng cao

📍 3.1. Descendant Selector (khoảng trắng)

Chọn element nằm BÊN TRONG element khác (con, cháu, chắt...).

/* Chọn TẤT CẢ thẻ p bên trong div */
div p {
  color: red;
}

/* Chọn TẤT CẢ thẻ a bên trong .menu */
.menu a {
  text-decoration: none;
}
<div>
  <p>Paragraph này sẽ màu đỏ</p>
  <section>
    <p>Paragraph này cũng màu đỏ (vì vẫn bên trong div)</p>
  </section>
</div>
<p>Paragraph này KHÔNG màu đỏ (ngoài div)</p>

📍 3.2. Child Selector (>)

Chọn element là CON TRỰC TIẾP của element khác.

/* Chỉ chọn thẻ p là CON TRỰC TIẾP của div */
div > p {
  color: blue;
}
<div>
  <p>Paragraph này màu xanh (con trực tiếp)</p>
  <section>
    <p>Paragraph này KHÔNG màu xanh (cháu, không phải con)</p>
  </section>
</div>

📍 3.3. Adjacent Sibling Selector (+)

Chọn element đứng NGAY SAU element khác (cùng cấp).

/* Chọn thẻ p đứng NGAY SAU h2 */
h2 + p {
  font-weight: bold;
}
<h2>Tiêu đề</h2>
<p>Paragraph này bold (đứng ngay sau h2)</p>
<p>Paragraph này bình thường</p>

📍 3.4. General Sibling Selector (~)

Chọn TẤT CẢ element đứng sau element khác (cùng cấp).

/* Chọn TẤT CẢ thẻ p đứng sau h2 */
h2 ~ p {
  color: gray;
}
<h2>Tiêu đề</h2>
<p>Paragraph 1 - màu xám</p>
<p>Paragraph 2 - màu xám</p>
<p>Paragraph 3 - màu xám</p>

📍 3.5. Grouping Selector (,)

Áp dụng cùng style cho nhiều selector.

/* Cách viết dài */
h1 { color: blue; }
h2 { color: blue; }
h3 { color: blue; }

/* Cách viết ngắn gọn */
h1, h2, h3 {
  color: blue;
}

.button, .link, #submit {
  cursor: pointer;
}

📊 Tóm tắt Combinator Selectors

Selector Tên Ý nghĩa Ví dụ
A B Descendant B bên trong A (con, cháu...) div p
A > B Child B là con trực tiếp của A div > p
A + B Adjacent Sibling B đứng ngay sau A h2 + p
A ~ B General Sibling Tất cả B sau A h2 ~ p
A, B Grouping Chọn cả A và B h1, h2

📋 4. Attribute Selectors

Chọn element dựa trên thuộc tính (attribute) của nó.

📍 4.1. [attribute]

Chọn element có attribute cụ thể.

/* Chọn tất cả thẻ có attribute "title" */
[title] {
  border-bottom: 1px dotted;
}

/* Chọn tất cả input có attribute "required" */
input[required] {
  border: 2px solid red;
}

📍 4.2. [attribute="value"]

Chọn element có attribute với giá trị chính xác.

/* Chọn input có type="text" */
input[type="text"] {
  background: lightyellow;
}

/* Chọn link có target="_blank" */
a[target="_blank"] {
  color: red;
}

📍 4.3. [attribute^="value"]

Chọn element có attribute BẮT ĐẦU bằng value.

/* Chọn link bắt đầu bằng "https://" */
a[href^="https://"] {
  color: green;
}

/* Chọn class bắt đầu bằng "btn-" */
[class^="btn-"] {
  padding: 10px 20px;
}

📍 4.4. [attribute$="value"]

Chọn element có attribute KẾT THÚC bằng value.

/* Chọn link kết thúc bằng ".pdf" */
a[href$=".pdf"] {
  background: url('pdf-icon.png') no-repeat;
  padding-left: 20px;
}

/* Chọn ảnh định dạng .jpg */
img[src$=".jpg"] {
  border: 2px solid blue;
}

📍 4.5. [attribute*="value"]

Chọn element có attribute CHỨA value (ở bất kỳ đâu).

/* Chọn link chứa "google" */
a[href*="google"] {
  color: #4285f4;
}

/* Chọn class chứa "primary" */
[class*="primary"] {
  background: blue;
}
Selector Ý nghĩa Ví dụ
[attr] Có attribute [title]
[attr="val"] Giá trị chính xác [type="text"]
[attr^="val"] Bắt đầu bằng [href^="https"]
[attr$="val"] Kết thúc bằng [href$=".pdf"]
[attr*="val"] Chứa [class*="btn"]

✨ 5. Pseudo-class Selectors

Chọn element dựa trên TRẠNG THÁI hoặc VỊ TRÍ của nó.

📍 5.1. Link Pseudo-classes

/* Link chưa được visit */
a:link {
  color: blue;
}

/* Link đã được visit */
a:visited {
  color: purple;
}

/* Khi hover chuột lên link */
a:hover {
  color: red;
  text-decoration: underline;
}

/* Khi đang click (active) */
a:active {
  color: orange;
}
⚠️ Thứ tự quan trọng: Link → Visited → Hover → Active (LVHA)

📍 5.2. Input Pseudo-classes

/* Input đang được focus */
input:focus {
  border: 2px solid blue;
  outline: none;
}

/* Input bị disabled */
input:disabled {
  background: #e0e0e0;
  cursor: not-allowed;
}

/* Checkbox được check */
input:checked {
  accent-color: green;
}

📍 5.3. Structural Pseudo-classes

/* Element đầu tiên */
li:first-child {
  font-weight: bold;
}

/* Element cuối cùng */
li:last-child {
  border-bottom: none;
}

/* Element thứ 3 */
li:nth-child(3) {
  color: red;
}

/* Các element chẵn (2, 4, 6...) */
li:nth-child(even) {
  background: #f0f0f0;
}

/* Các element lẻ (1, 3, 5...) */
li:nth-child(odd) {
  background: white;
}
📺 Demo nth-child:
  • Item 1 (lẻ - trắng)
  • Item 2 (chẵn - xám)
  • Item 3 (lẻ - trắng)
  • Item 4 (chẵn - xám)

📍 5.4. Other Useful Pseudo-classes

/* Element không có class="special" */
p:not(.special) {
  color: gray;
}

/* Div rỗng (không có nội dung) */
div:empty {
  display: none;
}

/* Element duy nhất con của parent */
p:only-child {
  text-align: center;
}
Pseudo-class Ý nghĩa
:hover Khi di chuột qua
:focus Khi được focus (input, button)
:first-child Con đầu tiên
:last-child Con cuối cùng
:nth-child(n) Con thứ n
:not(selector) Không phải selector

🎯 Bài tập thực hành

Bài 1: Tạo Menu Navigation

Tạo menu với các yêu cầu:

📺 Demo kết quả mẫu:

💡 Di chuột qua các item để xem hover effect!

Bài 2: Style Form

Tạo form với các field:

📺 Demo kết quả mẫu:

💡 Click vào ô input để xem focus effect. Check vào checkbox!

Bài 3: Style Table

Tạo bảng với style:

📺 Demo kết quả mẫu:
STT Họ tên Email Tuổi
1 Nguyễn Văn A nguyenvana@email.com 25
2 Trần Thị B tranthib@email.com 28
3 Lê Văn C levanc@email.com 30
4 Phạm Thị D phamthid@email.com 22
5 Hoàng Văn E hoangvane@email.com 27

💡 Di chuột qua các dòng để xem hover effect!

💡 Gợi ý code mẫu Bài 1:
/* Menu Navigation */
ul {
  list-style: none;
  display: flex;
  gap: 0;
}

li {
  padding: 15px 25px;
  border-right: 1px solid #ddd;
}

li:first-child {
  border-left: 3px solid #667eea;
}

li:last-child {
  border-right: 3px solid #764ba2;
}

li:hover {
  background: #f0f0f0;
}

a:link {
  color: #333;
  text-decoration: none;
}

a:visited {
  color: #999;
}

a:hover {
  color: #667eea;
}