CSS grid 布局如何添加分隔線?
分享一些超級實用的布局小技巧。
平時開發(fā)過程中會碰到各式各樣的布局,如下是一個7* N
的網(wǎng)格布局,不過每一行還有一條分隔線。
image-20250419142949987
這種布局該如何實現(xiàn)呢?
一、grid 布局結(jié)構(gòu)與局限
這里的內(nèi)容都是后端返回的,通常是一個完整的一維數(shù)組。
const list =[
{...},
{...},
//...
]
眾所周知,grid
是二維布局,可以在扁平dom
結(jié)構(gòu)下直接實現(xiàn)網(wǎng)格布局。
<div class="grid">
<div class="grid-item">1</div>
<div class="grid-item">2</div>
<div class="grid-item">3</div>
<div class="grid-item">4</div>
<div class="grid-item">5</div>
<div class="grid-item">6</div>
<div class="grid-item">7</div>
<div class="grid-item">8</div>
...
</div>
然后設(shè)置grid
樣式:
.grid{
display: grid;
grid-template-columns:repeat(7,1fr);
width:300px;
padding:10px;
border:1px solid #ccc;
border-radius:5px;
margin:20px auto;
}
效果如下,很方便就實現(xiàn)一個網(wǎng)格布局。
image-20250419150527200
由于每一行還有一條單獨(dú)的分隔線,看似好像無法處理?畢竟 grid
沒有所謂的行選擇器
。
這時,很多同學(xué)可能會單獨(dú)給每一行包一層,合成一個二維數(shù)組。
const grouplist =[
[{...},{...},{...},{...},{...},{...},{...}],// 每一行7個
//...
]
自然dom
結(jié)構(gòu)也需要包裹一層,然后給每一行單獨(dú)樣式。
<div class="list">
<div class="col"><!--設(shè)置樣式-->
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
</div>
<div class="col"> ...</div>
</div>
雖然也能實現(xiàn),但還是有些繁瑣,也不夠優(yōu)雅。
那么,有沒有辦法在不嵌套的情況實現(xiàn)分隔線呢?
二、使用漸變實現(xiàn)
我們可以直接繪制重復(fù)平鋪的漸變,原理其實也很簡單。
假設(shè)每一行的高度固定為--size
,那么我們需要繪制一條從透明到實色的漸變,線條的高度是1px
,然后背景尺寸是--size
,這樣漸變就會自動平鋪,形成我們所需的網(wǎng)格線效果,原理如下:
image-20250425193050298
用代碼實現(xiàn)就是:
.grid{
/**/
--size:54px;
background:linear-gradient(transparent0calc(var(--size)-1px),red)01px/100%var(--size);
}
效果是這樣的:
image-20250425193448881
看著好像和每一行沒對齊?
其實是因為我們設(shè)置了padding
,漸變會默認(rèn)從padding-box
開始平鋪,也就是起始點是從內(nèi)邊距開始的,所以我們要改變一下,讓他從內(nèi)容盒子開始。
.grid{
background-origin: content-box;
}
效果如下:
image-20250425193710051
對齊了,但是上下多了兩條,有沒有什么辦法去掉呢?
還是盒子的問題,漸變默認(rèn)會充滿padding-box
,也需要改一下。
.grid{
background-clip: content-box;
}
這樣上右左,只要在padding
區(qū)域的漸變都被裁剪了,不過地下還是有一條線。
image-20250425193934087
因為剛好處于平鋪的最下方,仍然位于content-box
內(nèi),所以沒有被裁掉,那有沒有辦法去掉呢?
其實將整個容器的高度減少1個像素就可以讓下方的線條出去了,不過試了幾種方式都不能很好解決,沒辦法,我們將這層背景繪制在一個單獨(dú)的偽元素上,使用偽元素可以方便的控制尺寸,也無需改變padding-box
了。
.grid::before{
content:'';
position: absolute;
inset:10px10px11px;/*底部多一像素*/
background:linear-gradient(transparent0calc(var(-- size)-1px),red)00/100%var(--size);
pointer-events: none;
}
這樣就完美實現(xiàn)了。
image-20250425200529835
你也可以訪問在線demo真實體驗:https://codepen.io/xboxyan/pen/azzWGYM[1]。
不過這種方式要求每一行高度是固定,提前算好的,如果每一行的高度會發(fā)生變化就不適用了。
三、用上下border實現(xiàn)
我們可以給每個子元素設(shè)置上邊框來實現(xiàn)分隔線效果。
.grid-item{
border-top:1px solid #ccc
}
缺點很明顯,第一行是多余的,而且當(dāng)最后一行不足時,邊框就斷開了,效果如下:
image-20250419151636163
我們可以換個方向,用下邊框?qū)崿F(xiàn)。
.grid-item{
border-bottom:1px solid #ccc
}
稍微好點了,只是最后一行有點多余,效果如下:
image-20250419151952511
如何把最后的尾巴去掉呢?也就是如何選中grid
布局的最后一行?
這里可以一一列舉,比如當(dāng)最后一行只有一個元素時(其實是「最后一個元素并且是每一行的第一個,需同時滿足」)。
.grid-item:last-child:nth-child(7n+1){
border: none
}
同時滿足這兩個條件即可確定是最后一行的第一個, 示意如下:
image-20250421101716395
然后是最后一行只有兩個元素(「倒數(shù)第二個元素并且是每一行的第一個」)。
.grid-item:nth-last-child(2):nth-child(7n+1),
.grid-item:nth-last-child(2):nth-child(7n+1)~.grid-item{
border: none
}
示意如下:
image-20250421101909227
依次類推,完整選擇器代碼是:
/*1*/
.grid-item:last-child:nth-child(7n+1),
/*2*/
.grid-item:nth-last-child(2):nth-child(7n+1),
.grid-item:nth-last-child(2):nth-child(7n+1)~.grid-item,
/*3*/
.grid-item:nth-last-child(3):nth-child(7n+1),
.grid-item:nth-last-child(3):nth-child(7n+1)~.grid-item,
/*4*/
.grid-item:nth-last-child(4):nth-child(7n+1),
.grid-item:nth-last-child(4):nth-child(7n+1)~.grid-item,
/*5*/
.grid-item:nth-last-child(5):nth-child(7n+1),
.grid-item:nth-last-child(5):nth-child(7n+1)~.grid-item,
/*6*/
.grid-item:nth-last-child(6):nth-child(7n+1),
.grid-item:nth-last-child(6):nth-child(7n+1)~.grid-item,
/*7*/
.grid-item:nth-last-child(7):nth-child(7n+1),
.grid-item:nth-last-child(7):nth-child(7n+1)~.grid-item{
border:0;
}
這樣就能選中最后一行行了,雖然看著很多(別急,后面還有其他方案),但是效果很不錯。
image-20250419154146111
還有其他情況也表現(xiàn)完美。
image-20250419154215435
你也可以訪問在線demo真實體驗:https://codepen.io/xboxyan/pen/PwwqLXM[2]。
四、借助偽元素實現(xiàn)
上面雖然能夠?qū)崿F(xiàn),也非常靈活,如果僅僅是實現(xiàn)分隔線,其實還有另外更巧妙的方案。
還是前面的結(jié)構(gòu),我們可以給每一行的第一個元素添加一個偽元素,用偽元素實現(xiàn)分隔線。
.grid-item:nth-child(7n+1)::before{
content:'';
display: block;
height:1px;
background-color:#ccc;
}
效果如下:
image-20250419160711227
看著好像相差甚遠(yuǎn)?沒關(guān)系,我們可以使用絕對定位,需要注意的是,我們需要讓偽元素貫穿整行,所以要給外層添加相對定位。
.grid{
position: relative;
}
.grid-item:nth-child(7n+1)::after{
content:'';
position: absolute;
left:10px;/*只設(shè)置水平方向定位*/
right:10px;
height:1px;
background-color:#ccc;
}
注意這里只設(shè)置了水平方向上的定位(left
和right
),垂直方向上仍然保持原位,我稱之為「不完全絕對定位」,效果如下:
image-20250419160947752
由于不能使用垂直方向定位,這里就用transform
實現(xiàn),然后可以用:not
排除掉第一行的元素,具體實現(xiàn)如下:
.grid-item:nth-child(7n+1):not(:first-child)::after{
/*...*/
transform:translateY(-15px);
}
效果就很完美了,實現(xiàn)也比較簡單。
image-20250419161739021
你也可以訪問在線demo真實體驗:https://codepen.io/xboxyan/pen/dPPoLYa[3]
四、總結(jié)一下
以上就本文的全部內(nèi)容了,非常實用的布局小技巧,其實都是選擇器的實際運(yùn)用,你學(xué)會了嗎?下面總結(jié)一下:
grid
布局無法直接選擇行- 嵌套的方式實現(xiàn)分隔線有些繁瑣,不夠優(yōu)雅
- 漸變可以很方便的實現(xiàn)平鋪的線條
- 默認(rèn)情況下,漸變會從
padding-box
開始平鋪,也會充滿整個padding-box
- 使用偽元素可以方便的控制尺寸,可以無需改變
padding-box
來控制漸變的起始點,也能控制漸變的平鋪區(qū)域 grid
布局最后一行可以一一列舉處理,比如當(dāng)最后一行只有一個元素時其實是「最后一個元素并且是每一行的第一個」- 最后一行只有兩個元素的條件是「倒數(shù)第二個元素并且是每一行的第一個」
- 還可以借助偽元素的不完全絕對定位貫穿整行