Nội dung

Nội dung

15 Mẹo Giúp Viết CSS Hiện Đại, Gọn Gàng và Chuyên Nghiệp

Sê-ri - Fe-Series
Nội dung

Bạn từng vật lộn với việc căn giữa một cái nút? Tự hỏi vì sao margin, padding lại “khó ở” như vậy? Hay cảm thấy CSS là một “mê cung” không hồi kết?

Chào mừng bạn đến với cuộc cách mạng viết CSS hiện đại!

Trong bài viết này, mình sẽ chỉ cho bạn 15 mẹo chuyên nghiệp về CSS được chọn lọc, và biến chúng thành những kiến thức dễ hiểu – dễ nhớ – dễ áp dụng, ngay cả khi bạn chưa từng học lập trình web.

Không lý thuyết khô khan. Không cú pháp hàn lâm. Chỉ là những cách viết CSS ngắn hơn, sạch hơn, mạnh hơn – kèm theo ví dụ cụ thể, minh hoạ sinh động, và cả những mẹo ít ai biết tới.

✨ Học xong bài viết này, bạn sẽ không còn “sợ” CSS – mà sẽ bắt đầu “thuần hoá” được nó!


Bạn căn chỉnh phần tử thấy “lệch lạc”, có khoảng trống kỳ lạ, hay khung bị tràn? Đó là vì bạn chưa hiểu Box Model.

Mỗi phần tử HTML đều là một chiếc hộp gồm 4 phần:

+----------------------------+
|        Margin (lề)         |
|  +----------------------+  |
|  |     Border (viền)    |  |
|  |  +----------------+  |  |
|  |  | Padding (đệm)  |  |  |
|  |  | +----------+   |  |  |
|  |  | | Content  |   |  |  |
|  |  | +----------+   |  |  |
|  |  +----------------+  |  |
|  +----------------------+  |
+----------------------------+
<div class="box">Xin chào!</div>
.box {
  width: 200px;
  padding: 20px;
  border: 5px solid red;
  margin: 10px;
  background-color: lightyellow;
}

📏 Tổng chiều rộng thực tế: 200 (content) + 40 (padding) + 10 (border) = 250px
Lưu ý: Margin không tính vào kích thước thực của phần tử, chỉ ảnh hưởng đến khoảng cách với các phần tử khác.

Để tránh nhầm lẫn, hãy dùng:

* {
  box-sizing: border-box; /* padding và border sẽ không làm tăng kích thước */
}

.box-modern {
  width: 200px;
  padding: 20px;
  border: 5px solid red;
  box-sizing: border-box; /* Tổng chiều rộng chỉ là 200px */
}

Kết quả: Chiều rộng cuối cùng vẫn là 200px, padding và border sẽ “ăn vào” bên trong!


Chrome tốt, nhưng Firefox có thêm tính năng chuyên biệt dành cho CSS như:

  • Gợi ý lỗi tràn (overflow)
  • Xem bố cục Flexbox/Grid trực quan
  • Hiển thị rõ Box Model từng lớp
  • Chuột phải phần tử → Inspect → Tab “Layout” trên Firefox
/* Thêm outline để debug layout mà không ảnh hưởng box model */
* {
  outline: 1px solid red !important;
}

/* Hoặc dùng này để thấy tất cả elements */
* {
  background-color: rgba(255,0,0,.2) !important;
  outline: 1px solid red !important;
}

Paste đoạn CSS này vào DevTools Console để thấy ngay layout của toàn bộ trang!


Bạn muốn căn giữa, chia hàng/cột linh hoạt nhưng dùng float, position rối rắm?

<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
</div>
.container {
  display: flex;
  justify-content: center; /* căn giữa theo chiều ngang */
  align-items: center;      /* căn giữa theo chiều dọc */
  height: 200px;
  border: 1px solid black;
}
.item {
  padding: 20px;
  background: lightblue;
}

🎯 Kết quả: hai item nằm giữa cả theo chiều ngang và dọc

.flex-container {
  display: flex;
  
  /* Main Axis (trục chính) - mặc định là horizontal */
  justify-content: space-between; /* space-around, space-evenly, flex-start, flex-end */
  
  /* Cross Axis (trục phụ) - mặc định là vertical */  
  align-items: stretch; /* flex-start, flex-end, center, baseline */
  
  /* Đổi hướng */
  flex-direction: row; /* row-reverse, column, column-reverse */
  
  /* Xuống hàng khi cần */
  flex-wrap: wrap; /* nowrap, wrap-reverse */
}

.flex-item {
  flex: 1; /* Viết tắt của: flex-grow: 1, flex-shrink: 1, flex-basis: 0 */
  
  /* Hoặc chi tiết hơn */
  flex-grow: 2;    /* Chiếm 2 phần trong không gian còn lại */
  flex-shrink: 1;  /* Có thể co lại khi cần */
  flex-basis: 100px; /* Kích thước ban đầu */
}

Khi bạn cần tạo bố cục nhiều dòng, nhiều cột (như giao diện admin, dashboard…)

<div class="grid">
  <div class="item">A</div>
  <div class="item">B</div>
  <div class="item">C</div>
