Bài 11: Responsive Design – Media Query

Ngày nay, mọi người truy cập website từ nhiều thiết bị khác nhau: desktop (1920px), tablet (768px), mobile (375px)… Nếu trang web chỉ tối ưu cho desktop, nó sẽ trông xấu trên điện thoại. Responsive Design là giải pháp — trang web tự động điều chỉnh giao diện tùy theo kích thước màn hình.

Bài này sẽ dạy bạn Media Query — công cụ CSS để tạo responsive design. Bạn sẽ học cách xây dựng trang web hoạt động tốt trên tất cả thiết bị.

Responsive Design là gì?

Responsive Design (RWD) là cách thiết kế trang web để tự động thích ứng với kích thước màn hình của người dùng. Thay vì tạo 3 trang web khác nhau (một cho desktop, một cho tablet, một cho mobile), bạn chỉ tạo một trang web duy nhất nhưng có CSS linh hoạt.

  • 📱 Mobile (≤ 480px): Điện thoại (1 cột, chữ lớn, nút lớn)
  • 📱 Tablet (481px – 768px): Máy tính bảng (2 cột, balance)
  • 💻 Desktop (≥ 769px): Máy tính (3+ cột, layout đầy đủ)

Viewport Meta Tag – Bắt buộc cho responsive

Trước tiên, bạn phải thêm viewport meta tag vào <head> để báo cho trình duyệt rằng trang web là responsive.

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <!-- QUAN TRỌNG: Viewport meta tag -->
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Responsive Website</title>
</head>
<body>
  <!-- Nội dung -->
</body>
</html>
Thuộc tínhÝ nghĩa
width=device-widthChiều rộng = chiều rộng thực của thiết bị
initial-scale=1.0Không zoom mặc định khi tải trang

⚠️ Cảnh báo: Luôn thêm viewport meta tag! Nếu không, trình duyệt sẽ render trang web theo desktop (960px) và thu nhỏ để vừa màn hình mobile — giao diện sẽ bé và khó đọc.

Media Query – Viết CSS cho từng kích thước

Media Query cho phép bạn áp dụng CSS khác nhau dựa trên kích thước viewport.

/* CSS mặc định (cho tất cả kích thước) */
.box {
  width: 100%;
  font-size: 16px;
}

/* Media query: trên desktop (≥ 769px) */
@media (min-width: 769px) {
  .box {
    width: 50%;
    font-size: 18px;
  }
}

/* Media query: trên tablet (481px - 768px) */
@media (min-width: 481px) and (max-width: 768px) {
  .box {
    width: 75%;
    font-size: 16px;
  }
}

/* Media query: trên mobile (≤ 480px) */
@media (max-width: 480px) {
  .box {
    width: 100%;
    font-size: 14px;
  }
}

Cú pháp Media Query

@media (điều kiện) {
  /* CSS áp dụng khi điều kiện đúng */
}

Các điều kiện phổ biến

Điều kiệnÝ nghĩaVí dụ
(min-width: 768px)Chiều rộng ≥ 768px@media (min-width: 768px) { }
(max-width: 767px)Chiều rộng ≤ 767px@media (max-width: 767px) { }
(min-width: 768px) and (max-width: 1024px)Chiều rộng từ 768px đến 1024pxTablet
(orientation: portrait)Chiều dọc (cao hơn rộng)@media (orientation: portrait) { }
(orientation: landscape)Chiều ngang (rộng hơn cao)@media (orientation: landscape) { }

Mobile-First Approach – Bắt đầu từ mobile

Mobile-First là cách tiếp cận hiện đại: viết CSS cho mobile trước, sau đó thêm CSS cho tablet/desktop. Cách này dễ bảo trì hơn.

/* ❌ CÁCH CŨ: Desktop-first (không khuyến khích) */
.container {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;  /* 3 cột (desktop) */
}

@media (max-width: 768px) {
  .container {
    grid-template-columns: 1fr 1fr;  /* 2 cột (tablet) */
  }
}

@media (max-width: 480px) {
  .container {
    grid-template-columns: 1fr;  /* 1 cột (mobile) */
  }
}

/* ✅ CÁCH MỚI: Mobile-first (khuyến khích) */
.container {
  display: grid;
  grid-template-columns: 1fr;  /* 1 cột (mobile) - mặc định */
}

@media (min-width: 481px) {
  .container {
    grid-template-columns: 1fr 1fr;  /* 2 cột (tablet) */
  }
}

@media (min-width: 769px) {
  .container {
    grid-template-columns: 1fr 1fr 1fr;  /* 3 cột (desktop) */
  }
}

