Bài 15. Thiết kế responsive: media query và container query

Giao diện phải đẹp trên điện thoại, máy tính bảng và màn hình lớn. Bài này dạy tư duy mobile-first, viết media query theo breakpoint, container query để thành phần tự thích ứng theo khung chứa, và các media feature như chế độ tối, giảm chuyển động.

55 phútTrung cấp
Bạn sẽ học được
  • Áp dụng mobile-first với min-width
  • Chọn breakpoint hợp lý
  • Dùng container query cho thành phần
  • Dùng prefers-color-scheme, prefers-reduced-motion, hover
Thuật ngữ cần biết
Breakpoint
Mốc chiều rộng đổi bố cục.
Mobile-first
Viết CSS cho màn hình nhỏ trước, mở rộng dần.
Container query
Điều kiện theo kích thước phần tử chứa thay vì màn hình.

Một số khái niệm

Điều kiện tiên quyết: thẻ <meta name="viewport" content="width=device-width, initial-scale=1">. Sau đó, viết CSS mặc định cho điện thoại (bố cục 1 cột), rồi dùng @media (min-width: ...) thêm cột khi màn hình rộng hơn. Cách này giữ CSS cho điện thoại nhẹ và đơn giản.

Breakpoint gợi ýThiết bị
< 576pxĐiện thoại dọc (mặc định)
≥ 576pxĐiện thoại ngang
≥ 768pxMáy tính bảng
≥ 992pxLaptop
≥ 1200pxMàn hình lớn

Đừng chọn breakpoint theo từng thiết bị cụ thể; hãy thu nhỏ trình duyệt và thêm breakpoint ở chỗ giao diện bắt đầu vỡ.

Media query mobile-first

<style>
  .ds { display: grid; gap: 8px; grid-template-columns: 1fr; }
  .ds div { background: #e3f2fd; padding: 14px; border-radius: 8px; text-align: center; }
  @media (min-width: 420px) { .ds { grid-template-columns: repeat(2, 1fr); } }
  @media (min-width: 640px) { .ds { grid-template-columns: repeat(4, 1fr); } .ds div { background: #e8f5e9; } }
  @media (orientation: landscape) and (max-height: 400px) { .ds div { padding: 6px; } }
</style>
<div class="ds"><div>1</div><div>2</div><div>3</div><div>4</div></div>
<p style="font-size:13px;color:#666">Thu nhỏ cửa sổ trình duyệt: 4 → 2 → 1 cột.</p>
Kết quả hiển thị
/* Cú pháp khoảng (range syntax) mới, dễ đọc */
@media (480px <= width < 992px) { ... }

Container query

<style>
  .vo { container-type: inline-size; border: 2px dashed #90a4ae; padding: 8px; margin-bottom: 8px; border-radius: 8px; }
  .the { display: grid; gap: 10px; background: #fff; }
  .the .anh { aspect-ratio: 16/9; background: #90a4ae; border-radius: 6px; }
  @container (min-width: 380px) { .the { grid-template-columns: 140px 1fr; } .the .anh { aspect-ratio: 1; } }
</style>
<div class="vo" style="width:300px"><div class="the"><div class="anh"></div><div><b>Thẻ trong cột hẹp</b><br>Ảnh nằm trên</div></div></div>
<div class="vo"><div class="the"><div class="anh"></div><div><b>Thẻ trong cột rộng</b><br>Ảnh tự chuyển sang trái</div></div></div>
Kết quả hiển thị

Cùng một thẻ, đặt vào cột hẹp (sidebar) hay cột rộng (nội dung chính) tự đổi bố cục theo khung chứa, không phụ thuộc màn hình. Đây là cách xây thành phần tái sử dụng hiện đại.

Media feature về người dùng

/* Chế độ tối theo hệ điều hành */
@media (prefers-color-scheme: dark) {
  :root { --nen: #121212; --chu: #e0e0e0; }
}
/* Người dùng bật giảm chuyển động */
@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; scroll-behavior: auto !important; }
}
/* Chỉ áp dụng hiệu ứng hover cho thiết bị có chuột */
@media (hover: hover) and (pointer: fine) {
  .the:hover { transform: translateY(-4px); }
}
/* Khi in */
@media print { nav, footer, .quang-cao { display: none; } a::after { content: " (" attr(href) ")"; } }
Mẹo hay

Ảnh responsive: img { max-width: 100%; height: auto; } và dùng thuộc tính srcset, sizes để trình duyệt tải ảnh vừa kích thước màn hình (xem HTML - Hình ảnh).

Lưu ý

Kiểm thử trên điện thoại thật, không chỉ chế độ thiết bị của DevTools: font, thanh địa chỉ, vùng chạm ngón tay (tối thiểu 44×44px) khác biệt đáng kể.

Thực hành
  1. Chuyển một trang 3 cột sang mobile-first: 1 → 2 → 3 cột.
  2. Làm thanh menu: điện thoại hiện nút ☰, máy tính hiện đủ mục.
  3. Tạo thẻ sản phẩm dùng container query.
  4. Thêm chế độ tối theo prefers-color-scheme bằng biến CSS.
Tóm tắt bài học
  • viewport + mobile-first + min-width.
  • Breakpoint theo nơi giao diện vỡ.
  • @container cho thành phần tự thích ứng.
  • prefers-color-scheme, prefers-reduced-motion, hover, print.