</div>
.grid {
  display: grid;
  grid-template-columns: 1fr 2fr 1fr; /* 3 cột: cột giữa lớn gấp đôi */
  gap: 10px;
}
.item {
  background-color: lightgreen;
  padding: 10px;
}

fr là đơn vị phần (fractional unit), giúp chia đều không gian mà không cần pixel.

.advanced-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); /* Responsive không cần media query */
  grid-template-rows: auto 1fr auto; /* header, main, footer */
  gap: 1rem;
  
  /* Đặt tên cho lines */
  grid-template-areas: 
    "header header header"
    "sidebar main aside"
    "footer footer footer";
}

.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }

/* Grid item positioning */
.special-item {
  grid-column: 1 / 3; /* Từ cột 1 đến cột 3 */
  grid-row: 2 / 4;    /* Từ hàng 2 đến hàng 4 */
}

Dùng nhiều @media gây rối?

.title {
  font-size: clamp(16px, 5vw, 32px); /* nhỏ nhất 16px, lớn nhất 32px */
}

.container {
  width: min(90vw, 1200px); /* Nhỏ hơn trong 90vw và 1200px */
  padding: max(1rem, 5vw); /* Lớn hơn trong 1rem và 5vw */
}

.responsive-spacing {
  margin: clamp(1rem, 5vw, 3rem);
  padding: clamp(0.5rem, 2vw, 2rem);
}

/* Modern responsive typography */
.responsive-text {
  font-size: clamp(1rem, 2.5vw, 2rem);
  line-height: clamp(1.4, 1.5vw + 1rem, 1.8);
}

Tự động co giãn theo kích thước màn hình mà không cần @media

.modern-units {
  /* Viewport units */
  height: 100vh;  /* 100% viewport height */
  width: 100vw;   /* 100% viewport width */
  height: 100dvh; /* Dynamic viewport height (mobile-friendly) */
  
  /* Container query units - CSS2023 */
  width: 50cqw;   /* 50% container query width */
  height: 30cqh;  /* 30% container query height */
  
  /* Relative units */
  font-size: 1rem;  /* Relative to root font-size */
  width: 10ch;      /* Width of 10 characters */
  height: 3ex;      /* Height of 3 x-heights */
}

Đôi khi tên lớp quá dài và khó nhớ, ví dụ:

<div class="error-message-important-red-text">Oops!</div>

Bạn có thể dùng emoji như một mã ngắn gọn:

<div class="🔥">Oops!</div>
.🔥 {
  color: red;
  font-weight: bold;
}
  • Không nên lạm dụng trong dự án lớn hoặc teamwork
  • Dễ gây hiểu lầm nếu không được chú thích rõ
  • Có thể gây lỗi nếu hệ thống không hỗ trợ tên lớp bằng emoji

✅ Dùng trong dự án cá nhân, học tập hoặc để tạo style vui nhộn


Phải dùng mẹo padding-bottom, position: absolute, khá phức tạp.

<div class="video-preview"></div>
.video-preview {
  aspect-ratio: 16 / 9; /* giữ tỉ lệ 16:9 */
  background-color: black;
  width: 100%;
}

Dễ dàng áp dụng với ảnh, iframe, div chứa media…

<div class="image-container">
  <img src="image.jpg" alt="Sample image" />
</div>
.image-container {
  aspect-ratio: 16 / 9;
  overflow: hidden;
}

.image-container img {
  width: 100%;
  height: 100%;
  object-fit: cover; /* Crop ảnh để vừa khung */
  object-position: center; /* Căn giữa phần được crop */
}

/* Aspect ratio khác */
.square { aspect-ratio: 1; }
.portrait { aspect-ratio: 3 / 4; }
.ultrawide { aspect-ratio: 21 / 9; }

:root {
  --main-color: #4CAF50;
  --spacing: 16px;
}
.button {
  background: var(--main-color);
  padding: var(--spacing);
}

Khi bạn đổi màu chính, chỉ cần sửa trong :root

  • Dễ tái sử dụng
  • Tự động kế thừa trong các thành phần con
  • Có thể dùng cho cả toán học:
.box {
  width: calc(var(--spacing) * 2);
}

.sidebar {
  width: calc(100vw - 200px);
}

100vw: chiều rộng toàn màn hình -200px: dành chỗ cho sidebar hoặc padding

.card {
  animation-delay: calc(var(--index) * 0.2s);
}

Bạn có thể gán --index: 1, 2, 3… cho từng .card để tạo hiệu ứng lướt sóng


Phải viết thủ công từng số thứ tự trong HTML

<ol class="steps">
  <li>Bắt đầu</li>
  <li>Chạy</li>
  <li>Về đích</li>
</ol>
.steps {
  counter-reset: step; /* khởi tạo bộ đếm */
}

.steps li {
  counter-increment: step; /* tăng mỗi lần gặp li */
  list-style: none;
}

.steps li::before {
  content: "Bước " counter(step) ": ";
  font-weight: bold;
}

Kết quả:

Bước 1: Bắt đầu
Bước 2: Chạy
Bước 3: Về đích

Menu xổ xuống thường phải viết JavaScript để mở/đóng khi người dùng nhấp vào input.

