使用 CSS columns 佈局來實現自動分組佈局

蓦然JL發表於2024-05-06

最近在專案中碰到這樣一個佈局,有一個列表,先按照 4 * 2 的正常順序排列,當超過 8 個後,會橫向重新開始 4 * 2 的佈局,有點像一個個獨立的分組,然後水平排列,如下

使用 CSS columns 佈局來實現自動分組佈局

圖中序號是 dom 序列,所以其實這這樣的一個順序

使用 CSS columns 佈局來實現自動分組佈局

很多同學可能會想到給子元素分組(透過 JS將原陣列拆分組合成一個二維陣列),每 8 個套一層容器,然後水平排列就行了

使用 CSS columns 佈局來實現自動分組佈局

是不是有點麻煩呢?

其實,無需單獨巢狀容器也能實現類似分組的效果,這就需要藉助本文要介紹的 column 佈局了,一起看看吧\~

一、簡單介紹一下 columns

平時接觸較多的都是flex或者grid,但還有一個columns佈局往往被忽視了。

developer.mozilla.org/z

columns佈局,又稱“多列”佈局(或者“分欄”佈局),這是一個使用場景比較有限,但是幾乎無法被替代的一種佈局。

使用非常簡單,直接看一個例子,假設有這樣一段文字

p{
  width: 500px;
}
<p>歡迎關注前端偵探,這裡有一些有趣的、你可能不知道的HTML、CSS、JS小技巧技巧,比如這篇文章,如何使用 CSS columns 佈局來實現自動分組佈局,一起看看吧</p>

預設是這樣的

下面我們將段文字分成3列

p{
  columns: 3;
}

看,自動就分成了3列

並且閱讀順序是從左到右,從下到下,直到整列閱讀完成,非常類似以前的報刊讀物閱讀習慣。

除了指定列數,還可以根據指定寬度自動去計算列數,比如

p{
  columns: 100px;
}

效果如下

這個表示按照最小100px去分段,看最多可以分成多少列,並不是說每列就一定是 100,應該是大於等於 100,直到剩餘空間可以再放下一列。

那為啥設定的是100,總寬度是500,卻只分成了4列?原因是有預設列間距,如果去除這個間距

p{
  column-gap: 0px;
}

這樣就剛好被分成了5

看不清楚?加個分割線試試

p{
    column-rule: 1px solid red;
}

是不是剛好分成了 5 列?(注意,這裡的分割線是不佔空間的)

簡單瞭解columns多列布局後,下面來看另外的用途

二、columns 實現橫向分組佈局

可能你已經發現了,上面的文字分列布局和我們文章開頭所需要的效果非常類似,都是一列一列的,因此我們可以嘗試用columns佈局來實現這樣的效果

假設html是這樣的

<div class="wrap">
  <div class="list">
    <div class="item">1</div>
    <div class="item">2</div>
    <div class="item">3</div>
    <div class="item">4</div>
    <div class="item">5</div>
    <div class="item">6</div>
    <div class="item">7</div>
    <div class="item">8</div>
    <div class="item">9</div>
    <div class="item">10</div>
    <div class="item">11</div>
    <div class="item">12</div>
    <div class="item">13</div>
    <div class="item">14</div>
  </div>
</div>

這裡多了一層wrap是用來做滾動容器的,簡單修飾一下

.wrap{
  display: flex;
  width: 400px;
  overflow: auto;
  outline: 1px dashed #9747FF;
}
.item{
  display: inline-flex;
  width: 80px;
  margin: 10px;
  aspect-ratio: 1/1;
  background: #FFE8A3;
  color: #333;
  font-size: 30px;
  border-radius: 10px;
  align-items: center;
  justify-content: center;
}

效果如下,很正常的一個佈局

使用 CSS columns 佈局來實現自動分組佈局

現在,我們希望縱向高度是固定的,然後橫向滾動,先加一個高度試試

.list{
  height: 200px;
}

這樣就變成了縱向滾動的佈局了

那麼,如何讓它橫向分欄並且滾動呢?其實非常簡單,只需要新增一行

.list{
  height: 200px;
  column-width: 400px;
}

設定分欄寬度為滾動容器寬度之後,就自動將整個列表分成多組了,相當於每個滾動螢幕作為一組,從左到右排列,由於空間不足,所以可以橫向滾動

使用 CSS columns 佈局來實現自動分組佈局

是不是非常神奇?僅需一個屬性就實現了縱向滾動到橫向滾動的切換

三、藉助 scroll-snap 實現輪播效果

通常碰到這種橫向滾動的效果,你可能會想到一個swiper元件,也就是那種一屏一屏切換的效果,沒錯,我們這裡也可以藉助scroll-snap輕易實現。

關於scroll-snap,網上教程非常多,MDN 官網也有非常清晰的 demo,如果不熟悉的可以先去了解一下:developer.mozilla.org/z

這裡就不詳細介紹了。

回到這裡,由於整個列表下面只有一層子元素,好像並沒有辦法區分每一屏的臨界點。其實不然,可以想一下,這裡每一屏有 8 個元素,也就是第1917...個分別是每一屏的第一個元素,是不是可以以這些元素為標識(吸附物件)呢?

首先要在滾動容器下定義一下

.wrap{
  scroll-snap-type: x mandatory;
}

然後給第1917...個元素新增吸附物件,這裡可以用nth-child選擇器

.item:nth-child(8n+1){
  scroll-snap-align: start;
}

效果如下(為了區分,把每一屏的第一個元素背景做了高亮)

使用 CSS columns 佈局來實現自動分組佈局

四、CSS 實現的優勢和總結

相對於傳統的 JS實現來說,有哪些好處呢?

  1. 少了一層巢狀容器,業務邏輯會更加乾淨
  2. 自適應強,可以根據需求選擇固定列數或者固定寬度,JS往往只能根據數量去分組
  3. 不會報錯,想想看,JS中的陣列經常會出現xxx.slice is not function這樣的錯誤,輕則警告,總則整個頁面白屏
  4. 佈局足夠靈活,想橫向滾動就橫向滾動,想縱向滾動就縱向滾動,而JS方式往往還需要改變陣列形態

有這麼多好處還不趕緊用起來?下面再來回顧一下columns佈局

  1. columns佈局,又稱“多列”佈局(或者“分欄”佈局),可以將預設的文字流輕易分成多欄,非常類似以前的報刊讀物排版
  2. column可以透過寬度(column-width)去自動分割,或者透過指定數量(column-count)將佈局分成多少欄
  3. column-gap可以設定分欄之間的空隙,預設是有間隔的
  4. column-rule可以設定分隔線,這種分割線是不佔據空間的
  5. columns佈局使用場景比較有限,但是幾乎無法被替代

相關文章