CSSJquery

Chuyển hiển thị bài viết từ dạng list sang grid (dạng lưới)

Demo: Demo 1Demo 2

Chuyển bài viết dạng list dang grid
Chuyển bài viết dạng list dang grid

Trong thiết kế website sẽ có 2 kiểu hiển thị bài viết, nội dung đó là dạng list (danh sách) và dạng grid (lưới). Và đa phần bây giờ mọi người theo xu hướng làm web về dạng grid. Có lẽ là vì sự bố trí theo kiểu grid sẽ làm website trở nên khoa học, bắt mắt và hiển thị được nhiều bài viết hơn trên 1 trang.

Vậy thì hôm nay, mình sẽ giúp các bạn hiểu cơ chế cơ bản để tự triển khai được cho website của mình nhé.

Trong bài viết mình sẽ sử dụng 2 kiến thức mà mình đã viết trước đây là:

Các bạn hãy đọc lại để hiểu cách dùng nhé. Giờ thì ta bắt đầu nhé.

Grid kiểu cơ bản

Giả dụ mình có toàn bộ code gồm HTML, CSS và Jquery như sau. Mình sẽ giải thích những dòng code quan trọng ngay bên cạnh.

HTML

<div class="wrapper">
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
</div>
<button>Click me</button>

CSS

body, html {
  margin: 0;
  padding: 0;
  border: 0;
  outline: 0;
  font-family: sans-serif;
}

.wrapper {
  max-width: 600px;
  overflow: hidden;
  margin: 0 auto;
}
.wrapper .item {
  position: relative;
  width: 100%; /* set 100% để item đứng 1 mình 1 hàng, không thì đặt display: block cũng được */
  height: 100px;
  background: #70c3e9;
  margin: 20px;
  -webkit-transition: all 0.4s ease;
  transition: all 0.4s ease;
}
.wrapper .item.grid {
  width: 100px; /* Set width: 100px để thu gọn phần tử lại để có thể chứa thêm nhiều phần tử khác trên cùng 1 hàng (đúng chuẩn dạng grid) */
  float: left; /* Dùng thuộc tính float: left để kéo các phần tử lên vì mặc định giá trị của thẻ div là block. Không dùng float: left có thể dùng display: inline-block */
}

button {
  display: block;
  margin: 20px auto;
  outline: 0;
  border: 0;
  padding: 1rem;
  border: 2px solid #70c3e9;
  background: transparent;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 1px;
  border-radius: 2px;
  color: #333;
  -webkit-transition: all 0.4s ease;
  transition: all 0.4s ease;
  cursor: pointer;
  clear: both;
}
button:hover {
  background: #70c3e9;
  color: #fff;
}

Jquery

$(function() {
    $('button').click(function() { // Gán sự kiện click cho cho nút bấm chuyển đổi 2 dạng list và grid cho nhau. Bạn hoàn toàn có thể thay bằng thẻ khác, miễn là gọi sự kiện cho đúng selector là được.
        $('.item').toggleClass('grid'); // toggleClass grid cho .item
    });
});

Nguyên tắc hoạt động: Bạn hãy để ý, dạng list sẽ cho bài viết ở chế độ full width tức chiều rộng 100% còn bố trí bài viết theo dạng grid sẽ làm nhiều bài viết cùng hiển thị trên 1 hàng. Vì thế mà width của bài viết sẽ phải nhỏ đi để đáp ứng được yêu cầu đó.

Dấu hiệu thứ 2 là thuộc tính float giúp kéo các phần tử lên đến khi hết chiều rộng tối đa của phần tử cha (tức là 1 hàng đó) thì sẽ xuống dòng. Khi không quen dùng float thì bạn có thể dùng display: inline-block (để hiểu rõ thì bạn search google thuộc tính này nhé) cũng được.

Demo cơ bản (mình dùng SCSS để viết CSS nên nếu bạn không hiểu thì ở đó có tùy chọn View Compiled CSS để show CSS nhé): https://codepen.io/tsmkevin815/pen/NEoeRO

Nếu bạn đã hiểu về tí code cơ chế chuyển đổi 2 dạng list và grid rồi thì giờ mình làm nâng cao lên 1 xíu cho nó gần gũi với các blogger nhé.

Grid nâng cao tí xíu

Phần này mình sẽ cung cấp demo trước: https://codepen.io/tsmkevin815/pen/LXwWbM

Code ta cần sẽ như sau (mình vẫn sẽ để CSS ở bài viết, demo mình dùng SCSS viết CSS cho nhanh thôi cả mình quen rồi nên các bạn thông cảm :D)

HTML