<div class="dropdown">
  <input type="text" placeholder="Nhập gì đó..." />
  <div class="menu">Gợi ý A<br/>Gợi ý B</div>
</div>
.dropdown .menu {
  display: none;
}

.dropdown:focus-within .menu {
  display: block;
  background: #eee;
  padding: 10px;
}

Bất kỳ phần tử con nào được focus (ví dụ: input) → menu hiện Khi focus mất → menu ẩn


  • CSS hiện đại (ví dụ: flex, grid, clamp) đôi khi không hoạt động trên trình duyệt cũ.
  • Bạn không muốn viết thủ công:
display: -webkit-box;
display: -ms-flexbox;
display: flex;
  • Tự động thêm prefix khi build
  • Giúp CSS gọn gàng, tương thích trình duyệt tốt hơn
npm install -D autoprefixer postcss
// postcss.config.js
export default {
  plugins: {
    autoprefixer: {}
  }
}

Khi website hỗ trợ ngôn ngữ RTL (Right-to-Left) như tiếng Ả Rập, margin-left sẽ không phù hợp.

/* Thay vì dùng physical properties */
.old-way {
  margin-left: 1rem;
  margin-right: 2rem;
  border-left: 2px solid red;
  text-align: left;
}

/* Dùng logical properties */
.new-way {
  margin-inline-start: 1rem;  /* margin-left trong LTR, margin-right trong RTL */
  margin-inline-end: 2rem;    /* margin-right trong LTR, margin-left trong RTL */
  border-inline-start: 2px solid red;
  text-align: start;          /* left trong LTR, right trong RTL */
}

/* Logical properties cho block direction */
.block-direction {
  margin-block-start: 1rem;   /* margin-top */
  margin-block-end: 2rem;     /* margin-bottom */
  padding-block: 1rem;        /* padding-top và padding-bottom */
  padding-inline: 2rem;       /* padding-left và padding-right */
}

/* :is() - Nhóm selectors */
/* Thay vì viết: */
.header h1, .header h2, .header h3 { color: blue; }
.sidebar h1, .sidebar h2, .sidebar h3 { color: blue; }

/* Viết ngắn gọn: */
:is(.header, .sidebar) :is(h1, h2, h3) { 
  color: blue; 
}

/* :where() - Giống :is() nhưng specificity = 0 */
:where(.card, .widget) h2 {
  margin-top: 0; /* Dễ override */
}

/* :not() với nhiều selector */
button:not(.disabled, .loading, .ghost) {
  background: blue;
}

/* :has() - Parent selector (CSS2023) */
.card:has(img) {
  display: grid;
  grid-template-columns: 1fr 2fr;
}

.article:has(h2) .read-time {
  display: block; /* Chỉ hiện read-time nếu có h2 */
}

/* Container queries */
@container (min-width: 400px) {
  .card {
    display: grid;
    grid-template-columns: 1fr 1fr;
  }
}

/* ✅ GOOD - Chỉ animate properties này để có 60fps */
.smooth-animation {
  transition: transform 0.3s ease, opacity 0.3s ease;
}

.smooth-animation:hover {
  transform: translateY(-5px) scale(1.05);
  opacity: 0.9;
}

/* ❌ BAD - Làm browser repaint/reflow */
.laggy-animation {
  transition: width 0.3s, height 0.3s, top 0.3s;
}

/* Custom easing với cubic-bezier */
.custom-ease {
  transition: transform 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}

/* CSS Animation với keyframes */
@keyframes slideInUp {
  from {
    transform: translateY(100px);
    opacity: 0;
  }
  to {
    transform: translateY(0);
    opacity: 1;
  }
}

.slide-in {
  animation: slideInUp 0.6s ease-out;
  animation-fill-mode: both; /* Giữ trạng thái cuối */
}

/* Staggered animation với CSS Variables */
.stagger-item {
  animation: slideInUp 0.6s ease-out;
  animation-delay: calc(var(--index) * 0.1s);
  animation-fill-mode: both;
}
/* Tôn trọng người dùng muốn giảm animation */
@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

CSS không chỉ là ngôn ngữ “trang điểm” cho website. Khi hiểu đúng và dùng đúng, nó là một công cụ mạnh mẽ giúp bạn:

  • Viết ít, hiệu quả hơn với modern CSS features
  • 🎯 Tạo bố cục responsive tốt trên mọi thiết bị
  • Giảm phụ thuộc JavaScript cho UI interactions
  • 🔧 Dễ bảo trì, dễ mở rộng với CSS Variables và logical properties
  • 🌍 Hỗ trợ đa ngôn ngữ với logical properties
  • Accessible với prefers-reduced-motion và semantic selectors
  1. Thực hành: Thử từng tip trong dự án nhỏ
  2. Đọc thêm: MDN CSS cho documentation chi tiết
  3. Tools: Cài đặt DevTools, PostCSS cho workflow tốt hơn
  4. Keep learning: CSS đang phát triển nhanh với Container Queries, :has(), CSS Layers

💡 Pro tip: Bookmark bài này và quay lại khi cần reference nhanh các CSS patterns!