Hướng dẫn cắt PSD sang HTML toàn tập phần 4

hướng dẫn cắt psd sang html cho người mới bắt đầu

Mấy nay lại có hứng khởi viết tiếp bài cho serie hướng dẫn cắt PSD sang HTML toàn tập với mục đích hoàn thành serie trong tháng 12 cuối năm này cũng như giúp các bạn mới hiểu biết được quy trình cắt PSD sang HTML nó như thế nào để từ đó có thể học và cải thiện kiến thức – trình độ hơn.

Ở bài trước chúng ta đã làm Block Feature với layout khá phức tạp tuy nhiên với việc phân tích kỹ càng thì chúng ta đã hoàn thành nó một cách trơn tru. Hôm nay chúng ta sẽ tiếp tục làm các block còn lại của Design đó là Block Tweet và Block Images Shop.

# Block Tweet

hướng dẫn cắt psd dành cho newbie

Nhìn vào Block Tweet thì hiểu ngay đó là Slider dạng hiển thị các tweet của các tác giả. Tuy nhiên trong phạm vi serie này mình chỉ hướng dẫn cắt PSD sang HTML CSS mà thôi nên mình sẽ code như một block bình thường chứ không dùng Javascripts hay thư viện Slider gì ở đây cả.

Cấu trúc của nó khá đơn giản như Block Feature Header ở phần trước. Có màu nền là màu xám lợt, một icon twitter(dùng font-awesome), một thẻ tiêu đề, một đoạn chữ và cuối cùng là phân trang. Từ đây ta có cấu trúc HTML như sau

<div class="tweet">
  <i class="fab fa-twitter tweet__icon"></i>
  <h2 class="tweet__heading">
    <span class="tweet__location">AOD New York</span>
    <span class="tweet__author">@aod</span>
    <time class="tweet__time">35min</time>
  </h2>
  <p class="tweet__content">Lorem ipsum... </p>
  <ul class="tweet__pagi">
    <li class="tweet__pagi-item is-active"></li>
    <li class="tweet__pagi-item"></li>
    <li class="tweet__pagi-item"></li>
  </ul>
</div>

Trong thẻ h2 có class tweet__heading mình thấy có ba phần nhỏ đó là địa chỉ, tác giả và thời gian cho nên mình chia ra các thẻ spantime để code cho chuẩn.

.tweet {
  padding: 12.5rem 1.5rem 7rem;
  background-color: var(--bg-light);
  text-align: center;
}
.tweet__icon {
  font-size: 4rem;
  color: #00aefd;
  margin-bottom: 3rem;
}
.tweet__heading {
  font-size: 1.8rem;
  margin-bottom: 2rem;
}
.tweet__location,
.tweet__author {
  color: var(--heading);
  font-weight: bold;
}
.tweet__time {
  color: var(--text);
  font-weight: 300;
  padding-left: 1.5rem;
  margin-left: 1.5rem;
  position: relative;
}

Các bạn để ý ở mũi tên trên hình chỗ thời gian có dấu “/” cách ra một đoạn. Các bạn có thể gõ khoảng trắng rộng ra hoặc có thể dùng :before hay :after đều được. Nếu dùng :before hay :after thì các bạn có thể code như sau

.tweet__time:before {
  content: "/";
  position: absolute;
  left: 0;
  top: 0;
}

Đoạn chữ thì không có gì ngoài kiểu chữ in nghiêng và độ rộng tối đa là 104.5rem. Còn ở phân trang tweet__pagi mình dùng cấu trúc ul li và trong hình thì mình thấy hình tròn đầu tiên nó có màu nền cho nên mình hiểu là nó active nên mình thêm một class is-active vào nó

.tweet__content{
  font-size: 2.4rem;
  line-height: 1.4;
  color: var(--text);
  font-style: italic;
  max-width: 104.5rem;
  margin: 0 auto 10rem;
}
.tweet__pagi {
  display: flex;
  align-items: center;
  justify-content: center;
}
.tweet__pagi-item {
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 5rem;
  border: 1px solid var(--text);
  margin-left: .5rem;
  margin-right: .5rem;
}
.tweet__pagi-item.is-active {
  background-color: var(--text);
}

Thế là xong block Tweet. Các bạn lưu ý là các thông số mình lấy từ Design ra bằng Photoshop. Cái này các bạn nên tự làm nhá chớ mình không chỉ cách lấy như thế nào nữa nhé. Giờ chúng ta sẽ tiếp tục đến block Images Shop dưới đây.

# Block Images Shop

