1.引子
今天閑逛知名前端資訊站Front-End Front碳锈,發(fā)現(xiàn)一個(gè)比較有意思的效果售碳,給大家分享下贸人,希望可以對(duì)大家有所啟發(fā)艺智。
純CSS實(shí)現(xiàn)表格排序
心急的同學(xué)力惯,先看效果父晶,我放在codepen上甲喝。
本案例用到了以下知識(shí)點(diǎn):
- CSS變量
- Flexbox布局
- grid布局(非必須直撤,可以替代)
因此谋竖,本案例只在現(xiàn)代瀏覽器中運(yùn)行良好蓖乘。
2.核心原理
我們利用Flexbox的方式打破表格布局韧骗,讓表格做Flex容器(container)袍暴,每一行做Flex子項(xiàng)(item)政模,然后利用CSS變量的方式設(shè)置order览徒。
.table-body {
display: flex;
flex-direction: column;
}
.table-row {
order: calc(var(--order) * var(--sort-order, -1));
}
另外习蓬,為了實(shí)現(xiàn)純CSS躲叼,我們用到了input的:checked
偽類模擬實(shí)現(xiàn)單擊枫慷。
#sort-by-published:checked ~ .table > .table-body > .table-row {
--order: var(--order-by-published);
}
#sort-by-views:checked ~ .table > .table-body > .table-row {
--order: var(--order-by-views);
}
#sort-ascending:checked + .table {
--sort-order: 1;
}
3.實(shí)現(xiàn)步驟
3.1 HTML
為了實(shí)現(xiàn)單擊,我們使用input+label的方式調(diào)用:checked
偽類探孝。首先顿颅,我們需要兩組input粱腻。
<!-- :checked實(shí)現(xiàn)單擊,這些input不在網(wǎng)頁中顯示 -->
<!-- name為sort的input捞慌,用來控制排序字段 -->
<input type="radio" name="sort" id="sort-by-name">
<input type="radio" name="sort" id="sort-by-published" checked="checked">
<input type="radio" name="sort" id="sort-by-views">
<!-- name為sort-order的input啸澡,用來控制排序方式锻霎,升序還是降序 -->
<input type="radio" name="sort-order" id="sort-descending" checked="checked">
<input type="radio" name="sort-order" id="sort-ascending">
然后是label旋恼。
<table class="table">
<thead class="table-head">
<tr class="table-row">
<th class="table-cell">
<label class="table-sorter" for="sort-by-name">文章</label>
<label class="table-orderer" for="sort-ascending" data-filtered="filtered">↓</label>
<label class="table-orderer" for="sort-descending" data-filtered="filtered">↑</label>
</th>
<th class="table-cell">
<label class="table-sorter" for="sort-by-published">出版</label>
<label class="table-orderer" for="sort-ascending">↓</label>
<label class="table-orderer" for="sort-descending" data-filtered="filtered">↑</label>
</th>
<th class="table-cell">
<label class="table-sorter" for="sort-by-views">瀏覽</label>
<label class="table-orderer" for="sort-ascending" data-filtered="filtered">↓</label>
<label class="table-orderer" for="sort-descending" data-filtered="filtered">↑</label>
</th>
</tr>
</thead>
<tbody class="table-body">
</tbody>
</table>
接下去是表格主題內(nèi)容。
<tbody class="table-body">
<tr class="table-row" style="--order-by-published: 161021; --order-by-views: 10368;">
<th class="table-cell">Conditions for CSS Variables</th>
<td class="table-cell">2016-10-21</td>
<td class="table-cell">10 368</td>
</tr>
<tr class="table-row" style="--order-by-published: 161221; --order-by-views: 2431;">
<th class="table-cell">Controlling the Specificity</th>
<td class="table-cell">2016-12-21</td>
<td class="table-cell">2 431</td>
</tr>
<tr class="table-row" style="--order-by-published: 180104; --order-by-views: 4463;">
<th class="table-cell">Counters and Stones</th>
<td class="table-cell">2018-01-04</td>
<td class="table-cell">4 463</td>
</tr>
<tr class="table-row" style="--order-by-published: 171128; --order-by-views: 6585;">
<th class="table-cell">Flexible Overflow</th>
<td class="table-cell">2017-11-28</td>
<td class="table-cell">6 585</td>
</tr>
<tr class="table-row" style="--order-by-published: 170627; --order-by-views: 4597;">
<th class="table-cell">Keyboard-Only Focus</th>
<td class="table-cell">2017-06-27</td>
<td class="table-cell">4 597</td>
</tr>
<tr class="table-row" style="--order-by-published: 170531; --order-by-views: 2829;">
<th class="table-cell">Label-to-Input States</th>
<td class="table-cell">2017-05-31</td>
<td class="table-cell">2 829</td>
</tr>
</tbody>
3.2 CSS
/* 關(guān)鍵代碼 */
.table-body {
display: flex;
flex-direction: column;
}
.table-row {
order: calc(var(--order) * var(--sort-order, -1));
}
#sort-by-published:checked ~ .table > .table-body > .table-row {
--order: var(--order-by-published);
}
#sort-by-views:checked ~ .table > .table-body > .table-row {
--order: var(--order-by-views);
}
#sort-ascending:checked + .table {
--sort-order: 1;
}
/* 反向排序 */
#sort-by-name:checked ~ #sort-ascending:checked + .table > .table-body {
flex-direction: column-reverse;
}
以及其他布局和樣式方面的代碼
/* 其他代碼 */
.table-wrapper > input {
position: fixed;
left: 0;
right: 0;
clip: rect(1px,1px,1px,1px);
visibility: hidden;
}
.table,
.table-caption,
.table-head {
display: block;
margin: 0;
}
table,td,th{
border: 1px solid #000;
border-collapse:collapse;
}
a{
text-decoration: none;
color:black;
}
.table-row {
position: relative;
display: grid;
grid-template-columns: 50% 25% 25%;
}
.table-cell {
text-align: right;
padding: 0.25em 0.5em;
white-space: nowrap;
}
.table-cell:first-child {
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
}
.table-orderer {
display: none;
}
.table-head .table-cell {
position: relative;
display: flex;
user-select: none;
}
.table-head .table-cell:hover {
background: rgba(0,0,0,0.05);
}
.table-head .table-cell:not(:first-child) {
flex-direction: row-reverse;
}
.table-sorter:before,
.table-orderer:before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
cursor: pointer;
}
#sort-by-name:checked ~ .table .table-sorter[for=sort-by-name] ~ .table-orderer,
#sort-by-published:checked ~ .table .table-sorter[for=sort-by-published] ~ .table-orderer,
#sort-by-views:checked ~ .table .table-sorter[for=sort-by-views] ~ .table-orderer {
display: inline;
}
#sort-ascending:checked + .table .table-orderer[for=sort-ascending],
#sort-ascending:not(:checked) + .table .table-orderer[for=sort-descending] {
display: none !important;
}
3.3 整體源碼
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>純CSS實(shí)現(xiàn)表格排序-利用CSS 變量和Flexbox</title>
<style type="text/css">
/* 其他代碼 */
.table-wrapper>input {
position: fixed;
left: 0;
right: 0;
clip: rect(1px, 1px, 1px, 1px);
visibility: hidden;
}
.table,
.table-caption,
.table-head {
display: block;
margin: 0;
}
table,
td,
th {
border: 1px solid #000;
border-collapse: collapse;
}
a {
text-decoration: none;
color: black;
}
.table-row {
position: relative;
display: grid;
grid-template-columns: 50% 25% 25%;
}
.table-cell {
text-align: right;
padding: 0.25em 0.5em;
white-space: nowrap;
}
.table-cell:first-child {
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
}
.table-orderer {
display: none;
}
.table-head .table-cell {
position: relative;
display: flex;
user-select: none;
}
.table-head .table-cell:hover {
background: rgba(0, 0, 0, 0.05);
}
.table-head .table-cell:not(:first-child) {
flex-direction: row-reverse;
}
.table-sorter:before,
.table-orderer:before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
cursor: pointer;
}
#sort-by-name:checked~.table .table-sorter[for=sort-by-name]~.table-orderer,
#sort-by-published:checked~.table .table-sorter[for=sort-by-published]~.table-orderer,
#sort-by-views:checked~.table .table-sorter[for=sort-by-views]~.table-orderer {
display: inline;
}
#sort-ascending:checked+.table .table-orderer[for=sort-ascending],
#sort-ascending:not(:checked)+.table .table-orderer[for=sort-descending] {
display: none !important;
}
</style>
</head>
<body>
<div class="table-wrapper">
<!-- :checked實(shí)現(xiàn)單擊,這些input不在網(wǎng)頁中顯示 -->
<input type="radio" name="sort" id="sort-by-name">
<input type="radio" name="sort" id="sort-by-published" checked="checked">
<input type="radio" name="sort" id="sort-by-views">
<input type="radio" name="sort-order" id="sort-descending" checked="checked">
<input type="radio" name="sort-order" id="sort-ascending">
<table class="table">
<thead class="table-head">
<tr class="table-row">
<th class="table-cell">
<label class="table-sorter" for="sort-by-name">文章</label>
<label class="table-orderer" for="sort-ascending" data-filtered="filtered">↓</label>
<label class="table-orderer" for="sort-descending" data-filtered="filtered">↑</label>
</th>
<th class="table-cell">
<label class="table-sorter" for="sort-by-published">出版</label>
<label class="table-orderer" for="sort-ascending">↓</label>
<label class="table-orderer" for="sort-descending" data-filtered="filtered">↑</label>
</th>
<th class="table-cell">
<label class="table-sorter" for="sort-by-views">瀏覽</label>
<label class="table-orderer" for="sort-ascending" data-filtered="filtered">↓</label>
<label class="table-orderer" for="sort-descending" data-filtered="filtered">↑</label>
</th>
</tr>
</thead>
<tbody class="table-body">
<tr class="table-row" style="--order-by-published: 161021; --order-by-views: 10368;">
<th class="table-cell">Conditions for CSS Variables</th>
<td class="table-cell">2016-10-21</td>
<td class="table-cell">10 368</td>
</tr>
<tr class="table-row" style="--order-by-published: 161221; --order-by-views: 2431;">
<th class="table-cell">Controlling the Specificity</th>
<td class="table-cell">2016-12-21</td>
<td class="table-cell">2 431</td>
</tr>
<tr class="table-row" style="--order-by-published: 180104; --order-by-views: 4463;">
<th class="table-cell">Counters and Stones</th>
<td class="table-cell">2018-01-04</td>
<td class="table-cell">4 463</td>
</tr>
<tr class="table-row" style="--order-by-published: 171128; --order-by-views: 6585;">
<th class="table-cell">Flexible Overflow</th>
<td class="table-cell">2017-11-28</td>
<td class="table-cell">6 585</td>
</tr>
<tr class="table-row" style="--order-by-published: 170627; --order-by-views: 4597;">
<th class="table-cell">Keyboard-Only Focus</th>
<td class="table-cell">2017-06-27</td>
<td class="table-cell">4 597</td>
</tr>
<tr class="table-row" style="--order-by-published: 170531; --order-by-views: 2829;">
<th class="table-cell">Label-to-Input States</th>
<td class="table-cell">2017-05-31</td>
<td class="table-cell">2 829</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
4.聲明
愛前端脏里,樂分享迫横。FedFun希望與您共同進(jìn)步番舆。
歡迎任何形式的轉(zhuǎn)載恨狈,煩請(qǐng)注明裝載拴事,保留本段文字圣蝎。
獨(dú)立博客http://whqet.github.io
極客頭條http://geek.csdn.net/user/publishlist/whqet
CSDN博客http://blog.csdn.net/whqet/
我的簡書http://www.reibang.com/u/c11d4318b3c7