動態

詳情 返回 返回

那些你不知道的 CSS 自定義形狀網格佈局 - 動態 詳情

本文翻譯自 CSS Grid and Custom Shapes, Part 1,略有刪改

在正常的開發中,我們會遇到很多元素塊排列對齊的需求,如九宮格抽獎,多張圖片上傳後等分佈局預覽,微信朋友圈多張圖片展示等。這都是正常的正方形很規整的佈局。

如下所示,如果圖像不是完全正方形,而是形狀像六邊形或菱形怎麼辦?我們怎麼做呢。事實上,我們將結合我們已經研究過的 CSS 網格技術,並加入一些 CSS clip-pathmask魔法,為您可以想象的任何形狀創建精美的圖像網格!

相同的HTML

我們將要研究的大多數佈局乍一看似乎很容易實現,但具有挑戰性的部分是使用相同的 HTML 標記來實現它們。我們可以使用很多包裝器、divs 等等,但這篇文章的目標是使用相同且最少的 HTML 代碼,並且仍然可以實現我們想要的所有不同風格的網格。

這就是説,讓我們從以下的HTML開始:

<div class="gallery">
  <img src="..." alt="...">
  <img src="..." alt="...">
  <img src="..." alt="...">
  <img src="..." alt="...">
  <!-- as many times as we want -->
</div>

一個帶有圖像的容器就是我們在這裏所需要的。足已!

六邊形 CSS 網格

這個形狀有時也稱為蜂窩網格。

首先,我們使用clip-path在圖像上使用來創建六邊形形狀,並將它們全部放在同一個網格區域中,以便它們重疊。

.gallery {
  --s: 150px; /* controls the size */
  display: grid;
}

.gallery > img {
  grid-area: 1/1;
  width: var(--s);
  aspect-ratio: 1.15;
  object-fit: cover;
  clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0 50%);
}

![clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0 50%)
](https://files.mdnice.com/user...)

此時所有的圖像都是六邊形並且重疊在一起。所以看起來我們只有一個六邊形的圖像元素,但實際上有七個。下一步將把圖像平移到它們正確放置的網格上。

保留其中一張圖像在中心位置。其餘圖像使用 CSS translate 平移在它周圍。這是我為網格中的每個圖像提出的模擬公式:

translate((height + gap)*sin(0deg), (height + gap)*cos(0))
translate((height + gap)*sin(60deg), (height + gap)*cos(60deg))
translate((height + gap)*sin(120deg), (height + gap)*cos(120deg))
translate((height + gap)*sin(180deg), (height + gap)*cos(180deg))
translate((height + gap)*sin(240deg), (height + gap)*cos(240deg))
translate((height + gap)*sin(300deg), (height + gap)*cos(300deg))

經過一些計算和優化後,我們得到以下最終 CSS

.gallery {
  --s: 150px; /* control the size */
  --g: 10px;  /* control the gap */
  display: grid;
}
.gallery > img {
  grid-area: 1/1;
  width: var(--s);
  aspect-ratio: 1.15;
  object-fit: cover;
  clip-path: polygon(25% 0%, 75% 0%, 100% 50% ,75% 100%, 25% 100%, 0 50%);
  transform: translate(var(--_x,0), var(--_y,0));
}
.gallery > img:nth-child(1) { --_y: calc(-100% - var(--g)); }
.gallery > img:nth-child(7) { --_y: calc( 100% + var(--g)); }
.gallery > img:nth-child(3),
.gallery > img:nth-child(5) { --_x: calc(-75% - .87*var(--g)); }
.gallery > img:nth-child(4),
.gallery > img:nth-child(6) { --_x: calc( 75% + .87*var(--g)); }
.gallery > img:nth-child(3),
.gallery > img:nth-child(4) { --_y: calc(-50% - .5*var(--g)); }
.gallery > img:nth-child(5), 
.gallery > img:nth-child(6) { --_y: calc( 50% + .5*var(--g)); }

每個圖像都由基於這些公式的--_x和變量轉換。--_y只有第二張圖片 ( nth-child(2)) 在任何選擇器中未定義,因為它位於中心。如果您決定使用不同的順序,它可以是任何圖像。這是我使用的順序:

只需幾行代碼,我們就得到了一個很酷的圖像網格。為此,我在圖像上添加了懸停的效果,讓交互效果更上一層樓,代碼在線預覽如下:

https://code.juejin.cn/pen/71...

CSS 菱形網格

菱形是將一個正方形旋轉45度。

還是相同的 HTML,我們首先在 CSS 中定義一個 2×2 的圖像網格:

.gallery {
  --s: 150px; /* controls the size */

  display: grid;
  gap: 10px;
  grid: auto-flow var(--s) / repeat(2, var(--s));
  place-items: center;
}
.gallery > img {
  width: 100%; 
  aspect-ratio: 1;
  object-fit: cover;
}

然後設置旋轉,請注意我如何將它們都旋轉45deg,但方向相反。

.gallery {
  transform: rotate(45deg);
}
.gallery > img {
  transform: rotate(-45deg);
}

向負方向旋轉圖像可防止它們與網格一起旋轉,因此它們保持筆直。現在,我們應用 clip-path 從它們中剪出菱形。

![clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%)
](https://files.mdnice.com/user...)

此時的圖像並沒有按我們的預期的間距排列,我們需要糾正圖像的大小以使它們適合在一起。否則,它們的間距會很遠,以至於看起來不像圖像網格。

圖像在綠色圓圈的邊界內,即放置圖像的網格區域的內切圓。我們想要的是將圖像放大以適合紅色圓圈,即網格區域的外接圓。

.gallery > img {
  width: 141%; /* 100%*sqrt(2) = 141% */
  aspect-ratio: 1;
  object-fit: cover;
  transform: rotate(-45deg);
  clip-path: polygon(50% 0, 100% 50%, 50% 100%, 0 50%);
}

最後,還是給圖像增加懸停的效果,在線代碼如下:
https://code.juejin.cn/pen/71...

三角形的 CSS 網格

你現在可能知道,最大的竅門是找出clip-path我們想要的形狀。對於這個網格,每個元素都有自己的clip-path值,而最後兩個網格使用一致的形狀。所以,這一次,就像我們正在處理幾個不同的三角形形狀,它們組合在一起形成一個矩形的圖像網格。

頂部的三個圖像

底部的三張圖片

我們使用以下 CSS 將它們放置在 3×2 網格中:

.gallery {
  display: grid;
  gap: 10px; 
  grid-template-columns: auto auto auto; /* 3 columns */
  place-items: center;
}
.gallery > img {
  width: 200px; /* controls the size */
  aspect-ratio: 1;
  object-fit: cover;
}
/* the clip-path values */
.gallery > img:nth-child(1) { clip-path: polygon(0 0, 50% 0, 100% 100% ,0 100%); }
.gallery > img:nth-child(2) { clip-path: polygon(0 0, 100% 0, 50% 100%); }
.gallery > img:nth-child(3) { clip-path: polygon(50% 0, 100% 0, 100% 100%, 0 100%); }
.gallery > img:nth-child(4) { clip-path: polygon(0 0, 100% 0, 50% 100%, 0 100%); }
.gallery > img:nth-child(5) { clip-path: polygon(50% 0, 100% 100%, 0% 100%); }
.gallery > img:nth-child(6) { clip-path: polygon(0 0, 100% 0 ,100% 100%, 50% 100%); } }

最終得到的效果如下圖所示:

最後一點是使中間列的寬度等於0消除圖像之間的空間。我們在菱形網格中遇到了同樣的間距問題,但對我們使用的形狀採用了不同的方法:

grid-template-columns: auto 0 auto;

最終的在線代碼如下:

https://code.juejin.cn/pen/71...

