Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Lập Trình

Xây dựng thanh điều hướng responsive (Flexbox vs CSS Grid)

Trong hướng dẫn hôm nay, chúng ta sẽ xây dựng thanh điều hướng trên cùng (navbar) với HTML và CSS. Chúng ta sẽ xem hai cách khác nhau: một dùng flexbox, một dùng CSS grid.

Đây là cách tốt để so sánh sự khác biệt giữa hai phương pháp. Bạn có thể xem mình thích cách nào hơn.

Kết quả thanh điều hướng hoàn thành:

Xây dựng thanh điều hướng responsive (Flexbox vs CSS Grid)

Trên desktop, tất cả link cùng hàng, Home bên trái, các link còn lại bên phải.

Xây dựng thanh điều hướng responsive (Flexbox vs CSS Grid)

Trên mobile, Home hàng trên, các link còn lại hàng dưới, và các link căn giữa trang.

Bắt đầu bằng thiết lập file.

Thiết lập file

Để tạo navbar, tạo file index.html và style.scss, compile thành style.css dùng extension VS Code Live Sass.

Trong <head> thêm <link> tải style.css.

Bây giờ bắt đầu xây navbar!

Tạo HTML markup

Trong index.html, tạo markup cho navbar. Tôi dùng thẻ HTML semantic nhiều nhất có thể, tránh dùng div cho mọi thứ.

Tạo element <nav> chứa tất cả link điều hướng. Đặt link trong danh sách không thứ tự <ul> như sau:

<nav> <ul> <li><a href="#">Home</a></li> <li><a href="#">About</a></li> <li><a href="#">Blog</a></li> <li><a href="#">Contact</a></li> </ul> </nav>

Đây là markup navbar cơ bản. Sẽ phải điều chỉnh khi xây flexbox và grid, nhưng bắt đầu bằng cách tạo hai bản sao của element <nav> này.

Load index.html trên trình duyệt, trông khá cơ bản.

Xây dựng thanh điều hướng responsive (Flexbox vs CSS Grid)

Đừng lo! Hãy thêm style vào style.scss.

Thêm global styles và media queries

Trước tiên, thêm một số global styles tôi luôn dùng:

html { font-size: 100%; box-sizing: border-box; } body { margin: 0px; padding: 0px; min-height: 100vh; } *, *::before, *::after { box-sizing: inherit; }

Thêm màu sắc thú vị hơn. Trong <body> đặt background-color: #1b1b1b, và tất cả element cùng link <a> màu trắng color: #ffffff cho theme tối.

Cho <ul> trong <nav>: thêm list-style-type: none ẩn dấu chấm, margin và padding = 0px.

Thêm padding cho <nav> với padding: 10px, tăng padding cho tablet/desktop dùng media query:

nav { padding: 10px; @media (min-width: 600px){ padding: 20px; } }

Trông tốt hơn! Thay font mặc định serif bằng Google Font Open Sans.

Import font family vào style.scss bằng dòng này ở đầu file:

@import url('https://fonts.googleapis.com/css?family=Open+Sans&display=swap'); 

Trong style cho <body>, đặt font-family: 'Open Sans', Arial, Helvetica, sans-serif.

Làm cho style link thú vị hơn.

Bỏ underline mặc định bằng text-decoration: none cho <a>. Thay bằng underline dày màu hồng dùng border-bottom. Tạo gradient underline khi hover từ hồng sang tím.

Dùng biến Sass cho màu. Ở đầu style.scss dưới @import, thêm:

$linkPink: rgb(216, 29, 216); $linkPurple: rgb(98, 16, 250);

Biến giúp đơn giản hóa khi thêm màu vào style khác.

Để tạo underline dày, dùng pseudo-element ::before của <a> làm bottom border.

Code:

a { position: relative; text-decoration: none; } a::before { content: ""; position: absolute; height: 3px; right: 0px; bottom: -3px; left: 0px; background-color: $linkPink; }

Ở đây, ::before cao 3px, nền hồng. Để đặt dưới cùng, set position: absolute và <a> phải position: relative (tránh bay lên trang).

Để pseudo-element nằm dưới chữ, set bottom: -3px tạo khoảng cách. Để đường kéo full width link, dùng left: 0px và right: 0px.

Xây dựng thanh điều hướng responsive (Flexbox vs CSS Grid)

Link trông đẹp hơn!

Hover style gradient

Thêm hiệu ứng hover: underline chuyển gradient hồng-tím, chữ trắng thành hồng khi hover.

Dùng selector a:hover với style:

a:hover { color: $linkPink; &::before { background: linear-gradient(to right, $linkPink 40%, $linkPurple 75%); } }

Cho ::before, background đổi thành linear-gradient. Trong gradient, chuyển từ hồng sang tím khi di chuyển từ trái sang phải.

Kiểm soát vị trí chuyển màu bằng phần trăm. Màu hồng đầu từ 0% (bên trái) đến 40% width. Màu tím thứ hai từ 100% (bên phải) đến 75% width. Giữa 40% và 75% là gradient.

Cũng đổi màu chữ link thành hồng khi hover.

Khi hover link trông như sau:

Xây dựng thanh điều hướng responsive (Flexbox vs CSS Grid)

Đẹp hơn đúng không?

Đã xong global styles dùng cho cả flexbox và grid navbar.

Bây giờ viết style cho navbar flexbox.

Navbar Flexbox

Chia link thành nhóm flex child

Tôi thường viết style desktop trước, rồi mobile. Desktop phức tạp hơn với nhiều cột, mobile thường xếp chồng một cột. Nhưng bạn viết theo thứ tự phù hợp.

Navbar desktop: Home bên trái, ba link phụ cùng nhóm bên phải.

Với flexbox, chia link thành hai nhóm: nhóm trái và nhóm phải. Cả hai là flex child của flex parent.

Quay lại HTML, muốn <nav> là flex parent. Di chuyển link Home ra khỏi <ul> thành child trực tiếp của <nav>. Các link còn lại giữ trong <ul>.

Thêm class "flexbox" cho <nav> tách style flexbox và grid.

Markup cập nhật:

<nav class="flexbox"> <a href="#">Home</a> <ul> <li><a href="#">About</a></li> <li><a href="#">Blog</a></li> <li><a href="#">Contact</a></li> </ul> </nav>

Thêm style flexbox cho desktop

Bật flexbox cho nav.flexbox bằng display: flex. Thêm justify-content: space-between đưa nhóm đầu trái, nhóm sau phải.

Làm <ul> thành flex parent nữa với display: flex và justify-content: flex-end căn link phải. Thêm align-items: center; căn dọc flex child.

Xây dựng thanh điều hướng responsive (Flexbox vs CSS Grid)

Trông tốt hơn!

Ba link phụ cũng cần cạnh nhau flexbox. Làm <ul> flex parent cho ba link, set align-items: center. Thêm khoảng cách link bằng margin-right: 20px nhưng 0px cho :last-child để link cuối không thừa khoảng trống.

Style desktop:

nav.flexbox { display: flex; justify-content: space-between; align-items: center; ul { display: flex; align-items: center; } ul li { margin-right: 20px; &:last-child { margin-right: 0px; } } }

Navbar trông như sau:

Xây dựng thanh điều hướng responsive (Flexbox vs CSS Grid)

Thêm style flexbox cho mobile

Thêm style mobile. Trước hết, căn giữa flex content mobile.

Hiện tại mobile, Home căn trái do justify-content: space-between của flex parent.

Căn giữa bằng cách chuyển rule đó vào media query cho width lớn. Set justify-content là center cho mobile.

Muốn ba link phụ wrap xuống hàng mới, thêm flex-wrap: wrap cho selector nav.flexbox.

Style như sau:

nav.flexbox { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; @media (min-width: 600px){ justify-content: space-between; } }

Để ép wrap, làm flex child <ul> chiếm 100% width, buộc nó xuống dưới Home.

Tôi dùng helper class, thêm class "fullwidth" cho <ul>, tạo rule cho .fullwidth trong nav.flexbox.

Set flex: 1 0 100%. Thuộc tính flex là shorthand cho flex-grow, flex-shrink, flex-basis.

Cho phép grow nếu cần với flex-grow = 1. Không cho shrink với flex-shrink = 0. Width mặc định 100% dùng flex-basis.

Căn giữa link trong flex parent mobile, thêm justify-content: center.

Tuy nhiên, không muốn link phụ fullwidth và căn giữa cho tablet/desktop. Với width lớn, muốn flex là 0 1 auto: không grow, có thể shrink, width mặc định theo nội dung.

Thêm media query desktop:

.fullwidth { flex: 1 0 100%; justify-content: center; @media (min-width: 600px){ flex: 0 1 auto; } }

Có thể dùng media query max-width cho mobile. Nhưng tôi thích dùng style mobile mặc định, rồi thêm min-width media query lớn dần để tránh xung đột.

Tùy bạn dùng loại media query nào, nhưng khuyên dùng một loại (min hoặc max) cho nhất quán.

Cũng cho ba link phụ, muốn set width để chữ "Blog" căn giữa dưới "Home". Hiện tại căn giữa dựa trên tổng width hàng hai. Vì "Contact" dài hơn "About", tâm hàng hai hơi lệch phải so với tâm "Blog".

Xây dựng thanh điều hướng responsive (Flexbox vs CSS Grid)

Sửa bằng cách làm mỗi flex child cột hàng hai cùng width tĩnh 100px. Set flex = 0 0 100px và text-align: center. Chỉ mobile, hủy cho desktop bằng flex: 0 0 auto.

Giảm khoảng cách item mobile 10px, desktop giữ 20px.

Code:

ul li { flex: 0 0 100px; margin-right: 10px; text-align: center; @media (min-width: 600px){ flex: 0 0 auto; margin-right: 20px; } &:last-child { margin-right: 0px; } }

Tweak cuối: thêm khoảng cách giữa Home và ba link phụ bằng margin-bottom mobile. Viết rule target element <a> child trực tiếp của nav.flexbox, chỉ ảnh hưởng Home:

nav.flexbox { > a { margin-bottom: 10px; @media (min-width: 600px){ margin-bottom: 0px; } } }

