Nội dung bài viết
Sau phần 2 của series hướng dẫn cắt PSD sang HTML toàn tập mình đã drop một thời gian vì bận viết các bài khác cho nên hôm nay quay lại để tiếp tục cho các bạn với mục tiêu trong tháng 12 là xong series hướng dẫn cắt PSD sang HTML toàn tập cho các bạn luôn.
Hôm nay sẽ là phần 3 tiếp nối phần trước thì chúng ta đã làm xong phần Header và Menu. Tiếp đến bây giờ là phần Feature với cấu trúc layout khá phức tạp hơn một chút. Các bạn có thể xem qua hình trước
Wow. Cái trên thì chắc dễ rồi còn ba phần dưới thì sao nhỉ, tạo cấu trúc HTML sao cho đúng, đặt tên class sao cho chuẩn BEM, dễ dàng tái sử dụng, tối ưu code và quan trọng là hiển thị đúng so với Design. Thôi thì không dài dòng nữa chúng ta cùng phân tích và làm nhé.
Nếu bạn nào chưa đọc các bài trước thì nhớ nhấn vào đây để đọc lại nhé vì mình có để liên kết tới source code để các bạn có thể tải về làm theo đó. Nếu các bạn không đọc hai phần trước mà bay vô phần này luôn là tẩu hỏa nhập ma đấy.
# Feature header
Rồi nhìn vào phần Feature Header thì ta thấy có ba phần chính đó là một tấm hình nhỏ, một tiêu đề và một đoạn text đơn giản.
Sau khi dùng các công cụ của Photoshop để lấy các thông số như kích thước chữ, khoảng cách… thì mình đã có các số liệu cụ thể như kích thước của tiêu đề và chữ đều là 18px, màu nền của block là màu xám mờ, khoảng cách giữa các phần tử là 30px, 20px…
Lưu ý những thông số như khoảng cách, kích cỡ chữ, màu sắc các bạn nên tự làm bằng cách dùng công cụ có sẵn của Photoshop nhé. Trong phạm vi bài này mình chỉ nói sơ thôi vì chỉ cụ thể từng bước rất là dài và tốn thời gian.
Giờ mình tạo cấu trúc HTML đơn giản cho nó như sau:
<div class="feature"> <div class="feature__header"> <img src="images/icon1.png" alt="" class="feature__img-top"> <h2 class="feature__heading">A NEW GENERATION OF VINTAGE BIKE</h2> <p class="feature__header-desc">Lorem Ipsum simply dummy text... </p> </div> </div>
Mình đặt tên theo chuẩn BEM đã nói ở các bài trước để cho code nó clean hơn. Nhiều bạn sẽ hỏi tại sao không đặt thẻ img
class là feature__header-img
hay là thẻ h2
class là feature__header-title.
Là vì tẹo nữa chúng ta sẽ dùng lại chúng ở phần Feature List bên dưới cho nên mình đặt tên theo kiểu đó để có thể dùng lại sau này.
Lưu ý việc đặt tên: Các bạn có thể đặt tên theo kiểu của mình để học hỏi hoặc có thể đặt theo phong cách riêng của các bạn nhé. Miễn sao các bạn thấy ổn là được rồi nhé.
Cuối cùng dựa vào các thông số mình đã lấy được từ Photoshop chúng ta có CSS như sau
.feature__header { padding: 11rem 1.5rem 14rem; background-color: var(--bg-light); } .feature__img-top { margin: 0 auto 3rem; } .feature__heading { font-size: 1.8rem; line-height: 1.6; text-transform: uppercase; color: var(--heading); margin-bottom: 2rem; font-weight: bold; text-align: center; } .feature__header-desc { font-size: 1.8rem; line-height: 1.6; color: var(--text); max-width: 106rem; margin: 0 auto; text-align: center; }
Chúng ta sẽ có kết quả như mong đợi. Như vậy là xong phần Feature Header nha các bạn. Tiếp đến sẽ là phần khó nhằn bên dưới.
# Feature list
Nhìn vào hình thì tổng thể ta có block1 và block2 giống nhau nhưng ngược hướng ta có thể dùng CSS flexbox kèm thuộc tính order
để thay đổi vị trí vì thế chỉ cần code cái block1 thì cái block2 cũng coi như xong. Cấu trúc block1 và block2 có tỉ lệ là 2/3 và 1/3 tương ứng với 67% và 33%.
Còn block3 thì cấu trúc nó có tới ba cột. Nhìn có cảm giác bằng nhau nhưng sau khi đo thì mình thấy cột thứ hai to hơn hai cột còn lại một chút xíu thôi cho nên nếu chia % ra thì ta sẽ có ba cột tương ứng là cột1(33%) cột 2(34%) và cột 3(33%) hen.
Bây giờ là đến phần code HTML cho chúng. Mình dùng lại HTML ở phần Feature Header ở trên luôn cho các bạn dễ hình dung và thêm thẻ ul
để làm cái Feature List này.
<div class="feature"> <div class="feature__header"> ... </div> <ul class="feature__list"> ... </ul> </div>
Mình dùng ul li
để làm dạng danh sách vì mình có tới ba phần tử cũng như có thể chọn các phần tử dễ dàng bằng cách dùng:nth-child,
:last-child
…. để tiện cho việc tùy chỉnh code một cách trơn tru.
# Feature item
Lưu ý những đoạn code dưới đây nằm trong thẻ ul có class
feature__list
ở đoạn code trên nhé.
Dựa vào hình ta thấy block1 có hai phần đó là phần hình ảnh bên trái và phần nội dung bên phải và chiều cao của block1 là 600px. Tỉ lệ đã nói ở trên là 67% và 33% và chúng ta sẽ sử dụng CSS Flexbox để làm layout từ đó ta có HTML CSS như thế này.
<li class="feature__item"> <div class="feature__item-img"> </div> <div class="feature__item-content"> </div> </li>
.feature__item { display: flex; flex-flow: row wrap; height: 60rem; overflow: hidden; } .feature__item-img { width: 67%; position: relative;/*Note*/ } .feature__item-content { width: 33%; }
Vì mới chia cột thôi nên lúc này nhìn vào Web vẫn chưa có gì đâu. Nên chúng ta sẽ tiếp tục đưa tiếp các phần tử khác vào.
Ở cột bên trái ta có hai tấm hình, một hình to phủ hết cột và một hình nhỏ nằm chính giữa cột. Ta sẽ có HTML như thế này
<div class="feature__item-img"> <img src="images/img14.jpg" alt="" class="img__bg"> <img src="images/img-bicycle-company.png" alt="" class="img__brand"> </div>
Tấm hình phủ hết cột mình cho class là img__bg
nghĩa là hình nền và tấm hình nhỏ là img__brand
kiểu như là thương hiệu-logo nha. Sau đó mình sẽ CSS cho chúng như dưới đây.
.feature__item .img__bg { height: 100%; width: 100%; object-fit: cover; } .feature__item .img__brand { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 2; }
Các bạn để ý ở class feature__item-img
(có Note ở trên) mình cho thuộc tính position: relative
để tấm hình có class img__brand
có thể dùng position: absolute
để căn chỉnh theo đấy. Nếu bạn chưa rõ về thuộc tính position trong CSS thì có thể tìm hiểu tại đây.
Đến cột phải thì trong cột phải thì lại có hai nội dung khác theo chiều dọc. Một trên một dưới nên mình sẽ đặt là content-top và content-bottom.
<div class="feature__item-content"> <div class="feature__item-content-top"> <img src="images/icon2.png" alt="" class="feature__img-top"> <h3 class="feature__heading">Vintage Oliva</h3> <p class="feature__item-text">Lorem Ipsum simply...</p> </div> <div class="feature__item-content-bottom"> <img src="images/img1.jpg" alt="" class="img__bg"> </div> </div>
Phần content-top có chiều cao là 400px và content bottom có chiều cao là 200px. Từ đó mình tính ra được phần trăm chiều cao tương ứng là 67% và 33%.
Các bạn để ý sẽ thấy lại class
feature__heading
vàfeature__img-top
mình đã dùng trước đó vì như mình đã nói từ trước là các phần sau cũng sử dụng chúng nên phải đặt tên như thế để tái sử dụng.
Nhìn vào cấu trúc cột bên phải mình thấy nội dung theo hướng chiều dọc cho nên mình sẽ dùng flexbox với thuộc tính flex-direction: column
. Nếu chưa hiểu kỹ về flexbox thì đừng quên tham khảo lại nó tại đây.
.feature__item-content { height: 100%; display: flex; flex-direction: column; justify-content: space-between; }
Tiếp đến là content-top ta có padding hai bên là 70px và nội dung của nó nằm giữa cho nên mình cũng dùng flexbox cho nó luôn, kèm theo đó là CSS cho chiều cao của nó(content-top) và cho đoạn chữ(feature__item-text
) cũng như chiều cao của content-bottom.
.feature__item-content-top { display: flex; flex-direction: column; justify-content: center; padding: 0 7rem; position: relative; background-color: white; height: 67%; } .feature__item-text { font-size: 1.6rem; line-height: 1.6; color: var(--text); text-align: justify; position: relative; padding-bottom: 3rem; } .feature__item-content-bottom { height: 33%; }
Đến block2 thì cấu trúc HTML y chang block1 luôn chỉ thay đổi đường dẫn hình ảnh và nội dung chữ đồ thôi, rồi sau đó ta dùng thuộc tính order
cho class feature__item
số hai bằng cách dùng :nth-child
như sau thì lúc này phần nội dung hình bên trái sẽ nằm qua bên phải và ngược lại phần nội dung bên phải sẽ chạy qua trái.
.feature__item:nth-child(2) .feature__item-img{ order: 2; }
Cuối cùng là block3 với cấu trúc HTML cũng y hệt block1 nhưng thêm một cột hình ảnh mà thôi(feature__item-img
). Mình có Note ở cấu trúc HTML dưới đây
<li class="feature__item"> <div class="feature__item-img"> <img src="images/img7.jpg" alt="" class="img__bg"> <img src="images/img-bicycle-text.png" alt="" class="img__brand"> </div> <div class="feature__item-content"> <div class="feature__item-content-top"> <img src="images/icon4.png" alt="" class="feature__img-top"> <h3 class="feature__heading">Retrò Bike - M. Hulot</h3> <p class="feature__item-text">Lorem Ipsum simply ...</p> </div> <div class="feature__item-content-bottom"> <img src="images/img9.jpg" alt="" class="img__bg"> </div> </div> <div class="feature__item-img">//Note <img src="images/img8.jpg" alt="" class="img__bg"> </div> </li>
Cấu trúc đã thay đổi nên không thể để 67% 33% như hai cột được nữa nên chúng ta phải code lại. Như đã nói ở phần phân tích thì ta có tỉ lệ ba cột tương ứng là 33% 34% 33%.
Để chọn feature__item
cuối cùng thì chúng ta sẽ dùng :last-child
và CSS cho phần hình ảnh(cùng một class) và phần nội dung ở giữa lần lượt là.
.feature__item:last-child > .feature__item-img { width: 33%; } .feature__item:last-child > .feature__item-content { width: 34%; }
“Rất đơn giản” phải không các bạn ?
Còn hai điểm nữa mà mình quên làm một là ở content-top của cột nội dung ở phía dưới có cái hình tam giác như mình đã note mũi tên ở trên hình.
Chúng ta đã tìm hiểu và sử dụng nó ở bài before và after đấy. Các bạn có thể quay lại xem để tham khảo nha. Ở đây mình sẽ dùng :after
và code như sau
.feature__item-content-top:after { content: ""; position: absolute; bottom: 0; left: 50%; width: 2rem; height: 2rem; background-color: white; z-index: 10; transform: translate(-50%, 50%) rotate(-45deg); }
Và hai là ở phần chữ trong content-top có border ở dưới một đoạn ngắn mình cũng đã chỉ trên hình cho các bạn thấy đó. Nên chúng ta sẽ lại áp dụng :after
tiếp để làm.
.feature__item-text:after { content: ""; position: absolute; bottom: 0; left: 50%; transform: translateX(-50%); width: 6rem; height: 1px; background-color: var(--bg-light); }
Kết quả là sau một hồi vật vã phân tích và code thì chúng ta đã có kết quả y như mong đợi hehe.
# Lời kết
Phù!!! Cuối cùng cũng xong. Cám ơn các bạn đã đọc một bài viết dài và chi tiết như thế này. 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 xem có giống code của các bạn làm không nhé cũng như để tiếp tục theo dõi phần 4 sẽ ra sắp tới.
Nếu có gì không hiểu hoặc góp ý thì đừng ngại mà bình luận nha. Mình luôn sẵn sàng trả lời. Chúc các bạn một ngày tốt lành.
Ad viết về phần hướng dẫn responsive được không ạ? 😀
Mai mốt mình viết series này cũng tới phần responsive đó bạn. Tới đó mình viết luôn nà
nice <3
Thanks <3
Hi vọng bạn làm cả phần responsive nữa !! Cảm ơn nhiều 😀
Chắc cỡ 2 phần nữa sẽ tới keke
Thank anh, mong anh ra nhiều bài viết hơn nữa để mọi người cùng tham khảo và học tập.
Chắc chắn rồi em nè. A sẽ cố gắng.
Anh ơi cho em hỏi khi nào thì mình dùng padding hoặc margin để căn văn bản vậy anh? Em thấy anh trong bài lúc dùng padding lúc dùng margin vậy làm sao để biết dùng cái nào vậy anh? Cảm ơn anh vì bài viết
Làm nhiều em sẽ biết khi nào nên dùng padding, margin thôi em ah. Margin thì dùng bên ngoài phần tử khi em muốn nó cách một phần tử nào đó khác một khoảng bao nhiêu đó chẳng hạn, còn padding thì nó áp dụng cho bên trong chính content đó. Padding càng lớn thì nó càng bóp content lại.
Cám ơn anh em cứ thắc mãi. Anh cho em xin hỏi thêm 1 câu nữa, khi em đang viết theo code css của anh có vài chỗ em cứ thắc mắc là khi em xóa 1 thuộc tính thì browser vẫn hiển thị như cũ. Cụ thể lúc em viết cái class feature__item-content thì có thuộc tính height: 100% thì khi em xóa nó đi nó vẫn không làm thay đổi giao diện. Vậy sao mình phải thêm nó vào vậy anh?
À lúc đầu do anh nghĩ set ở class cha height: 60rem nên content phải cho height: 100% để nó cao = cha á mà. Nhưng a quên là a đang dùng display: flex và mặc định align-items là stretch nên nó tự dãn ra luôn. Nên đoạn code em nói bỏ cũng được nha em hi. thanks em
Ok em cám ơn anh chúc anh có sức khỏe để ra tiếp những bài viết bổ ích như vậy.
Thanks em 😀
Hi a, lại là e đây =)) ko biết a nhớ ko, tự dưng e đọc lại và thắc mắc 1 điểm, đó là chỗ phần text trong .feature__item-content-top mà tăng thì làm sao để giữ được tỉ lệ của layout? =D
Thường design người ta sẽ làm chuẩn nếu dài quá ảnh hưởng đến layout thì ta có thể cắt ngắn lại nè em kaka
sau những phần làm xong mình thấy có tải code về coi lại thì đa phần download lỗi, bạn coi lại giúp mình,
Updated. Thank you
Hic, nhìn code của a gọn gàng hết sức. Nội dung hữu ích quá a ơi
Cám ơn em nhiều nè. Làm nhiều sẽ tốt thôi em hi
vấn dề thừa thiếu 1 vài px trong margin vs pading có quan trọng quá ko b
Không sao đâu bạn ah, 80-90% là quá giỏi rồi nè
Phần feature__header-desc nó có vài cái tương tự như feature__item-text e thấy người ta khuyên nên thêm cả hai cái vào class rồi mình sửa lại vài cái trong feature__item-text.
Với lại e thấy người ta dùng Block__Element–Modifier cái phần M người ta dùng 2 gạch còn anh dùng 1 gạch, cái này có quan trọng k anh
2 gạch là modified, còn một gạch là dành cho element nào tên dài thay vì viết headerDesc thì anh viết header-desc
Tks anh, em hiểu rồi. Em vẫn chưa quen với kiểu đặt tên này lắm :))