比薩形狀的 CSS 網格

基於上面的三角形網格通過添加簡單的border-radius和overflow就可以實現另一個很酷的網格,比薩形狀的 CSS 網格。

拼圖風格的 CSS 網格

這次我們將使用 CSS mask 屬性來使圖像看起來像拼圖。

現在設置網格應該是小菜一碟,所以讓我們把注意力集中在mask上。我們需要兩個漸變來創建最終的拼圖形狀。一個漸變創建一個圓形(綠色部分),另一個漸變創建紅色區域並填充半圓白色區域。

--g: 6px; /* controls the gap */
--r: 42px;  /* control the circular shapes */

background: 
  radial-gradient(var(--r) at left 50% bottom var(--r), green 95%, #0000),
  radial-gradient(calc(var(--r) + var(--g)) at calc(100% + var(--g)) 50%, #0000 95%, red)
  top/100% calc(100% - var(--r)) no-repeat;

兩個變量控制形狀。--g變量控制網格間隙,相對不是最重要的。重要的是考慮間隙之間如何正確放置我們的圓圈,以便在組裝整個拼圖時它們完美重疊。該--r變量則控制拼圖形狀的圓形部分的大小。

然後我們使用相同的 CSS 值並針對不同的位置稍加調整來創建其他三個形狀:

此時整體拼圖形狀好了,但沒有按我們的預期重疊在一起。因為每個圖像都被限制在它所在的網格單元中,所以現在形狀有點混亂是對的:

我們需要通過增加圖像的高度/寬度來創建溢出。從上圖中,我們必須增加第一個和第四個圖像的高度,同時增加第二個和第三個圖像的寬度。您可能已經猜到我們需要使用--r變量來增加它們。

.gallery > img:is(:nth-child(1),:nth-child(4)) {
  width: 100%;
  height: calc(100% + var(--r));
}
.gallery > img:is(:nth-child(2),:nth-child(3)) {
  height: 100%;
  width: calc(100% + var(--r));
}

此時左邊兩張圖片按預期展示了,但默認情況下,我們的圖像要麼在右側(如果我們增加寬度)重疊,要麼在底部(如果我們增加高度)重疊。但這不是我們想要的第二張和第四張圖片。解決方法是在這兩個圖像上使用place-self: end,最後我們的完整代碼如下:

https://code.juejin.cn/pen/71...

最後來一個不一樣的,為保障gif圖加載速度,我將圖片替換成純色圖像,這次我們使用clip-path,因為它是我們可以動畫的屬性,我們只需更新控制形狀的自定義屬性即可獲得很酷的懸停效果。我們設置一個自定義變量控制默認的三角形的角度,在鼠標懸停時設置該變量為0則回到正常的正方形,效果圖如下:

在線代碼如下:
https://code.juejin.cn/pen/71...

最後

本文通過將我們已經瞭解的有關 CSS Grid 的知識與一些附加clip-pathmask魔法相結合,我們能夠製作不同形狀的網格佈局。而且我們每次都使用相同的 HTML 代碼!代碼本身只不過是一個包含少量圖像元素的容器!看完是不是覺得很簡單很神奇呢,有興趣的同學可以自己試試看,興許你能創造出更多有趣的網格圖形。

看到最後如果覺得有用,記得點個贊收藏起來吧,説不定哪天就用上啦。

專注前端開發,分享前端相關技術乾貨,公眾號:南城大前端(ID: nanchengfe)

user avatar wu_cat 頭像 heath_learning 頭像 fennudemantou 頭像 alibabataoxijishu 頭像 shine_zhu 頭像 judei 頭像 ranck 頭像 n7pkpnuy 頭像 zengjingdeshaonian 頭像 dragonir 頭像 qinglong_62898aa51988d 頭像 sigui_5f58bd7ced379 頭像
點贊 12 用戶, 點贊了這篇動態!
點贊

Add a new 評論

Some HTML is okay.