<div class="main">
    <div class="post">
        <div class="thumbnail">
            <img src="https://i.ytimg.com/vi/e7N_JwuXPGY/maxresdefault.jpg">
        </div>
        <div class="content">
            <h2><a href="#">Lorem ipsum dolor sit amet</a></h2>
            <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aliquid ea sequi, tempora eveniet odit quam?</p>
        </div>
    </div>
    <div class="post">
        <div class="thumbnail">
            <img src="https://i.ytimg.com/vi/e7N_JwuXPGY/maxresdefault.jpg">
        </div>
        <div class="content">
            <h2><a href="#">Lorem ipsum dolor sit</a></h2>
            <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolorem necessitatibus deleniti quo repudiandae, enim cumque?</p>
        </div>
    </div>
    <div class="post">
        <div class="thumbnail">
            <img src="https://i.ytimg.com/vi/e7N_JwuXPGY/maxresdefault.jpg">
        </div>
        <div class="content">
            <h2><a href="#">Lorem ipsum dolor sit amet, consectetur</a></h2>
            <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Reprehenderit, qui perferendis repudiandae labore quam ducimus.</p>
        </div>
    </div>
</div>
<div class="post-action">
    <span class="switch-button gridbtn active"></span>
</div>

CSS

body,
html {
  margin: 0;
  padding: 0;
  border: 0;
  outline: 0;
  font-family: sans-serif;
}

.main {
  max-width: 800px;
  overflow: hidden;
  margin: 0 auto;
  padding: 20px 0;
}
.main .post {
  margin: 20px 0;
  background: #fff;
  border: 1px solid #eee;
  border-radius: 2px;
  padding: 8px;
  transition: all 0.4s ease;
}
.main .post:hover {
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.15);
}
.main .post .thumbnail {
  height: 150px;
  overflow: hidden;
  float: left;
  width: 180px;
  margin-right: 20px;
}
.main .post .thumbnail img {
  width: 100%;
  height: 100%;
  -o-object-fit: cover;
     object-fit: cover; /* Dòng này giúp hình ảnh không bị méo khi co kích thước */
}
.main .post .content {
  padding: 20px;
}
.main .post .content h2 {
  font-size: 1.2rem;
  margin-bottom: 5px;
  letter-spacing: 0.5px; /* Khoảng cách giữa các kí tự trong 1 từ */
  font-weight: 400;
}
.main .post .content h2 a {
  text-decoration: none;
  color: #555;
  transition: all 0.4s ease;
}
.main .post .content h2 a:hover {
  color: #70c3e9;
}
.main .post .content p {
  font-size: 0.9rem;
  font-style: italic;
  text-align: justify;
  line-height: 1.4;
}
/* Các CSS bên dưới sẽ là khi thêm class .grid-style tức là khi chuyển qua dạng grid, bạn đặt là class hay id gì tùy bạn nhé. */
.main .post.grid-style {
  float: left;
  width: 30%;
  margin: 0.5%;
}
.main .post.grid-style .thumbnail {
  float: none; /* Không float và ảnh full width để nội dung gồm tiêu đề và mô tả dịch chuyển xuống dưới. Cái này tùy cách viết CSS của các bạn thôi, mình thấy hợp lý nên mình viết theo cách này */
  width: 100%;
  height: 180px;
  margin: 0;
}
.main .post.grid-style .content {
  padding-top: 0;
  text-align: center;
}

.post-action {
  text-align: center;
}
.post-action .switch-button {
  display: inline-block;
  position: relative;
  font-size: 1.5rem;
  cursor: pointer;
  transition: all 0.4s ease;
}
.post-action .switch-button::after { /* Tạo tooltip cho nút bấm chuyển đổi dạng list và grid */
  content: "";
  color: #fff;
  background: #333;
  display: inline-block;
  font-size: 0.9rem;
  padding: 5px 10px;
  position: absolute;
  top: -30px;
  left: 50%;
  -webkit-transform: translateX(-50%); 
          transform: translateX(-50%); /* Thuộc tính này bạn thêm vào để nó căn giữa thôi, mình sẽ viết 1 bài giới thiệu về thuộc tính này sau */
  opacity: 0;
  visibility: hidden;
  transition: all 0.4s ease;
  width: 135px;
}
.post-action .switch-button.active {
  color: #333;
}
.post-action .switch-button.gridbtn::before {
  content: "\f00a"; /* Icon Grid từ FontAwesome 4.7 */
  font-family: FontAwesome;
}
.post-action .switch-button.gridbtn::after {
  content: "Change Grid Style"; /* Nội dung tooltip cho icon grid */
}
.post-action .switch-button.no-gridbtn::before {
  content: "\f0ca"; /* Icon List */
  font-family: FontAwesome;
}
.post-action .switch-button.no-gridbtn::after {
  content: "Remove Grid Style"; /* Nội dung tooltip cho icon list */
}
.post-action .switch-button:hover::after {
  opacity: 1;
  visibility: visible;
}