hướng dẫn cắt psd cho người mới bắt đầu

Cấu trúc của block này khá là phức tạp nhưng nhìn kỹ thì ta có thể chia layout thành ba phần bằng nhau. Phần một và phần ba giống nhau nhưng ngược hướng ta có thể dùng CSS Flexbox với thuộc tính order hoặc flex-direction: column-reverse. Còn phần hai thì quá đơn giản chỉ chia thành hai cột bằng nhau mà thôi.

Trong từng phần tử bên trong block Images Shop mình có kẻ đường line màu xanh cho các bạn dễ nhìn thấy có một hình nền và một hình logo kèm chữ “Shop now” khi rê chuột vào nó mới hiện ra kèm theo đó là một lớp nền phủ trên màu xanh lá mờ. Hiệu ứng này chúng ta sẽ làm sau.

Cái quan trọng ở đây chính là cấu trúc HTML  sao cho hợp lý có thể tái sử dụng, không dư thừa nhiều. Thì mình sẽ phân tích cho các bạn như sau.

Đầu tiên là cấu trúc HTML chung cho từng phần tử trong block Images Shop mình gọi là images__item nhé. Trong phần tử này ta có một tấm hình nền mình đặt class là images__item-bg và một tấm hình logo kèm chữ “Shop now” mình đặt chung trong một div có class là images__item-brand

Từ đây ta có HTML cho nó như sau

<div class="images__item">
  <img src="images/img10.jpg" alt="" class="images__item-bg">
  <div class="images__item-brand">
    <img src="images/img-bicycle-sm.png" alt="">
    <h3 class="images__item-text">Shop now</h3>
  </div>
</div>

Bây giờ đến phân tích cấu trúc HTML tổng thể cho block Images Shop. Như đã nói ở trên chúng ta sẽ chia thành ba phần bằng nhau cho nên ở đây mình sẽ dùng thẻ ul li để dễ dàng dùng Selectors trong CSS để tùy chỉnh. Mình tạo cấu trúc HTML  đơn giản và CSS như sau

<ul class="images">
  <li class="images__block"></li>
  <li class="images__block"></li>
  <li class="images__block"></li>
</ul>
.images {
  display: flex;
  justify-content: space-between;
  height: 53.5rem;
  overflow: hidden;
}
.images__block {
  width: 33.333%;
  height: 100%;
  display: flex;
}

Mình đo từ Design trong Photoshop thì thấy block Images Shop này có chiều cao tối đa là 535px(53.5rem) cho nên mình set cứng cho nó luôn. Sau đó mình dùng CSS Flexbox để tạo layout và cho các images__block cao 100% và rộng bằng nhau 33.333%.

Và mình thấy các images__block đều sẽ dùng CSS Flexbox cho nên mình set thêm thuộc tính display: flex vào luôn ở trên. Thế là xong cấu trúc tổng thể. Bây giờ chúng ta sẽ đi vào chi tiết từng phần một nhé.

# Block images số 1

hướng dẫn cắt psd dễ dàng

Ở đây mình thấy nó chia ra thành hai phần trên và dưới. Phần trên có hai phần tử hình ảnh(images__item) mỗi cái chiếm một nửa còn phần dưới thì chỉ có một phần tử hình ảnh chiếm full hết. Ta sẽ có HTML như sau

<li class="images__block">
  <div class="images__block-item">
    <div class="images__item">
      <img src="images/img10.jpg" alt="" class="images__item-bg">
      <div class="images__item-brand">
        <img src="images/img-bicycle-sm.png" alt="">
        <h3 class="images__item-text">Shop now</h3>
      </div>
    </div>
    <div class="images__item">
      <img src="images/img11.jpg" alt="" class="images__item-bg">
      <div class="images__item-brand">
        <img src="images/img-bicycle-sm.png" alt="">
        <h3 class="images__item-text">Shop now</h3>
      </div>
    </div>
  </div>
  <div class="images__block-item">
     <div class="images__item">
      <img src="images/img12.jpg" alt="" class="images__item-bg">
      <div class="images__item-brand">
        <img src="images/img-bicycle-sm.png" alt="">
        <h3 class="images__item-text">Shop now</h3>
      </div>
    </div>
  </div>
</li>

Đoạn images__item mình đã có phân tích trước ở phần cấu trúc HTML chung rồi nhé. Ở block số 1 này mình thấy nó hiển thị dạng cột cho nên mình sẽ dùng CSS Flexbox với flex-direction: column và tạo hai class images__block-item để chia ra một phần trên và một phần dưới . Tạm thời mình có CSS như sau

