Hướng dẫn cắt PSD toàn tập với Leospa design phần cuối

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.

# CSS cho menu dưới mobile

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 ở .wrapperoverflow-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 XheaderMenu 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é..

Subscribe
Notify of
guest

14 Comments
Inline Feedbacks
View all comments
Huy
Huy

Woao

Long
Long

Anh ơi sao click do home nó không tắt cái menu xuống dậy anh?

Long
Long

Anh ơi anh trả lời câu hỏi của em ở trên đi ạ ?

Nhân
Nhâ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ế :/

Hulkk
Hulkk

@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 ạ

Hulkk
Hulkk
Reply to  evondev

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 ạ

Hulkk
Hulkk
Reply to  evondev

ui thế thì càng hóng content về kinh nghiệm của anh trong dự án react ạ

Hulkk
Hulkk
Reply to  evondev

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