Jquery

$(".switch-button").click(function() {
    $(".post").toggleClass("grid-style");
    $(this).toggleClass("no-gridbtn");
});

Nguyên tắc hoạt động: Bạn có thể để ý khi bài viết ở dạng list thì hình ảnh (thumbnail) của bài viết sẽ ở bên trái hoặc bên phải hoặc ở giữa phí trên, phía dưới nội dung. Khi ta chuyển qua dạng grid thì cách xếp khoa học và để hình ảnh không bị quá nhỏ thì ta sẽ đều để hình ảnh riêng biệt 1 chỗ so với nội dung chú không để cùng hàng đúng không?

Khi click button thì chuyển hết thuộc tính mới cho các phần tử hiển thị đồng thời button đó cũng thay đổi icon theo CSS mình đã viết.

Ngoài ra, có 1 điểm mình cực kì lưu ý để sau này bạn không phải thêm quá nhiều toggleClass cho selector khi viết Jquery là hãy chỉ để 1 selector cha nhận class hay id chuyển đổi (như ví dụ thì mình dùng .grid-style chỉ cho .post đó).

Để giúp hiểu rõ mình ví dụ đoạn mình đã viết:

.main .post.grid-style {
  float: left;
  width: 30%;
  margin: 0.5%;
}
.main .post.grid-style .thumbnail {
  float: none;
  width: 100%;
  height: 180px;
  margin: 0;
}
.main .post.grid-style .content {
  padding-top: 0;
  text-align: center;
}

Có thể thấy mình chỉ cho thằng cha (parent) là class .post nhận class mới (new) .grid-style và điều chỉnh các class con (child) theo dạng đúng (nếu không có class cha thì class con không nhận CSS nhé)

.parentclass.newclass .child {property: value;...}

Khi đó, Jquery ta chỉ cần toggleClass cho đúng thằng cha .post thì toàn bộ thằng con sẽ nhận CSS mới bạn mới code. Selector là id thì tương tự.

Nếu trường hợp bạn thêm class mới cho toàn bộ thì sẽ như sau:

.main .post.grid-style {
  float: left;
  width: 30%;
  margin: 0.5%;
}
.main .thumbnail.grid-style {
  float: none;
  width: 100%;
  height: 180px;
  margin: 0;
}
.main .content.grid-style {
  padding-top: 0;
  text-align: center;
}

Lúc đó Jquery sẽ phải toggleClass cho cả 3 selectors luôn là .post, .thumbnail.content thay vì chỉ cho 1 selector .post như trường hợp trên. Cái này hết sức lưu ý để sau thiết kế website mình tối ưu được chỗ code không bị thừa, ảnh hưởng SEO.

Kết luận

Vậy là mình vừa giúp các bạn tìm hiểu được cơ chế để tạo nút chuyển đổi giữa 2 dạng list và grid cho nhau. Trên đây, mình chỉ mới đưa ra ví dụ đơn giản. Do đó, ở mức độ phức tạp hơn (giả dụ bài viết có nhiều phần tử hơn) thì ta sẽ CSS nhiều hơn cũng như tạo 2 nút bấm riêng biệt (demo ở đây: https://webseo247.com/theme/).

Ngoài ra, nâng cao hơn nữa, có thể kết hợp cookies, localStorage… để lưu dữ liệu clients giúp khi F5 hay thoát website thì vẫn giữ được hiển thị cuối cùng của họ. Nôm na là đang ở dạng grid thì mãi là grid trừ khi họ bấm lại chuyển qua dạng list ấy. Cái này mình sẽ viết sau khi có thời gian.

Nếu thấy bài viết khó hiểu chỗ nào thì để lại comment nhé. Mình sẽ chỉ giải đáp thắc mắc ở đây, không inbox FB cá nhân mình nhé.

Created by: PCDevShare.Com

4
Bình luận

avatar
2 Comment threads
2 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
3 Số người bình luận
Cuong NguyenTrần Nhật SinhQuốc Bảo Blog Người mới bình luận
  Đăng kí  
mới nhất cũ nhất nhiều vote nhất
Nhận thông báo từ
Quốc Bảo Blog | 24 comments
Khách
Quốc Bảo Blog | 24 comments

“mình chỉ cho thằng cha” chỉ có ở pcdevshare :>

Trần Nhật Sinh | 15 comments
Khách
Trần Nhật Sinh | 15 comments

Ái chà chà , sau bao ngày chờ đợi cuối cùng a cường cũng viết bài hướng dẫn rồi , đúng cái mà em cần mấy nay