💡 Mẹo Mobile-First:

  • Viết CSS cơ bản cho mobile (mặc định)
  • Dùng @media (min-width: ...) để nâng cấp lên tablet/desktop
  • Điều này giảm CSS, tăng hiệu suất trên mobile

Breakpoints tiêu chuẩn

Thiết bịKích thướcBreakpointVí dụ
Mobile320px – 480pxmax-width: 480pxiPhone, Android phone
Tablet481px – 768pxmin-width: 481pxiPad Mini, Samsung Tab
Desktop nhỏ769px – 1024pxmin-width: 769pxLaptop nhỏ, iPad Pro
Desktop lớn≥ 1025pxmin-width: 1025pxDesktop, TV

Ví dụ hoàn chỉnh – Blog responsive

<!DOCTYPE html>
<html lang="vi">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Blog Responsive</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>

  <header class="header">
    <h1>📚 Blog Lập Trình</h1>
  </header>

  <nav class="navbar">
    <a href="#">Trang chủ</a>
    <a href="#">Blog</a>
    <a href="#">Liên hệ</a>
  </nav>

  <div class="container">
    <!-- Main content -->
    <main class="main">
      <article class="post">
        <img src="article1.jpg" alt="Article 1">
        <h2>Bài 1: HTML cơ bản</h2>
        <p>HTML là ngôn ngữ đánh dấu...</p>
        <a href="#" class="btn">Đọc tiếp</a>
      </article>

      <article class="post">
        <img src="article2.jpg" alt="Article 2">
        <h2>Bài 2: CSS cơ bản</h2>
        <p>CSS dùng để trang trí trang web...</p>
        <a href="#" class="btn">Đọc tiếp</a>
      </article>

      <article class="post">
        <img src="article3.jpg" alt="Article 3">
        <h2>Bài 3: JavaScript cơ bản</h2>
        <p>JavaScript thêm tương tác vào trang web...</p>
        <a href="#" class="btn">Đọc tiếp</a>
      </article>
    </main>

    <!-- Sidebar -->
    <aside class="sidebar">
      <h3>Bài viết phổ biến</h3>
      <ul>
        <li><a href="#">HTML là gì?</a></li>
        <li><a href="#">CSS layout</a></li>
        <li><a href="#">JavaScript DOM</a></li>
      </ul>
    </aside>
  </div>

  <footer class="footer">
    <p>© 2024 Blog Lập Trình. Tất cả quyền được bảo lưu.</p>
  </footer>

</body>
</html>
/* FILE: styles.css */

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  font-family: Arial, sans-serif;
  line-height: 1.6;
  color: #333;
  background-color: #f5f5f5;
}

/* Header */
.header {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  padding: 30px 20px;
  text-align: center;
}

.header h1 {
  font-size: 32px;
}

/* Navbar */
.navbar {
  background-color: #2c3e50;
  padding: 15px 20px;
  display: flex;
  gap: 20px;
  flex-wrap: wrap;
}

.navbar a {
  color: white;
  text-decoration: none;
  font-weight: 500;
  transition: color 0.3s;
}

.navbar a:hover {
  color: #3498db;
}

/* Container - MOBILE FIRST */
.container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
  display: grid;
  grid-template-columns: 1fr;  /* 1 cột (mobile) */
  gap: 20px;
}

/* Main content */
.main {
  display: grid;
  grid-template-columns: 1fr;  /* 1 cột (mobile) */
  gap: 20px;
}

.post {
  background: white;
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  transition: transform 0.3s;
}

.post:hover {
  transform: translateY(-5px);
}

.post img {
  width: 100%;
  height: 200px;
  object-fit: cover;
}

.post h2 {
  padding: 20px 20px 10px;
  color: #2c3e50;
  font-size: 20px;
}

.post p {
  padding: 0 20px;
  color: #666;
  font-size: 14px;
}

.btn {
  display: inline-block;
  margin: 15px 20px;
  padding: 10px 20px;
  background-color: #3498db;
  color: white;
  text-decoration: none;
  border-radius: 5px;
  transition: background-color 0.3s;
}

.btn:hover {
  background-color: #2980b9;
}

/* Sidebar */
.sidebar {
  background: white;
  padding: 20px;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  height: fit-content;
}

.sidebar h3 {
  color: #2c3e50;
  margin-bottom: 15px;
}

.sidebar ul {
  list-style: none;
}

.sidebar li {
  margin-bottom: 10px;
}

.sidebar a {
  color: #667eea;
  text-decoration: none;
  transition: color 0.3s;
}

.sidebar a:hover {
  color: #764ba2;
  text-decoration: underline;
}

/* Footer */
.footer {
  background-color: #2c3e50;
  color: white;
  text-align: center;
  padding: 20px;
  margin-top: 40px;
}

