12/08/2018, 16:56

Hướng dẫn tạo một responsive navbar với Flexbox

Bài viết đc dịch từ nguồn: https://medium.freecodecamp.org/how-to-create-a-fully-responsive-navbar-with-flexbox-a4435d175dd3 Trong bài viết này, mình sẽ hướng dẫn tạo một navbar tương thích với nhiều kích cỡ màn hình khác nhau bằng cách sử dụng Flexbox và media queries. Setup Bắt đầu ...

Bài viết đc dịch từ nguồn: https://medium.freecodecamp.org/how-to-create-a-fully-responsive-navbar-with-flexbox-a4435d175dd3

Trong bài viết này, mình sẽ hướng dẫn tạo một navbar tương thích với nhiều kích cỡ màn hình khác nhau bằng cách sử dụng Flexbox và media queries.

Setup

Bắt đầu markup cho một navbar đơn giản nào:

<nav>
  <ul class="container">
    <li>Home</li>
    <li>Profile</li>
    <li class="search">
      <input type="text" class="search-input" placeholder="Search">
    </li>
    <li>Logout</li>
  </ul>
</nav>
<ul> element là flex container và những <li> element là flex item. Để biến nó thành flexbox layout, chúng ta làm tiếp:
.container {
  display: flex;
}

Và sẽ đc kết quả sau:

Như bạn thấy, chúng ta còn thừa một ít khoảng trống ở phía bên phải. Đó là vì Flexbox đặt item từ bên trái sang bên phải, và mỗi item chỉ rộng bằng đúng content của nó thôi. Do mặc định, flex container là một block level element ( và nó rộng hơn cả 4 item), chúng ta có một khoảng trống ở cuối. Lý do mà ô search lại rộng hơn các item khác là do mặc định các input field đc set size là 20, và mỗi browser, mỗi hệ điều hành lại interpret nó theo một cách khác nhau.

Responsiveness #1

Để navbar của chúng ta có một mức responsiveness căn bản, chúng ta chỉ đơn giản là cho search item một flex value bằng 1

.search {
  flex: 1;
}

Điều này đồng nghĩa với việc search item sẽ phình ra hoặc co lại theo chiều rộng của container, chúng ta sẽ ko còn khoảng trống thừa ở phía bên phải nữa.

Để search item co giãn trong khi các item khác cố định thì cũng ok, tuy nhiên nó có thể trở lên quá to so với các item khác. Do vậy nếu bạn muốn tất cả các item đều co giãn theo chiều rộng của container, bạn chỉ cần đơn giản là set tất cả item có flex value là 1.

.container > li {
  flex: 1;
}

Nó sẽ thành ra như này:

Bạn cũng có thể set flex value khác cho các items, điều đó sẽ khiến chúng co giãn theo tốc độ khác nhau.

Responsiveness #2

Navbar của chúng ta hoạt động tốt ở màn hình rộng, tuy nhiên, khi ta co màn hình lại thì vấn đề bắt đầu phát sinh:

Đến một mức nào đó thì để tất cả các item ở cùng một hàng là bất khả thi, vì container đã trở lên quá hẹp. Để giải quyết vấn đề này, chúng ta sử dụng media query, tách 4 item thành 2 hàng. Media query này sẽ kích hoạt khi màn hình rộng 600px

@media all and (max-awidth: 600px) {
  
  .container {
    flex-wrap: wrap;
  }
  
  .container > li {
    flex-basis: 50%;
  }
}

Đầu tiên, chúng ta cho phép Flexbox layout có thể wrap với flex-wrap. Mặc định thì nó là nowrap, do đó ta chuyển sang thành wrap. Tiếp theo, chúng ta set flex-basis của các item thành 50%. Điều này đồng nghĩa với việc Flexbox cho phép mỗi item lấy 50% chiều rộng hiện có, kết quả cho ra là 2 item mỗi hàng, như sau:

Giờ ta đã có 2 trạng thái khác nhau của layout. Tuy nhiên, layout này vẫn ko hoạt động với màn hình rất nhỏ, như là portrait mode của mobile. Nếu ta tiếp tục thu nhỏ màn hình, ta sẽ đc kết quả như sau:

Vấn đề xảy ra là hàng thứ 2 ko thể chứa vừa 2 item nữa. Logout item và search item quá rộng, và bạn ko thể thu nhỏ chúng nhỏ hơn mức minimum awidth, mức mà chúng cần để hiển thị nội dung bên trong. Home item và profile item vẫn có thể ở chung hàng đầu tiên, và Flexbox cho phép chúng làm vậy. Điều này là ko tối ưu, vì chúng ta muốn tất cả các hàng phải cư xử giống nhau.

Responsiveness #3

Ngay khi mà một row ko thể chứa đc 2 item, chúng ta sẽ làm cho tất cả các row ko thể chứa đc 2 item. Nói cách khác, ở màn hình rất nhỏ, chúng ta sẽ làm navbar theo chiều dọc. Chúng ta sẽ xếp các item từ trên xuống dưới. Để làm đc việc này, chúng ta chỉ đơn giản là đổi cái 50% awidth thành 100% awidth, do đó mỗi hàng chỉ chứa đc 1 item. Chúng ta sẽ để mức chuyển là 400px

@media all and (max-awidth: 400px) {
  .container > li {
    flex-basis: 100%;
  }
  .search {
    order: 1;
  }
}

Kết quả là:

0