Responsive giao diện cực đỉnh với Container Queries 🤯

Đối với Frontend Developer thì việc tối ưu giao diện Responsive là điều hiển nhiên rồi. Và chúng ta thông thường từ trước đến giờ là dùng Media Queries để làm việc đó. Đối với font-size thì mình đã giới thiệu cho các bạn cách làm ở bài viết sử dụng hàm clamp trong CSS rồi.

Vậy thì còn cách nào khác để làm Responsive cho giao diện mà không hoặc ít dùng tới Media Queries không ? Tất nhiên là có rồi, và mình rất háo hức giới thiệu cho các bạn ngay sau đây Container Queries.

Đầu tiên chúng ta phải hiểu rằng khi sử dụng MQ(Media queries) thì chúng ta sẽ dựa vào Viewport của màn hình sẽ có các breakpoints như 1024, 1280, 768…. Tuy nhiên khi sử dụng CQ(Container Queries) thì sẽ dựa vào độ rộng của Container. Container là gì thì mình sẽ ví dụ cho các bạn sau đây

Giao diện ở trên là Sidebar ở phía bên trái, còn bên phải là Main, trong Main chứa Card với cấu trúc HTML và CSS như sau

<div class="wrapper">
      <div class="sidebar"></div>
      <div class="main">
        <div class="card">
          <div class="card-image">
            <img
              src="https://images.unsplash.com/"
              alt=""
            />
          </div>
          <div class="card-content">
            <p class="card-city">New York</p>
            <h3 class="card-title">
              New York City’s air pollution among the world’s worst as Canada wildfire smoke shrouds Northeast
            </h3>
          </div>
        </div>
      </div>
    </div>
.wrapper {
  display: grid;
  grid-template-columns: 250px minmax(0, 1fr);
  grid-gap: 20px;
  height: 100vh;
}
.sidebar {
  border-right: 1px solid #eee;
}
.main {
  padding: 20px;
}
.card {
  display: flex;
  gap: 20px;
}
.card-image {
  overflow: hidden;
  width: 100%;
  flex: 0 0 200px;
}
.card-image img {
  border-radius: 12px;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.card-content {
  padding: 20px 0;
  flex: 1;
}
.card-city {
  font-size: 14px;
  margin-bottom: 10px;
  color: #333;
}
.card-title {
  font-size: 18px;
  font-weight: bold;
  line-height: 1.5;
}

Khi ở màn hình tầm < 900px thì giao diện sẽ hiển thị như sau

Các bạn sẽ thấy một vấn đề là .card giao diện hiển thị như vầy nó không ổn một chút nào cả. Vì có thể kết quả mà chúng ta muốn là như dưới đây. Nếu vậy thì có thể chúng ta sẽ dùng MQ cho màn hình < 900px thay đổi flex-direction: column là xong xuôi.

/* Media queries */
@media screen and (max-width: 900px) {
  .card {
    flex-direction: column;
  }
}

Tuy nhiên chúng ta sẽ gặp một vấn đề nữa là khi màn hình < 800px thì Sidebar đã bị ẩn cho nên thằng Main sẽ tràn ra chiếm hết diện tích và lúc này thằng .card nó bị như dưới thì lại xấu quá, đáng lẽ nó nên nằm ngang như ở màn hình máy tính thì có lẽ sẽ đẹp hơn.

/* Media queries */
@media screen and (max-width: 800px) {
  .sidebar {
    display: none;
  }
  .wrapper {
    display: block;
  }
  .card {
    flex-direction: row;
  }
}

Để giải quyết nó thì chúng ta lại phải code thêm MQ cho một màn hình < 800px cho nó flex-direction: row lại, rồi khi màn hình < 480px thì lại thiết lập flex-direction: column lại nữa. Đọc thôi là thấy code rất chi là nhiều và rối rồi đó 🤯

@media screen and (max-width: 480px) {
  .card {
    flex-direction: column;
  }
}

Dùng MQ phức tạp quá, nhưng không sao, Container Queries đến để giải cứu vấn đề này. Để sử dụng CQ, thì chúng ta sẽ code vào phần tử bao ngoài chứa phần tử bên trong mà chúng ta muốn xử lý giao diện. Đối với cấu trúc HTML ở trên thì thằng chúng ta muốn xử lý giao diện là .card, và phần tử bao ngoài của nó(trong trường hợp này) là .main

Lưu ý: Phần tử sử dụng Container Queries không nhất thiết phải là thằng gần nhất, tùy thuộc vào logic của giao diện.

/* container queries */
.main {
  container-name: card;
  container-type: inline-size;
}
@container card (max-width: 500px) {
  .card {
    flex-direction: column;
  }
}

Như các bạn thấy đoạn code ở trên thì để sử dụng CQ, ở class .main mình sử dụng đoạn container-name: cardcontainer-type: inline-size. Container name là không bắt buộc, tuy nhiên mình khuyến khích các bạn đặt tên cho dễ nhận biết nhé

Để sử dụng thì các bạn viết như này, nhớ thay ContainerName thành tên nào tùy vào logic của các bạn nha.

.some-class{
  container-name: ContainerName;
  container-type: inline-size;
}
@container ContainerName (min or max width, height){
  // code
}

Các bạn có thể xem trực tiếp kết quả của ví dụ từ nãy đến giờ dưới này hoặc nhấn vào đây để xem toàn trang nhé.

Lưu ý: Phần tử sử dụng Container Queries thì không áp dụng @container vào chính nó được, mà chỉ áp dụng vào phần tử con của nó như mình đã làm ví dụ ở trên. Một ví dụ sai ở dưới đây cho các bạn biết mà tránh.

.main {
  container-name: card;
  container-type: inline-size;
}
@container card (max-width: 500px) {
  .main {
    flex-direction: column;
  }
}

Hi vọng thông qua kiến thức mới này sẽ giúp các bạn sẽ có thêm cách về việc xử lý giao diện Responsive một cách xịn xò hơn. Ngoài ra các bạn có thể nhấn vào đây để tham khảo thêm nhiều giao diện có sử dụng Container Queries cực xịn xò của tác giả IShadeed. Cuối cùng mấu chốt để hiểu và làm tốt đó chính là thực hành nhiều vào các bạn nhé.

Subscribe
Notify of
guest

3 Comments
Inline Feedbacks
View all comments
bean
bean

bài viết hay

Hường
Hường

anh cho em hỏi sao em thiết lập @media queries là ( max-width: 1279.98) cho phần sidebar biến mất khi trình duyệt <= 1279.98px , nhưng nếu em đẻ kích thước tình duyệt là 90% trở xuống thì không sao , còn khi để kích thước lên 100% thì lại bị lỗi vậy ạ , để 100% thì đoạn code trong media <= 1279.98 vẫn được thực thi