/* ========== TABLET (481px - 768px) ========== */
@media (min-width: 481px) {
  .header h1 {
    font-size: 36px;
  }

  .main {
    grid-template-columns: 1fr 1fr;  /* 2 cột */
  }

  .post:nth-child(3) {
    grid-column: 1 / -1;  /* Item 3 chiếm 2 cột */
    max-width: 50%;
  }
}

/* ========== DESKTOP NHỎ (769px - 1024px) ========== */
@media (min-width: 769px) {
  .container {
    grid-template-columns: 1fr 300px;  /* Main + Sidebar */
  }

  .main {
    grid-template-columns: 1fr 1fr;  /* 2 cột */
  }

  .post {
    display: flex;
    flex-direction: column;
  }

  .post img {
    height: 250px;
  }

  .navbar {
    gap: 40px;
  }
}

/* ========== DESKTOP LỚN (≥ 1025px) ========== */
@media (min-width: 1025px) {
  .header h1 {
    font-size: 48px;
  }

  .main {
    grid-template-columns: 1fr 1fr 1fr;  /* 3 cột */
  }

  .post img {
    height: 300px;
  }

  .navbar {
    gap: 60px;
    padding: 15px 40px;
  }

  .container {
    padding: 40px;
  }
}

Các kỹ thuật responsive khác

1. Flexible Images (Hình ảnh linh hoạt)

/* Hình ảnh tự điều chỉnh kích thước */
img {
  max-width: 100%;
  height: auto;
  display: block;
}

2. Flexible Typography (Chữ linh hoạt)

/* Kích thước chữ điều chỉnh theo viewport */
h1 {
  font-size: 24px;  /* Mobile */
}

@media (min-width: 769px) {
  h1 {
    font-size: 36px;  /* Desktop */
  }
}

/* Hoặc dùng vw (viewport width) */
h1 {
  font-size: clamp(24px, 5vw, 48px);  /* Min, preferred, max */
}

3. Hidden Elements (Ẩn phần tử)

/* Ẩn sidebar trên mobile */
.sidebar {
  display: block;  /* Mặc định: ẩn hoặc hiển thị */
}

@media (max-width: 768px) {
  .sidebar {
    display: none;  /* Ẩn trên tablet/mobile */
  }
}

Testing Responsive – Kiểm tra trên các kích thước

Cách test responsive của bạn:

  1. DevTools: F12 → Device Toolbar (Ctrl+Shift+M)
  2. Online Tools: responsivedesignchecker.com, browserstack.com
  3. Thiết bị thực: Mở trang trên điện thoại, tablet, desktop

💡 Mẹo testing:

  • Test tại các breakpoint chính: 375px, 768px, 1024px, 1920px
  • Test cả portrait (dọc) và landscape (ngang)
  • Test ở các trình duyệt khác nhau (Chrome, Firefox, Safari…)

Tóm tắt

  • Responsive Design: Trang web tự điều chỉnh trên mọi kích thước
  • Viewport meta tag: Bắt buộc để responsive hoạt động
  • Media Query: @media (điều kiện) { CSS }
  • Mobile-first: Viết CSS cho mobile trước, sau đó nâng cấp lên tablet/desktop
  • Breakpoints: 480px (mobile), 768px (tablet), 1024px (desktop), 1920px (large)
  • min-width vs max-width: min-width cho mobile-first, max-width cho desktop-first
  • Flexible images: max-width: 100%; height: auto;
  • Flexible layout: Dùng Flexbox, Grid, %
  • Test responsive: DevTools, online tools, thiết bị thực

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

Bài tập 1: Chuyển đổi một trang web cũ sang responsive:

  • Thêm viewport meta tag vào head
  • Viết lại CSS dùng mobile-first approach
  • Breakpoints: 480px, 768px, 1024px
  • Test trên DevTools (mobile, tablet, desktop)

Bài tập 2: Tạo portfolio responsive:

  • Mobile: 1 cột (tên, ảnh, các skill, portfolio items xếp dọc)
  • Tablet: 2 cột (thông tin trái, portfolio items phải)
  • Desktop: 3 cột (sidebar trái, main giữa, extra phải)
  • Hình ảnh responsive (max-width: 100%)
  • Navigation hamburger menu trên mobile (chỉ HTML/CSS, no JS)

Bài tập 3: Tạo e-commerce product grid responsive:

  • Mobile: 1 cột sản phẩm
  • Tablet: 2 cột sản phẩm
  • Desktop: 4 cột sản phẩm
  • Mỗi sản phẩm: ảnh, tên, giá, nút mua
  • Sidebar filter ẩn trên mobile, hiện trên tablet+
  • Responsive font sizes

Chúc bạn thành công! 🚀

Để lại bình luận

Email của bạn sẽ không được hiển thị.