Responsive Design và Media Queries

Responsive Web Design

Responsive design là kỹ thuật thiết kế web hiển thị tốt trên mọi kích thước màn hình — từ điện thoại nhỏ đến màn hình rộng — bằng cách điều chỉnh layout và nội dung tự động.


Viewport meta tag

Bắt buộc có trong <head> của mọi trang responsive:

<meta name="viewport" content="width=device-width, initial-scale=1">

Không có tag này, trình duyệt di động sẽ thu nhỏ toàn bộ trang.


Mobile-first

Triết lý mobile-first: viết CSS mặc định cho màn hình nhỏ, rồi mở rộng lên màn hình lớn bằng min-width.

/* Mặc định: layout 1 cột (mobile) */
.container { flex-direction: column; }

/* Màn hình >= 768px: 2 cột */
@media (min-width: 768px) {
  .container { flex-direction: row; }
}

Ngược lại là desktop-first — dùng max-width. Ít phổ biến hơn.


Media queries

@media (min-width: 768px) { /* >= 768px */ }
@media (max-width: 767px) { /* <= 767px */ }
@media (min-width: 600px) and (max-width: 900px) { /* khoảng giữa */ }
@media (orientation: landscape) { /* nằm ngang */ }
@media (prefers-color-scheme: dark) { /* dark mode OS */ }

Breakpoints phổ biến

Tên Giá trị Thiết bị
xs < 576px Điện thoại nhỏ
sm ≥ 576px Điện thoại lớn
md ≥ 768px Tablet
lg ≥ 992px Desktop
xl ≥ 1200px Màn hình rộng

Đơn vị tương đối

Đơn vị Tương đối theo
% Kích thước cha
em font-size phần tử cha
rem font-size của <html>
vw 1% chiều rộng viewport
vh 1% chiều cao viewport

Các kỹ thuật responsive cơ bản

/* Container có max-width */
.container { max-width: 1200px; margin: 0 auto; padding: 0 16px; }

/* Ảnh responsive */
img { max-width: 100%; height: auto; }

/* Grid responsive (không cần media query) */
.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 16px; }

clamp() cho fluid typography

/* font-size tối thiểu 1rem, lý tưởng 2.5vw, tối đa 1.5rem */
h1 { font-size: clamp(1rem, 2.5vw, 1.5rem); }

$\text{clamp}(min, val, max)$ — kẹp giá trị trong khoảng $[min, max]$.


Demo: 1 cột → 2 cột khi >= 600px

Kết quả
<div class="page-container">
  <header class="r-header">Header</header>
  <div class="r-body">
    <main class="r-main">
      <h2>Main Content</h2>
      <p>Đây là vùng nội dung chính. Trên mobile hiển thị toàn chiều rộng, trên màn hình lớn hơn sẽ ở bên phải sidebar.</p>
    </main>
    <aside class="r-sidebar">
      <h3>Sidebar</h3>
      <p>Nội dung phụ</p>
    </aside>
  </div>
  <footer class="r-footer">Footer</footer>
</div>
* { box-sizing: border-box; }
body { font-family: sans-serif; margin: 0; padding: 8px; }
h2, h3 { margin: 0 0 .5rem; }

.page-container { max-width: 800px; margin: 0 auto; }

.r-header { background: #4472c4; color: white; padding: 12px 16px; border-radius: 4px; margin-bottom: 8px; font-weight: bold; }
.r-footer { background: #595959; color: white; padding: 10px 16px; border-radius: 4px; margin-top: 8px; text-align: center; }

/* Mobile mặc định: 1 cột dọc */
.r-body { display: flex; flex-direction: column; gap: 8px; }
.r-main    { background: #f0f4ff; padding: 16px; border-radius: 4px; }
.r-sidebar { background: #d4edda; padding: 16px; border-radius: 4px; }

/* >= 600px: 2 cột ngang */
@media (min-width: 600px) {
  .r-body { flex-direction: row; }
  .r-main    { flex: 2; }
  .r-sidebar { flex: 1; }
}

Gợi ý: dùng nút 2 cột hoặc 1 cột, kéo thanh chia ở giữa, rồi kéo mép phải vùng preview để xem layout thay đổi theo nhiều kích thước khác nhau.


Demo: Fluid typography với clamp()

Kết quả
<div class="demo-wrap">
  <h1 class="fluid-h1">Tiêu đề fluid (clamp)</h1>
  <h2 class="fluid-h2">Tiêu đề phụ fluid</h2>
  <p class="fluid-body">Đoạn văn bản body dùng clamp để font tự điều chỉnh theo chiều rộng viewport.</p>
  <code style="display:block;margin-top:1rem;font-size:.8rem">
    h1: clamp(1.5rem, 5vw, 3rem)<br>
    h2: clamp(1.2rem, 3.5vw, 2rem)<br>
    p:  clamp(0.875rem, 1.5vw, 1.125rem)
  </code>

  <div class="fixed-comparison">
    <div>
      <p class="compare-label">Fixed px</p>
      <h2 class="fixed-h2">Tiêu đề cố định 24px</h2>
      <p class="fixed-body">Body cố định 16px — không thay đổi theo viewport</p>
    </div>
    <div>
      <p class="compare-label">Fluid clamp()</p>
      <h2 class="fluid-h2-sm">Tiêu đề fluid</h2>
      <p class="fluid-body-sm">Body fluid — tự điều chỉnh</p>
    </div>
  </div>
</div>
body { font-family: sans-serif; padding: 1rem; margin: 0; }
.demo-wrap { max-width: 100%; }

.fluid-h1   { font-size: clamp(1.5rem, 5vw, 3rem); margin: 0 0 .25rem; color: #4472c4; }
.fluid-h2   { font-size: clamp(1.2rem, 3.5vw, 2rem); margin: 0 0 .25rem; color: #333; }
.fluid-body { font-size: clamp(0.875rem, 1.5vw, 1.125rem); color: #555; margin: 0; }

.fixed-comparison {
  display: flex; gap: 16px; margin-top: 1.5rem;
  background: #f8f8f8; padding: 1rem; border-radius: 6px;
}
.fixed-comparison > div { flex: 1; }
.compare-label { font-size: .7rem; color: #888; text-transform: uppercase; letter-spacing: .05em; margin: 0 0 .25rem; }
.fixed-h2   { font-size: 24px; margin: 0 0 .25rem; }
.fixed-body { font-size: 16px; margin: 0; color: #555; }
.fluid-h2-sm  { font-size: clamp(1rem, 2.5vw, 1.5rem); margin: 0 0 .25rem; color: #4472c4; }
.fluid-body-sm { font-size: clamp(0.8rem, 1.2vw, 1rem); margin: 0; color: #555; }

Bình luận