.images__block:first-child {
  flex-direction: column;
}
.images__block-item {
  height: 50%;
  width: 100%;
}

Sau đó mình thấy ở phần trên có hai cột bằng nhau cho nên mình lại dùng CSS Flexbox và đồng thời mình cho toàn bộ các images__item có chiều cao 100% và độ rộng là 50% luôn. Để chọn phần tử đầu tiên mà không phải dạng danh sách như ul li hay ol li mà dạng div div thì mình dùng :first-of-type ta có

.images__block-item:first-of-type {
  display: flex;
}
.images__item {
  width: 50%;
  height: 100%;
}

Vì mình set toàn bộ images__item có độ rộng là 50% nên phần tử hình ảnh ở phần dưới chắc chắn sẽ ảnh hưởng vì dùng chung class cho nên mình phải style cho nó ra 100% và để chọn phần tử thứ hai(trường hợp ở đây là cuối cùng) mà không phải dạng danh sách thì ta dùng :last-of-type

.images__block-item:last-of-type .images__item {
  width: 100%;
}

Như vậy là xong block images số 1. Tiếp theo dưới đây sẽ là block images số 2, các bạn tiếp tục theo dõi nà.

# Block images số 2

hướng dẫn cắt psd từ a tới z

Ở block này rất đơn giản chúng ta chỉ cần có hai images__item mà thôi rồi thay các đường dẫn hình ảnh là xong vì CSS chúng ta làm ở trên đã đảm nhiệm luôn cho block này luôn rồi nên chỉ cần HTML như này là xong.

<li class="images__block">
  <div class="images__item">
      <img src="images/img13.jpg" alt="" class="images__item-bg">
      <div class="images__item-brand">
        <img src="images/img-bicycle-sm.png" alt="">
        <h3 class="images__item-text">Shop now</h3>
      </div>
  </div>
  <div class="images__item">
      <img src="images/img0.jpg" alt="" class="images__item-bg">
      <div class="images__item-brand">
        <img src="images/img-bicycle-sm.png" alt="">
        <h3 class="images__item-text">Shop now</h3>
      </div>
  </div>
</li>

# Block images số 3

hướng dẫn cắt psd siêu chi tiết

Ở block này tất cả mọi thứ đều như block số 1 ngoại trừ thay đường dẫn các hình ảnh và chỉ chỉnh duy nhất một thuộc tính CSS mà thôi đó chính là flex-direction với giá trị là column-reverse để đảo ngược hướng hiển thị. Ta có HTML và CSS như sau

<li class="images__block">
  <div class="images__block-item">
    <div class="images__item">
      <img src="images/img2.jpg" alt="" class="images__item-bg">
      <div class="images__item-brand">
        <img src="images/img-bicycle-sm.png" alt="">
        <h3 class="images__item-text">Shop now</h3>
      </div>
    </div>
    <div class="images__item">
      <img src="images/img4.jpg" alt="" class="images__item-bg">
      <div class="images__item-brand">
        <img src="images/img-bicycle-sm.png" alt="">
        <h3 class="images__item-text">Shop now</h3>
      </div>
    </div>
  </div>
  <div class="images__block-item">
     <div class="images__item">
      <img src="images/img6.jpg" alt="" class="images__item-bg">
      <div class="images__item-brand">
        <img src="images/img-bicycle-sm.png" alt="">
        <h3 class="images__item-text">Shop now</h3>
      </div>
    </div>
  </div>
</li>
.images__block:last-child {
  flex-direction: column-reverse;
}

Thế là xong block images số 3. Các bạn để ý mình có vẽ các mũi tên xanh chỉ chỗ background màu xanh lợt, chữ “Shop now” và logo. Chúng ta sẽ làm hiệu ứng đó tiếp theo dưới đây khi rê chuột vào.

# Images item style

<div class="images__item">
  <img src="images/img10.jpg" alt="" class="images__item-bg">
  <div class="images__item-brand">
    <img src="images/img-bicycle-sm.png" alt="">
    <h3 class="images__item-text">Shop now</h3>
  </div>
</div>

Để sử dụng thuộc tính position: absolute và căn chỉnh cho images__item-brand nằm trung tâm hay làm background mờ phủ lên cái images__item bằng :before hay :after thì images__item phải có thuộc tính position và giá trị ở đây là relative. Cấu trúc HTML đã có ở trên, chúng ta sẽ CSS như sau

