Table of Contents17 sections
Cách căn giữa một div — từ xịn đến "thôi kệ nó"
Câu hỏi kinh điển của mọi thời đại frontend. Có nhiều cách lắm, nhưng không phải cách nào cũng nên dùng.
Tier 1 — Best Practice (dùng đi không ai judge)
1. Flexbox — GOAT của mọi layout
.parent {
display: flex;
justify-content: center; /* căn ngang */
align-items: center; /* căn dọc */
}Khi nào dùng: Hầu hết mọi trường hợp. Layout 1 chiều, responsive tốt, browser support gần như 100%. Đây là cách mặc định nên nghĩ đến đầu tiên.
2. CSS Grid — khi bạn muốn flex nhưng "fancy" hơn
.parent {
display: grid;
place-items: center; /* shorthand của align-items + justify-items */
}Hoặc đầy đủ hơn:
.parent {
display: grid;
justify-content: center;
align-content: center;
}Khi nào dùng: Layout 2 chiều, hoặc khi place-items: center đọc xong ngầu hơn. Cũng rất modern, browser support ổn.
3. margin: auto — classic, không bao giờ lỗi thời
.child {
width: 300px; /* PHẢI có width */
margin: 0 auto;
}Khi nào dùng: Căn ngang element có width cố định, kiểu wrapper/container của cả trang. Không căn dọc được nhé.
Tier 2 — Dùng được, nhưng có caveats
4. text-align: center (cho inline elements)
.parent {
text-align: center;
}
.child {
display: inline-block;
}Khi nào dùng: Child là text, button, icon — tức là inline hoặc inline-block. Dùng cho block element thì không ăn thua đâu nha.
5. Flexbox trên chính element đó (self-centering)
.child {
display: flex;
justify-content: center;
align-items: center;
}Cách này căn nội dung bên trong child, không phải căn child trong parent. Dễ nhầm lắm.
6. width: fit-content + margin: auto
.child {
width: fit-content;
margin: 0 auto;
}Không cần biết width trước, browser tự tính. Khá tiện nhưng browser support cần check thêm với IE (nếu dự án bạn vẫn còn support IE thì... xin chia buồn 🕯️).
Tier 3 — Dùng được trong hoàn cảnh rất cụ thể
7. position: absolute + transform
.parent {
position: relative;
}
.child {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}Vấn đề: Child bị lấy ra khỏi document flow — các element khác không "biết" nó tồn tại. Dễ gây layout bug, khó responsive, khó maintain.
Dùng khi nào còn hợp lý: Modal, tooltip, overlay, loading spinner — những thứ cố tình nằm trên mọi thứ và không cần interact với flow.
8. position: absolute + margin: auto (ít biết hơn)
.parent {
position: relative;
}
.child {
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
margin: auto;
width: 200px; /* cần có width và height */
height: 100px;
}Ít phổ biến hơn cách trên, nhưng không bị lệch khi scroll như transform. Vẫn có vấn đề out-of-flow như trên.
Tier 4 — Tệ, đừng làm nếu có lựa chọn khác
9. padding cứng tay
.parent {
padding: 50px 100px;
}Magic number. Resize màn hình là vỡ ngay. Không responsive. Đây là "center" bằng niềm tin, không phải bằng code.
10. line-height trick (cho text)
.child {
height: 50px;
line-height: 50px; /* bằng với height */
}Chỉ hoạt động với single-line text. Nếu text xuống dòng là vỡ luôn. Legacy code đầy cái này, đừng viết mới nữa.
11. vertical-align: middle + display: table-cell
.parent {
display: table-cell;
vertical-align: middle;
text-align: center;
}Vẫn hoạt động, nhưng đây là giải pháp từ thời chưa có flexbox. Nếu thấy cái này trong codebase thì biết code đó "có tuổi" rồi 🫡
12. Dùng JavaScript để set position
const el = document.querySelector('.child');
const parent = el.parentElement;
el.style.marginLeft = (parent.offsetWidth - el.offsetWidth) / 2 + 'px';Không cần giải thích tại sao tệ. Đừng. 🚫
Tóm tắt nhanh
Cách | Căn ngang | Căn dọc | Responsive | Nên dùng? |
|---|---|---|---|---|
Flexbox | ✅ | ✅ | ✅ | ⭐⭐⭐ |
Grid | ✅ | ✅ | ✅ | ⭐⭐⭐ |
| ✅ | ❌ | ✅ | ⭐⭐⭐ |
| ✅ | ❌ | ✅ | ⭐⭐ |
| ✅ | ✅ | ⚠️ | ⭐ (modal only) |
| ⚠️ | ⚠️ | ❌ | ❌ |
| ❌ | ✅ | ❌ | ❌ |
JavaScript | ✅ | ✅ | ❌ | 🚫 |
TL;DR: Dùng Flexbox. Nếu không thì Grid. Nếu không thì
margin: auto. Còn lại chỉ dùng khi thực sự cần và biết mình đang làm gì.
