Table là 1 thành phần thường xuyên xuất hiện và không thể thiếu khi xây dựng các trang HTML/CSS để hiển thị nội dung dưới dạng bảng. Tuy nhiên, vấn đề xử lý để table hiển thị nội dung đầy đủ và rõ ràng cho các thiết bị mobile là 1 vấn đề khá nan giải, vì các thiết bị mobile có kích thước màn hình khá nhỏ.

Ví dụ, ta có 1 table với số column ít chỉ vài column thì vấn đề hiển thị nội dung của bảng trên mobile có vẻ như không có gì đáng lo. Nhưng nếu chúng ta xây dựng 1 table có số lượng column lớn, hàng chục thậm chí hàng trăm column thì khi hiển thị nội dung của table trên mobile thật là thảm họa.

Vấn đề

Chúng ta sẽ lấy ví dụ là 1 table gồm 5 column, dưới đây là hình ảnh của table khi hiển thị nội dung bên trong trên các thiết bị có kích thước lớn...

Responsive table với CSS image 28

...còn đây là khi hiển thị table trên mobile

Responsive table với CSS image 29

Điều này sẽ không làm người dùng các thiết bị mobile hài lòng chút nào, nếu muốn xem hết nội dung trong table này thì bắt buộc họ phải vuốt màn hình qua 2 bên. Rõ ràng, tâm lý chung của người dùng là rất không thích việc phải trượt ngang trên điện thoại hay tablet.

Xử lý

Ta có cấu trúc HTML của bảng trên như sau:

<table class="table table-bordered table-customize table-responsive">
    <thead>
        <tr>
            <th>Task</th>
            <th>Category</th>
            <th>Point</th>
            <th>User</th>
            <th>Time</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td data-title="Task"><a href="/task/138">The Very Beginning</a></td>
            <td data-title="Category">Logic Game</td>
            <td data-title="Point">10</td>
            <td data-title="User"><a href="/user/profile/55"><img src="http://www.gravatar.com/avatar/c4f70b92d051f8323e18b24030f0d045?d=mm&s=24" alt="KhanhLD" title="KhanhLD"/></img> <span class="text-danger">KhanhLD</span></a></td>
            <td data-title="Time">2016-06-18 10:22:45</td>
        </tr>

        <tr>
            <td data-title="Task"><a href="/task/100">The Dead Clock</a></td>
            <td data-title="Category">Logic Game</td>
            <td data-title="Point">20</td>
            <td data-title="User"><a href="/user/profile/2"><img src="http://www.gravatar.com/avatar/90b36c196a46f35da8c4fd1244cf15fd?d=mm&s=24" alt="bs90" title="bs90"/></img> <span class="text-danger">bs90</span></a></td>
            <td data-title="Time">2016-06-18 11:12:44</td>
        </tr>

        <tr>
            <td data-title="Task"><a href="/task/101">The Fotation</a></td>
            <td data-title="Category">Logic Game</td>
            <td data-title="Point">20</td>
            <td data-title="User"><a href="/user/profile/2"><img src="http://www.gravatar.com/avatar/90b36c196a46f35da8c4fd1244cf15fd?d=mm&s=24" alt="bs90" title="bs90"/></img> <span class="text-danger">bs90</span></a></td>
            <td data-title="Time">2016-06-18 11:13:11</td>
        </tr>

        <tr>
            <td data-title="Task"><a href="/task/107">Hello world!</a></td>
            <td data-title="Category">Logic Game</td>
            <td data-title="Point">10</td>
            <td data-title="User"><a href="/user/profile/2"><img src="http://www.gravatar.com/avatar/90b36c196a46f35da8c4fd1244cf15fd?d=mm&s=24" alt="bs90" title="bs90"/></img> <span class="text-danger">bs90</span></a></td>
            <td data-title="Time">2016-06-18 18:10:32</td>
        </tr>

        <tr>
            <td data-title="Task"><a href="/task/137">Picking CEO</a></td>
            <td data-title="Category">Logic Game</td>
            <td data-title="Point">5</td>
            <td data-title="User"><a href="/user/profile/2"><img src="http://www.gravatar.com/avatar/90b36c196a46f35da8c4fd1244cf15fd?d=mm&s=24" alt="bs90" title="bs90"/></img> <span class="text-danger">bs90</span></a></td>
            <td data-title="Time">2016-06-20 10:30:03</td>
        </tr>
    </tbody>
</table>

Dùng CSS để style cho table:

/* Style for table */
.table-customize {
  margin: 0;
  border-radius: 4px;
  overflow: hidden;
  box-shadow: 0 0 0 1px #ccc inset;
}
.table-customize > thead > tr {
  background-color: #535353;
  border-radius: 3px 3px 0 0;
}
.table-customize > thead > tr > th {
  color: #fff;
  border-bottom: none;
  padding: 10px 14px;
  font-size: 14px;
  font-weight: 400;
  border: 1px solid rgba(0, 0, 0, 0.2);
}
.table-customize > thead > tr > th:first-child {
  border-radius: 3px 0 0 0;
  border-top: 1px solid rgba(0, 0, 0, 0.2);
}
.table-customize > thead > tr > th:last-child {
  border-radius: 0 3px 0 0;
}
.table-customize > tbody > tr > td {
  vertical-align: middle;
  padding: 15px 14px;
  color: #ccc;
  font-size: 14px;
  color: #000;
  border: 1px solid #ccc;
}
.table-customize > tbody > tr > td a {
  text-decoration: none;
}

