Skip to content

[CSS] 以 Tailwind CSS 排列商品列表的 3 種方式

· 6 min

在電商網頁中,很常見到格狀的商品列表排列,前陣子也有機會碰到這種列表的排版,記錄當時處理的一些小細節~

預期最後的排版方式如下:

預期的排版方式

問題:卡片寬度 + 間隔導致非預期換行#

當時第一時間想到的是列表用 flex,再用 w-1/4給定卡片寬度、gap 處理卡片之間的間隔,程式碼如下(完整程式碼):
(以下程式皆使用 React.js 撰寫,部分樣式與資料參考自Pinkoi

<ul className='flex flex-wrap gap-4'>
{products.map((product) => (
<li className='w-full sm:w-1/2 md:w-1/3 lg:w-1/4' key={product.id}>
...
</li>
))}
</ul>;

但這樣會導致非預期的換行,預期一列要有 4 個商品,實際上一列卻只排了3 個商品,如下圖:

加了 gap 後產生非預期換行QQ

會產生這樣的原因是因為我指定每個商品寬度都是 1/4,又希望商品之間間隔 16px,而導致一列的總寬度超過 100%,因此 flex-wrap 讓多出的商品換行。

為了解決這問題,我研究了以下 3 種解法:

解法一:grid#

gird 應該是處理格狀排版最常見也最直覺的方式了,參考 tailwindui 提供的 Product List components 就可快速排出整齊的商品列表,於是我將原本的程式碼改寫成 grid,主要更動 ul 標籤的 class,程式碼如下(完整程式碼):

<ul className='grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4'>
{products.map((product) => (
<li key={product.id}>
...
</li>
))}
</ul>;

畫面就出現一列 4 個商品的整齊排版啦👏👏👏

另外,為了確認格線有對齊其他元件,多寫了一個“全部商品”的標題,用來確認整體格線是對齊的~以下 2 種解法也都會用這種方式檢查對齊

用 gird 排版,輕鬆又漂亮 :D

解法二:flex + -margin + padding#

如果我還是想要用 flex 排版呢? 我逛了一些電商的網頁,發現另一種寫法,也可能是 grid 還沒那麼普及時用的方法:

一樣用 w-1/4 給定卡片寬度,但在每個 li 寫 padding 向內推擠,產生卡片間的空白間隔,不過這樣列表的左右側會產生多餘的空白,因此整個 ul 列表需要再給一個負值的 margin,讓列表將多的空白回推~示意圖如下:

flex + -margin + padding 示意圖

主要就是在 li 寫 padding,ul 寫 -margin ,程式碼如下(完整程式碼):

<ul className='flex flex-wrap -m-2'>
{products.map((product) => (
<li key={product.id} className='w-full sm:w-1/2 md:w-1/3 lg:w-1/4 p-2'>
...
</li>
))}
</ul>;

畫面就出現一列 4 個商品的整齊排版啦👏👏👏

flex + -margin + padding,小複雜但還是能解決問題 👍

此解法主要是參考嘖嘖的專案探索頁,有興趣的讀者可以點進去看看~截圖他們的樣式如下:

嘖嘖官網就是用 -margin 和 padding 的方式完成卡片排版

補充,其實 Bootstrap 的格線系統也是用 padding 處理間隔的唷,有興趣也可以去官方文件看看。

解法三:flex + gap + basis-calc(寬度-gap)#

解法三其實是解法二的變形,也是我逛到別的網頁發現的解法,這個解法應該最接近一開始我想用的方法:

一樣用 flex 和 gap,但卡片寬度要扣掉 gap 的寬度,讓整體寬度加起來是 100%。公式如下:

卡片寬度- (gap 寬度 * gap數量/一列的卡片數)

舉例來說,如果卡片寬度 25%,gap 寬度 16px,因為一列 4 個卡片會有 3 個 gap,所以每個商品卡片的寬度是 25%-(16*3/4) px

程式碼如下(完整程式碼):

<ul className='flex flex-wrap gap-4'>
{products.map((product) => (
<li
key={product.id}
className='basis-full sm:basis-[calc(50%-(16*1/2*1px))] md:basis-[calc(33%-(16*2/3*1px))] lg:basis-[calc(25%-(16*3/4*1px))]'
>
...
</li>
))}
</ul>;

畫面就出現一列 4 個商品的整齊排版啦👏👏👏

計算寬度小麻煩,但還是能順利解決📏

此解法主要是參考 RHINOSHIELD 的商品列表,有興趣的讀者可以點進去看看,不過有發現他們的寬度沒有考量到 gap 只會在中間有(4 個商品只要扣掉 3 個 gap),因此每列的最右側都會空出空白,一列沒有完全填滿 100%。以md:basis-[calc(100%*4/12–20px)] 為例,應該要改成 md:basis-[calc(100%*4/12–15px)] 才會讓左右都貼齊外層框,讀者可以自己試試看😎

RHINOSHIELD 在扣除 gap 寬度時沒處理好導致右側多出空白QQ

以上就是我在用 Tailwind CSS 排列商品列表時發現的小細節,希望對大家有幫助 :D

如有任何問題歡迎聯絡、不吝指教✍️