Navbar mobile với Firefox flexbox inspector bật (xem line cho mỗi cột):

Xây dựng thanh điều hướng responsive (Flexbox vs CSS Grid)

Xong flexbox navbar! Chuyển sang CSS grid.

Phương pháp CSS Grid

Khác biệt chính flexbox và grid: flexbox sắp xếp cột/hàng bằng flex property trên flex child, và flex parent có wrap hay không. Flexbox theo 접근 "content-first".

CSS grid theo 접근 "grid-first". Thiết kế grid template (cột/hàng) dùng grid property trên parent. Kiểm soát riêng vị trí từng grid child trong template.

Nhờ kiểm soát riêng lẻ, navbar CSS grid có thể để tất cả link (kể cả Home) trong cùng parent <ul>.

<nav class="grid"> <ul> <li><a href="#">Home</a></li> <li><a href="#">About</a></li> <li><a href="#">Blog</a></li> <li><a href="#">Contact</a></li> </ul> </nav>

Thêm style grid cho mobile

Thay đổi: viết style mobile trước cho grid navbar!

Mobile: Home hàng đầu, chiếm 100% width. Ba link phụ hàng hai, căn giữa.

Trong <ul> grid parent, bật grid bằng display: grid.

Thiết kế grid template. Vì hàng hai có 3 link, tạo template 3 cột.

Muốn cột cùng width, nhưng không quá rộng. Set grid-template-columns: repeat(3, 100px) cho <ul> grid parent.

Dùng hàm repeat() tạo 3 cột width 100px.

Tính năng hữu ích của grid: tạo gutter (khoảng trống) giữa grid item. Thay vì thêm margin cho grid child như flexbox, chỉ cần set grid-gap: 10px.

Căn giữa toàn bộ grid trên trang với justify-content: center, căn chữ mỗi cột với justify-items: center.

Bật Firefox grid inspector (rất hay, nếu chưa thử hãy dùng), grid trông như sau:

Xây dựng thanh điều hướng responsive (Flexbox vs CSS Grid)

Rõ ràng grid 3 cột căn giữa, nhưng Home cần hàng riêng, chiếm 3 cột width.

Dùng helper class, thêm class "fullwidth" cho <li> Home.

Trong style, selector .fullwidth có rule grid-column: 1 / 4. Grid child cột đó bắt đầu từ grid line dọc thứ 1, kéo đến grid line thứ 4 cuối cùng.

Kết quả, bật số line để thấy đánh số:

Xây dựng thanh điều hướng responsive (Flexbox vs CSS Grid)

Thêm style grid cho desktop

Desktop: tất cả link cùng một hàng. Home trái, ba link còn lại phải.

Cũng muốn 3 cột cuối size theo nội dung, đảm bảo khoảng cách đều nhau.

Tức là cần đổi grid template cho width lớn, dùng media query.

Template đổi thành gì? Muốn 4 link cùng hàng, cần grid 4 cột.

Bước đầu: đổi grid-template-columns từ repeat(3, 100px) thành repeat(4, 100px) cho width > 600px.

Tạo 4 cột, tiếp tục tinh chỉnh.

Cập nhật style .fullwidth chỉ chiếm 1 cột desktop: grid-column: 1 / 2. Cột Home chỉ từ line 1 đến line 2.

Kết quả:

Xây dựng thanh điều hướng responsive (Flexbox vs CSS Grid)

Link 4 cột, nhưng đều 100px nên chỉ căn giữa trang.

Để Home cột đầu toàn bộ bên trái, cần grid chiếm 100% width trang. Làm cột đầu template chiếm phần không gian còn lại.

Đổi grid-template-columns thành 1fr repeat(3, 100px) để 3 cột phụ 100px, cột đầu lấy phần còn lại.

Xây dựng thanh điều hướng responsive (Flexbox vs CSS Grid)

Gần xong! Để 3 cột cuối chỉ rộng bằng nội dung, dùng hàm fit-content(). Set 3 cột cuối fit-content(50px) thì cột tự size theo nội dung.

grid-template-columns desktop thành 1fr repeat(3, fit-content(50px)).

Xây dựng thanh điều hướng responsive (Flexbox vs CSS Grid)

Width cột trông tốt!

Căn chỉnh chữ trong cột. Hiện tại căn giữa do justify-items: center mobile.

Đổi desktop thành justify-items: end căn link phải. Căn Home trái bằng justify-self: start cho .fullwidth.

Navbar grid desktop hoàn thành, khớp flexbox:

Xây dựng thanh điều hướng responsive (Flexbox vs CSS Grid)

Flexbox hay Grid?

Xây navbar này, style flexbox tốn 46 dòng code trong style.scss, HTML markup hơi phức tạp.

Style grid chỉ 24 dòng code! Chênh lệch lớn do flexbox phải thêm margin-bottom và margin-right tạo khoảng cách item. Grid lo hết bằng grid-gap.

Tôi rất thích code nhẹ nhàng của CSS grid. Nhưng flexbox vẫn lựa chọn tốt nếu bạn thoải mái hơn!

Xem source code trên Codepen tại đây.