.table-order > tbody > tr:nth-child(-n + 3) > td:first-child {
  position: relative;
  font-size: 10px;
  font-weight: 700;
}
.table-order > tbody > tr:nth-child(-n + 3) > td:first-child span {
  position: absolute;
  left: 0;
  right: 0;
  margin: auto;
  top: 14px;
}
.table-order > tbody > tr:nth-child(1) > td:first-child {
  background: url(../img/bg-order-1.png) no-repeat center center;
}
.table-order > tbody > tr:nth-child(2) > td:first-child {
  background: url(../img/bg-order-2.png) no-repeat center center;
}
.table-order > tbody > tr:nth-child(3) > td:first-child {
  background: url(../img/bg-order-3.png) no-repeat center center;
}
.table-order > tbody > tr td:first-child, .table-order > tbody > tr th:first-child {
  text-align: center;
}

Tiếp theo sẽ là vấn đề quan trọng nhất, xử lý responsive cho table này để hiển thị nội dung tốt nhất có thể cho mobile, người dùng có thể xem và hiểu đầy đủ nội dung 1 cách dễ dàng chứ ko phải dùng đến thao tác trượt màn hình sang 2 bên hay phải zoom màn hình lại.

@media (min-width: 320px) and (max-width: 767px) {
  .table-responsive,
  .table-responsive thead,
  .table-responsive tbody,
  .table-responsive th,
  .table-responsive td,
  .table-responsive tr {
    display: block;
  }
  .table-responsive > thead > tr {
    position: absolute;
    top: -9999px;
    left: -9999px;
  }
  .table-responsive > tbody > tr {
    border-top: 1px solid #ccc;
    border-bottom: 1px solid #ccc;
  }
  .table-responsive > tbody > tr:first-child {
    border-radius: 3px 3px 0 0;
    border-top: none;
  }
  .table-responsive > tbody > tr:last-child {
    border-radius: 0 0 3px 3px;
    border-bottom: none;
  }
  .table-responsive > tbody > tr td {
    border: none;
    border-bottom: 1px solid #ccc;
    position: relative;
    padding-left: 30% !important;
    width: 100%;
    overflow: hidden;
  }
  .table-responsive > tbody > tr td:before {
    content: attr(data-title);
    position: absolute;
    top: 15px;
    left: 14px;
    width: 30%;
    padding-right: 10px;
    white-space: nowrap;
    font-size: 14px;
  }
  .table-responsive > tbody > tr td:first-child {
    text-align: left;
  }
  .table-responsive.table-order > tbody > tr:nth-child(-n + 3) > td:first-child {
    padding: 25px 0 25px 30% !important;
    background-position: left 32% center;
  }
  .table-responsive.table-order > tbody > tr:nth-child(-n + 3) > td:first-child span {
    left: 32%;
  }
}

Và đây là kết quả

Responsive table với CSS image 1

Bây giờ, từng column của mỗi row sẽ là 1 khối độc lập theo hàng ngang và hiển thị đầy đủ, trực quan nội dung của table. Người dùng không còn phải trượt ngang trên mobile để có thể xem hết nội dung của bảng mà chỉ việc trượt dọc từ trên xuống.

Giải thích 1 chút về phần Responsive Table trong đoạn CSS trên:

  • Đầu tiên ta sử dụng thẻ @media để xác định độ rộng của thiết bị mobile cần hiển thị responsive table.
  • Tiếp theo, set tất cả các thành phần bên trong table có thuộc tính display: block;. Thuộc tính này sẽ đưa giúp các thành phần HTML hiển thị như một khối, khi sử dụng giá trị block thành phần sẽ đứng một hàng độc lập so với thành phần trước và sau nó.
  • Ẩn tất cả các title hiện có của các column bằng thuộc tính position: absolute và hiển thị title cho từng column của mỗi row.
  • Để hiển thị title cho từng column của mỗi row, ta sẽ đẩy nội dung trong column đó sang trái với thuộc tính padding cho thẻ td. Sử dụng phương thức :before sau thẻ td để hiển thị title, bằng cách truyền dữ liệu thông qua thuộc tính content: attr(data-title);, attr(data-title); sẽ lấy nội dung bên trong thuộc tính data-title của từng thành phần td ở file HTML mà chúng ta đã thêm vào tương ứng tên của từng column.
  • Như vậy chúng ta đã thực hiện xong việc responsive table cho mobile.

Kết luận

Trên đây là 1 trong những phương pháp thực hiện responsive table cho mobile đơn giản nhất với sự kết hợp linh hoạt giữa HTML và CSS. Tuy nhiên, việc thực hiện responsive table cho mobile còn rất nhiều vấn đề với nhiều dạng table phức tạp khác nhau, chúng ta sẽ xử lý những vần đề này trong những bài tiếp theo. Cảm ơn và hẹn gặp lại!

Viết câu trả lời

Drop Images