.images__item {
  position: relative;
}
.images__item:before { 
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: #70c6a6c9;
  z-index: 10;
  display: none;
}
.images__item-bg {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.images__item-brand {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 20;
  text-align: center;
  display: none;
}
.images__item-brand > img {
  margin: 0 auto;
}
.images__item-text {
  text-transform: uppercase;
  color: white;
  font-size: 1.6rem;
  margin-top: .5rem;
  font-weight: bold;
}

Với đoạn code đầu tiên thì mình dùng :before để làm background phủ lên hết nhưng nó phải nằm dưới images__item-brand cho nên ở phần CSS cái images__item-brand mình cho z-index cao hơn để nó nằm lên trên đồng thời mình set cái background mờ ở :beforeimages__item-brand thuộc tính display: none để ẩn đi.

Sau đó mình muốn khi rê chuột vào images__item thì nó mới hiện lên thì chúng ta sẽ CSS đơn giản như này

.images__item:hover:before,
.images__item:hover .images__item-brand {
  display: block;
}

Thế là xong hết toàn bộ. Cuối cùng chúng ta sẽ có kết quả như mong muốn. Các bạn có thể nhấn vào đây để xem kết quả online hoặc nhấn vào đây để tải source code về tham khảo đối chiếu nhé.

# Tạm kết

Phù!!! Thế là xong phần 4. Quả là một chặng đường dài trong việc cắt PSD sang HTML CSS này. Còn vài phần nữa thôi là hết rồi. Hi vọng các bạn còn đủ kiên trì theo dõi serie này để ngày càng cải thiện kiến thức và trình độ hơn nà. Chúc các bạn một ngày tốt lành..

Subscribe
Notify of
guest

24 Comments
Inline Feedbacks
View all comments
Cường
Cường

Vẫn luôn theo dõi series này của bạn và mong chờ từng ngày, rất hi vọng sau này bạn sẽ viết nhiều bài hướng dẫn bổ ích về Front-end để cho mọi người cùng học hỏi ! Một lần nữa cảm ơn bạn rất nhiều ^^

Nhaan
Nhaan

Hóng phần kế tiếp kaka bài viết quá hay

Việt Anh
Việt Anh

A ơi, trong bài này em thấy dùng first-child cũng được mà anh 🙂 Theo em đọc hiểu về first-child với first-of-type nó chỉ khác nhau là first-child thì chỉ dùng đc khi nó là con đầu tiên của cha nó, còn first-of-type là con đầu tiên mà thuộc loại nó đang dùng thuộc cha nó :D. Trong bài em thấy mấy tên kia đều là con đầu cả, ko cần phải phân biệt type nào. Nếu em sai mong a chỉ lại 😛

Việt Anh
Việt Anh
Reply to  evondev

Cho em hỏi cái padding right left a hay để 1.5rem, số đó có ý nghĩa gì không ạ, hay mình thường dùng padding 2 bên 15 pixel a?

Việt Anh
Việt Anh
Reply to  evondev

Dạ =D Đó là câu trả lời em mong muốn rồi ạ. Em cảm ơn anh nhiều nhé

phong
phong

a cho e hỏi ở chỗ .tweet__pagi-item {
margin-left: .5rem;
margin right: .5rem;}
dấu chấm ở .5rem đó có nghĩa là sao ạ

phong
phong
Reply to  evondev

em cảm ơn ạ, a cho em hỏi thêm là :
.inp_collapse:checked + .nav_bg{
transform: scale(80);
}
.inp_collapse:checked ~ .nav_list{
transform: translateX(0);
}
dấu + với dấu ~ ở đoạn code trên có nghĩa là gì vậy ạ, e muốn search gg mà không biết từ khóa ạ

phong
phong
Reply to  evondev

cảm ơn a nhiều ạ, hi vọng a sẽ ra tiếp nhiều series mới ạ

tttt
tttt
Reply to  phong

0.5rem

người qua đường
người qua đường
Reply to  phong

là 0.5 á

haihugn
haihugn
Reply to  phong

0.5rem đó bạn

Manh Ngo
Manh Ngo

Mới học dặt tên class BEM này loạn xì ngậu quá anh, mỗi lần code css lại phải quay lại nhìn cấu trúc html =))

Sang
Sang

bài viết hay thật mà thấy anh dàn layout toàn sài flexbox không nhỉ, hóng bài psd2html dàn layout với grid

Quỳnh Anh Nguyễn
Quỳnh Anh Nguyễn

Cảm ơn anh, bài viết rất chi tiết dễ hiểu =)))