Gần đây nhiều bạn inbox bảo là series cắt PSD với Leospa phần cuối đâu rồi ? Đang theo dõi hay còn phần nữa thôi mà… Thấy thế nên cố gắng tranh thủ ít thời gian để viết nốt phần cuối này rồi để viết các chuyên đề nâng cao và chuyên sâu khác như JS chẳng hạn…
Ở bài trước chúng ta đã gần như hoàn thiện giao diện rồi, chỉ còn làm cái toggle Menu bằng một chút Javascripts cơ bản để khi nhấn vào nó sẽ show ra menu nhỉ. Như hình dưới đây khi các bạn co màn hình lại ở điện thoại thì sẽ có logo bên trái như mọi khi và một nút hamburger bên phải và menu lúc này đã bị ẩn (đã nói ở các bài trước)
# Vấn đề về BEM
Lúc mình viết bài này thì mình thấy là có 2 cái menu chung class ở Header và Footer nên khi chúng ta CSS dưới mobile chung thì sẽ bị lỗi cả Footer nữa, nên lúc này mình thấy là ở Header có class .header
bao ngoài nên lúc này mình sẽ code có dạng .header .menu
để không ảnh hưởng tới Footer.
Dưới mobile thì mấy bài đầu mình đã ẩn rồi cũng như là có margin-left: 14%
. Xuống mobile thì không còn margin-left
cũng như display: none
nữa. Đồng thời lúc này menu không thể nằm ngang được vì không đủ diện tích như này tất nhiên là sẽ lỗi giao diện thôi
Để khắc phục việc này thì việc đầu tiên chúng ta cần làm là tìm ra giải pháp đó là cho menu nằm hàng dọc và không gây ảnh hưởng tới layout thì để làm việc đó mình sẽ sử dụng position: fixed
nằm cao và rộng khoảng 200px cũng như là sát bên phải ta có code cơ bản lúc này như sau
@media screen and (max-width: 767px) { .header .menu { margin-left: 0; position: fixed; top: 0; right: 0; bottom: 0; z-index: 100; background-color: white; border-left: 1px solid #f2f2f2; min-width: 20rem; } ...other code later }
Kết quả vẫn chưa đẹp cho lắm vì khi dùng fixed như vậy nó sẽ lấp hết màn hình. Cũng như menu chưa nằm dọc để khắc phục việc này mình dùng thêm transform: translateX(100%)
để nó chạy hết vào phía bên phải, khi nào nhấn vào nút hamburger thì nó sẽ chạy ra. Việc thứ 2 là CSS cho cái menu đẹp lại chúng ta có code tiếp theo như sau
.header .menu__list { flex-direction: column; } .header .menu__item { margin: 0; width: 100%; } .header .menu__link { display: block; padding: 1.5rem; border-bottom: 1px solid #f2f2f2; }
Khá là được rồi hen tuy nhiên khi menu hiện ra nó sẽ như trên thì để tắt nó đi thì có 2 trường hợp một là nhấn ra bên ngoài, hai là có một dấu X trên cùng bên phải để nhấn vào thì ẩn menu đi. Để thêm dấu X đó các bạn mở file html lên tìm chỗ này và thêm vào như sau
Đồng thời các bạn CSS cho nó tiếp theo như này
.menu__close{ display: none; } @media screen and (max-width: 767px) { ..code lúc nãy .header .menu__close { position: absolute; right: 1rem; top: 1rem; z-index: 10; cursor: pointer; font-size: 1.4rem; display: block; } }
Nó nằm như vậy thì nhìn cũng tàm tạm rồi. Nhưng không nên như vậy chúng ta cần cho nó thu vào trong như mình đã nói ở trên bằng cách dùng translateX(100%) code hoàn chỉnh lúc này chúng ta sẽ có như sau, 1 điểm là khi mình dùng translateX(100%) cho cái menu thì giao diện bị trống bên phải do nó tràn ra nên lúc này mình CSS thêm cho ở .wrapper
là overflow-x: hidden
để ẩn đi.
.wrapper{overflow-x: hidden;} .menu__close{display:none;} @media screen and (max-width: 767px) { .header .menu { margin-left: 0; position: fixed; top: 0; right: 0; bottom: 0; z-index: 100; background-color: white; border-left: 1px solid #f2f2f2; min-width: 20rem; transition: transform 0.25s linear; will-change: transform; transform: translateX(100%); } .header .menu.is-open { transform: translateX(0); } .header .menu__list { flex-direction: column; } .header .menu__item { margin: 0; width: 100%; } .header .menu__link { display: block; padding: 1.5rem; border-bottom: 1px solid #f2f2f2; } .header .menu__close { position: absolute; right: 1rem; top: 1rem; z-index: 10; cursor: pointer; font-size: 1.4rem; display: block; } }
Một điểm chú ý nữa là mình có thêm cái class .is-open
là khi nó được kích hoạt thì sẽ thêm class này vào với mục đích là thiết lập translateX(0) để cái menu nó chạy ra đó nhé, cũng như thêm chút transition
cho nó mượt mà, và will-change
để trình duyệt biết là thuộc tính nào cần thay đổi, ở đây là transform.
# Javascripts thần thánh
Vậy chúng ta đã xong phần tối ưu UI với CSS thần thánh, tiếp theo đây là chúng ta dùng JS để xử lý việc nhấn vào hiện ra menu. Như ở phần đầu hay phần hai mình có tạo một file là main.js rồi nhỉ và cũng đã chèn vào cuối cùng của file html rồi, giờ các bạn mở lên và code lần lượt như sau
const menuOpen = document.querySelector(".menu__collapse"); const menuClose = document.querySelector(".menu__close"); const headerMenu = document.querySelector(".header .menu");
Mình tạo 3 biến tương ứng là menuOpen cho nút nhấn menu mở ra, menuClose là nhấn vào dấu X và headerMenu là menu mà chúng ta tác động tới để nó chạy ra chạy vô. Lúc này mình viết vài sự kiện nhấn đơn giản đó là
menuOpen.addEventListener("click", function() { headerMenu.classList.add("is-open"); }); menuClose.addEventListener("click", function() { headerMenu.classList.remove("is-open"); });
Khi menuOpen nhấn vào thì mình thêm class is-open
cho headerMenu bằng .classList.add
và tương tự khi mình nhấn vào menuClose thì headerMenu sẽ bỏ class đó ra bằng .classList.remove
thì lúc này khi các bạn nhấn vào cái dấu 3 gạch hay còn gọi là hamburger á thì cái headerMenu nó sẽ thêm class is-open
vào và nó sẽ chạy ra nhờ đoạn code CSS mà chúng ta đã code là .header .menu.is-open{transform: translateX(0)}
Còn một vấn đề cuối là khi người dùng không thích nhấn vào dấu X mà là nhấn ra bên ngoài thì làm sao để ẩn đi. Thì khi nhấn ra bên ngoài tức là nhấn vào document nên ta sẽ có code sự kiện click cho document như sau
document.addEventListener("click", function(event) { if ( !headerMenu.contains(event.target) && // headerMenu không chưa element khi click !event.target.matches(".menu__collapse") // element khi click không phải là menuOpen ) { headerMenu.classList.remove("is-open"); } });
Khi nhấn vào document
thì mình kiểm tra là xem cái headerMenu có chứa cái element(event.target)
không nếu nó không nằm bên trong headerMenu thì headerMenu sẽ bỏ class is-open
đi, tuy nhiên là cái menuOpen nó nằm ngoài headerMenu nên khi nhấn vào menuOpen cũng là document nên nó sẽ không xuất hiện headerMenu ra ngoài cho nên lúc này mình kiểm tra thêm một điều kiện là cái element khi nhấn vào không phải là menuOpen.
Khi thoả mãn hai điều kiện trên thì chúng ta sẽ cho headerMenu bỏ class is-open
đi để nó thu vào lại bên trong.
# Tạm kết
Và như thế là xong tất cả. Mình đã hướng dẫn cho các bạn từ việc phân tích cho đến lúc hoàn thành giao diện Leospa từ những kiến thức cơ bản tới nâng cao, rồi responsive và thêm một chút JS thần thánh để xử lý menu dưới điện thoại… Cuối cùng chúc các bạn một ngày tốt lành và học tập thật tốt và cùng đón chờ những siêu phẩm mới của mình sắp tới nghen. Đừng quên tham khảo code của mình tại đây nhé..
Woao
Anh ơi sao click do home nó không tắt cái menu xuống dậy anh?
Em làm sao, sao a biết được em ơi, với lại em phải có kiến thức về Javascript thì mới hiểu và làm được nhé
Anh ơi anh trả lời câu hỏi của em ở trên đi ạ ?
Nhấn vào home nó là link mà em sao mà tắt được. Sau này đi làm ra sản phẩm thực tế thì nó sẽ bay qua trang web khác hay một liên kết trong trang nà
Thực ra đoạn code js tắt menu kia chỉ giả lập đth trên máy tính mới tắt được, e thử dùng đth ấn ra ngoài nó ko có tắt đi đâu ạ :/ A có thể xem lại ko ạ, hoặc vì e code khác 1 chút ở menu nên nó thế :/
Anh chưa up lên web nên cũng chưa test là trên điện thoại nó như nào. Nếu e làm được thì tốt nà.
@evondev: Anh ơi cho em hỏi với những project lớn thì việc quản lý các file css như thế nào ạ. Kiểu sẽ có nhiều trang khi đó code css sẽ như thế nào và các class dùng như thế nào. Em cảm ơn ạ
Các project lớn khi em đi làm sẽ có team thảo luận nha, nếu dùng sass họ thường dùng 7-1 pattern, còn các framework thì họ có thể dùng sass luôn hoặc các thư viện hỗ trợ như material, ant, hoặc styled components… nhen
Vâng, em cảm ơn anh ạ, anh có thể cho em xin một số dự án mà anh có thể share được để em có thể tham khảo cấu trúc thư mục được không ạ. Hay là anh ra 1 bài về vấn đề này em nghĩ cũng sẽ có khá nhiều bạn quan tậm đó ạ hehee
Cảm ơn anh nhiều ạ
thường a viết dự án toàn là react không ah em.
ui thế thì càng hóng content về kinh nghiệm của anh trong dự án react ạ
React a dùng NextJS ấy, tương lai a sẽ làm khoá học về React nè, hóng nhé em kaka
Hóng mạnh a ơi, cấu trúc code html css thì nhiều nguồn với em nghĩ các bạn cũng đang quen thuộc với code html thuần, giờ được tham khảo những kiến thức mới mà các dự án bây giờ họ hay lựa chọn thì còn gì bằng nữa ạ hehe