Một vài thủ thuật làm việc với các dạng layout - Phần 3
Bài đăng này đã không được cập nhật trong 4 năm
Chào mọi người, tiếp tục với series's về các dạng layout hôm nay mình sẽ chia sẻ thêm một trick thú vị nữa về layout table.
Đợt này mình ôm 2 project nên hơi sấp mặt, cũng là mấy con admin nhưng design có vẻ hứng thú và bắt mắt hơn mấy cái dashboard trước đây. Trong bài hát "Đường đến ngày vinh quang" của cố nhạc sĩ Trần Lập có câu "chặng đường nào trải bước trên hoa hồng bàn chân cũng thấm đau vì những mũi gai"... đi liền với cái đẹp thường là sự phức tạp, tuy nhiên làm việc với design đẹp và những cái đẹp là điều làm mình hứng thú.
Đâu đó cũng 3 tuần rồi, đang vật lộn với việc estimate task bên dự án khác thì lại bị vỗ vai nhờ support. Lần này không phải em gái xinh xắn bàn bên mà là một em trai cao to da trắng tưởng tới rủ mình đi chơi nhưng lại nhờ fix giúp cái table. Mình không còn sợ chị designer buồn dẫn đến trầm cảm nữa mà mình sợ anh em Backend sấp mặt với đội QA vì dự án sắp release nên mình đã ra tay giúp đỡ.
Bây giờ mình sẽ tái hiện lại chiếc table mình làm hôm trước. Anh em review phát xem có gọn gàng không nhé.
1. Sync scroll for table has a space
Thông thường, với kiểu table
có khoảng trống ngăn giữa các row
mọi người sẽ nghĩ ngay đến việc dùng margin
để tạo khoảng cách. Đúng như vậy nhưng nhiều khi cuộc sống đâu như những giấc mơ, việc coding để đẹp như design cũng không phải đơn giản.
Mô tả:
- Table xuất hiện scroll khi có nhiều cột
- Cột đầu tiên được cố định khi scroll
- Row cuối cùng cách các row trên 1 khoảng và table có bo tròn để tăng tính thẩm mĩ.
Ý tưởng thực hiện
- Giống như bài trước table lần này vẫn có bo tròn, có đường line đẹp đẹp.
- Tạo 2 table giống nhau, có
margin
để tạo khoảng cách - Viết 1 đoạn
js
nhỏ để getwidth
của từngcell
và set vàotable
bên dưới để đồng bộ size.
.wrap
.container
table
thead
tr
th Cột title
th Hích đờ
th Hích đờ
th Hích đờ
th Hích đờ
th Hích đờ
th Hích đờ
th Hích đờ
tbody
each row in [1, 2, 3, 4]
tr
td Row title
td cell content
td cell content
td cell content
td cell content
td cell content
td cell content
td cell content
tr.table-row-last
td.text-nowrap Row title long text...
td cell content
td cell content
td cell content
td cell content
td cell content
td cell content
td cell content
//- table (row cuối)
.wrap
.container
table.table-footer
tbody
tr
td Sum sum sum
td cell content
td cell content
td cell content
td cell content
td cell content
td cell content
td cell content
.wrap {
flex: 1;
width: 100%;
margin: auto;
margin-bottom: 5px;
border: 1px solid #36304a;
border-radius: 5px;
overflow: hidden;
}
// Chỗ này để chứa table scroll
.container {
display: block;
width: 100%;
overflow-x: auto;
}
table {
width: 100%;
min-width: 1000px;
tr {
&:not(:last-child) {
td {
border-bottom: 1px solid gray;
}
}
&:nth-child(even) {
td {
background: #ffc7f8;
}
}
}
td {
padding: 10px 20px;
background: #ffedfd;
}
th {
padding: 20px;
color: white;
background: #36304a;
white-space: nowrap;
text-align: center;
}
td, th {
// Fixed cột đầu tiên của table
&:first-child {
position: sticky;
left: 0;
z-index: 9;
}
&:not(:last-child) {
border-right: 1px dotted gray;
}
}
}
// customize scroll cho đẹp
::-webkit-scrollbar {
width: 5px;
height: 5px;
}
::-webkit-scrollbar-track {
background: white;
}
::-webkit-scrollbar-thumb {
background: #36304a;
}
// Đoạn này dùng để get/set width cho table
var firstTableWidth = [];
// selector đến th của table trên và get width th
$('table th').each(function(i, item) {
firstTableWidth.push($(this).width());
});
// set width vào từng td của table còn lại
$('.table-footer td').each(function(i, item) {
$(this).width(firstTableWidth[i]);
});
// Đồng bộ scroll cho 2 table
$('.container').on('scroll', function() {
$('.container:not(this)').scrollLeft($(this).scrollLeft());
});
Ngoài cách trên:
- Để tạo phân cách: mình cũng nghĩ việc dùng
:before
hoặc:after
set cùng màu background để tạo line phân cách. Tuy nhiên cách này sẽ không linh hoạt nếu bên số lượngrow
nhiều và theo design thì ở đây cóborder-radius
cho 2 table nên cách này là không dùng được. - Không cần đồng bộ scroll bằng JS: có thể dùng 1 wrapper bọc cả 2 table khi đó cũng scroll đồng bộ được, tuy nhiên mình cũng đã thử nhưng không giữ được
border-radius
nên dùng js có vẻ hợp lý.
2. Table responsive
Table có 2 dạng responsive đó là dạng có scroll và dạng từng list theo hàng. Tuy nhiên đối với table responsive có scroll ngang chỉ nên áp dụng với trường hợp table quá nhiều cột, dù ở PC / laptop không đủ kích thước mới nên xuất hiện. Đối với mobile, table chuyển thành từng hàng như design bên dưới (mình chưa biết thuật ngữ gọi là gì) sẽ phù hợp hơn vì nhìn rõ ràng, không phải scroll ngang gây cảm giác khó chịu.
Table scroll trên màn hình PC (trường hợp quá nhiều cột sẽ xuất hiện scroll)
Table responsive trên màn hình Mobile (chia theo từng hàng, không còn hiển thị theo từng cột nữa)
Ý tưởng thực hiện
- Dựng table cho PC như bình thường
- Responsive
- Ẩn row header của table
- Tạo label của header bằng cách dùng before hoặc after thông qua content
.wrap
.container
table
thead
tr
th Ticket
th Tracker
th Status
th Priority
th Assignee
th Target version
th Due date
th Estimated time
tbody
each item in [1, 2, 3, 4]
tr
//- data-label là attr dùng để hiển thị label khi về mobile
td(data-label='Ticket') #0001
td(data-label='Tracker') Task
td(data-label='Status') Resolved
td(data-label='Priority') Hight
td(data-label='Assignee') Nguyen Huu Khuyen
td(data-label='Target version') Sprint 3
td(data-label='Due date') 06/21/2020
td(data-label='Estimated time') 1616
//-- Những phần tương tự của table trên mình không lặp lại ở đây --
// Chỉ scroll table cho màn hình từ tablet
@media screen and (min-width: 640px) {
td, th {
&:first-child {
position: sticky;
left: 0;
z-index: 9;
}
&:not(:last-child) {
border-right: 1px dotted gray;
}
}
}
@media screen and (max-width: 640px) {
table {
min-width: auto;
// Ẩn header table
thead {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
}
tr {
display: block;
// tạo đường line kết thúc mỗi khối data
&:not(:last-child) {
border-bottom: 2px solid #8e3c78;
}
&:nth-child(even) {
td {
background: #fff;
}
}
td {
display: block;
font-size: 14px;
text-align: right;
border-bottom: 1px solid #ddd;
&:before {
// get value từ attribute 'data-label' để hiển thị
content: attr(data-label);
float: left;
font-weight: bold;
text-transform: uppercase;
}
&:last-child {
border-bottom: 0;
}
}
}
}
}
3. Tổng kết
Trên đây là 2 dạng table tiếp theo sau một loạt bài về table mình vừa gặp, cũng được anh em trong dự án trầm trồ. Hi vọng những tricks trên sẽ giúp mọi người có thể tận dụng được ctrl + c
và ctrl + v
từ code của mình.
All rights reserved