不規則圖形背景排版高階技巧 -- 酷炫的六邊形網格背景圖

来源:https://www.cnblogs.com/coco1s/archive/2022/12/26/17005071.html
-Advertisement-
Play Games

今天,收到一個很有意思的提問,如何實現類似如下的背景效果圖: 嗯?核心主體是由多個六邊形網格疊加形成。 那麼我們該如何實現它呢?使用純 CSS 能夠實現嗎? 當然可以,下麵我們就將嘗試如何使用 CSS 去實現這樣一個背景效果。 如何繪製六邊形? 首先,看到這樣一個圖形,如果想要使用一個標簽完成整個背 ...


今天,收到一個很有意思的提問,如何實現類似如下的背景效果圖:

嗯?核心主體是由多個六邊形網格疊加形成。

那麼我們該如何實現它呢?使用純 CSS 能夠實現嗎?

當然可以,下麵我們就將嘗試如何使用 CSS 去實現這樣一個背景效果。

如何繪製六邊形?

首先,看到這樣一個圖形,如果想要使用一個標簽完成整個背景,最先想到的肯定是使用背景 background 實現,不過可惜的是,儘管 CSS 中的 background 非常之強大,但是沒有特別好的方式讓它足以批量生成重覆的六邊形背景。

因此,在這個需求中,我們可能不得不退而求其次,一個六邊形實現使用一個標簽完成。

那麼,就拿 1 個 DIV 來說,我們有多少實現六邊形的方式呢?這裡簡單介紹 2 種方式:

  • 使用 border 實現六邊形
  • 使用 clip-path 實現六邊形

使用 border 或者 clip-path 實現六邊形

首先,使用 border 實現六邊形。這裡的核心在於上下兩個三角形疊加中間一個矩形。這裡,利用元素的兩個偽元素實現上下兩個三角形,從而讓這個元素看起來像一個六邊形。

思路比較簡單,直接上代碼:

.hexagon {
  position: relative;
  width: 200px;
  height: 100px;
  background-color: red;
}

.hexagon:before,
.hexagon:after {
  content: "";
  position: absolute;
  width: 0;
  height: 0;
  border-left: 100px solid transparent;
  border-right: 100px solid transparent;
}

.hexagon:before {
  bottom: 100%;
  border-bottom: 50px solid red;
}

.hexagon:after {
  top: 100%;
  border-top: 50px solid red;
}

上面的代碼會創建一個寬度為 200 像素,高度為 100 像素的六邊形,其中由兩個三角形和一個矩形組成。使用偽元素的優點是可以很方便地控制六邊形的大小、顏色等樣式。

當然,上述的代碼不是一個正六邊形,這是因為正六邊形中,元素的高是元素的寬的 1.1547 倍

並且,上述的方式也稍微複雜了點,因此,在今天,我們更推薦使用 clip-path 的方式去實現一個六邊形:

.clippath {
    --w: 100px;
    width: var(--w);
    height: calc(var(--w) * 1.1547);
    clip-path: polygon(0% 25%, 0% 75%, 50% 100%, 100% 75%, 100% 25%, 50% 0%);
    background: deeppink;
    margin: auto;
}

這樣,基於 clip-path,也能快速得到一個六邊形圖形:

CodePen Demo -- Two ways to achieve a hexagon

繪製多個六邊形背景

好了,有了上一步的鋪墊之後,接下來我們要做的,就是繪製多個六邊形,組成背景。

但是我們仔細觀察一下由多個六邊形組成的背景,會發現每雙數行的的六邊形,需要向右側有一個明顯的縮進,寬度大概為單個六邊形的寬度的一半:

這裡其實是一個非常棘手的問題。首先,我們會想到這樣一種解決方案:

  1. 每一行為一組,設置一個父 div 容器,填滿六邊形元素,設置元素不換行
  2. 給偶數行設置一個固定的 margin-left

基於這個策略,我們的代碼,大概會是這樣:

<div class="container">
    <div class="wrap">
    // ... 填滿六邊形
    </div>
    <div class="wrap" style="margin-left: 25px">
    // ... 填滿六邊形
    </div>
    <div class="wrap">
    // ... 填滿六邊形
    </div>
    <div class="wrap" style="margin-left: 25px">
    // ... 填滿六邊形
    </div>
</div>

可以看到,我們給偶數行,都添加了一個 margin-left

但是這個代碼,會有幾個問題:

  1. 我們的頁面寬度不一定是固定的,那麼每一行設置多少個子六邊形元素比較合適呢?設置多了勢必會帶來浪費,少了又無法滿足需求
  2. 多了一層嵌套,代碼邏輯更為複雜

什麼意思呢?也就是效果可能在屏幕非常寬的情況下,失效。

看看,正常情況,我們設置了每行 20 個六邊形,下圖是正常的

但是如果我們的屏幕特別寬,那麼,可能會得到這樣一種效果:

因此,這種方式存在非常大的弊端,我們希望能有一整佈局方式,能夠滿足我們如下兩個訴求:

  1. 所有六邊形代碼寫在一個父容器下
  2. 這個彈性佈局中,第二行的元素最左邊,能夠實現固定一個縮進

仔細思考一下,CSS 中有能夠實現類似佈局的方法麽?

妙用 shape-outside 實現隔行錯位佈局

有的!在 CSS 中,有一個神奇的元素能夠讓元素以非直線形式排布。它就是 shape-outside

如果你對 shape-outside 不太瞭解,也可以先看看我的這篇文章 -- 奇妙的 CSS shapes

shape-outside 是 CSS 中的一個屬性,用於控制元素的浮動方式。它允許你定義一個元素浮動時周圍元素的形狀。例如,你可以使用 shape-outside 屬性來定義一個元素浮動時周圍元素的形狀為圓形、六邊形等。

它和 clip-path 的語法非常類似,很容易觸類旁通。看看實例,更易理解:

假設我們有下麵這樣的結構存在:

<div class="container">
    <div class="shape-outside">
      <img src="image.png">
    </div>
    xxxxxxxxxxx,文字描述,xxxxxxxxx
</div>

定義如下 CSS:

.shape-outside {
    width: 160px;
    height: 160px;
    shape-outside: circle(80px at 80px 80px);
    float: left;
}

註意,上面 .shape-outside 使用了浮動,並且定義了 shape-outside: circle(80px at 80px 80px) ,表示在元素的 (80px, 80px) 坐標處,生成一個 80px 半徑的圓。

如此,將會產生一種圖文混排的效果:

CodePen Demo -- 圖文混排 shape-outside

總得來說,shape-outside 有兩個核心特點:

  1. shape-outside 屬性僅在元素定義了 float 屬性且不為 none 時才會生效
  2. 它能夠實現了文字根據圖形的輪廓,在其周圍排列

shape-outside 的本質

劃重點,劃重點,劃重點。

所以,shape-outside 的本質其實是生成幾何圖形,並且裁剪掉其幾何圖形之外周圍的區域,讓內容能排列在這些被裁剪區域之內

所以,瞭解了這個本質之後,我們再將他運用在上面的六邊形佈局之中。

為了方便理解,我們首先使用文字代替上面的六邊形,假設我們有這樣一段文本內容:

<p>
Lorem ipsum dolor sit amet conse...
</p>
p {
    line-height: 36px;
    font-size: 24px;
}

非常平平無奇的一段代碼,效果如下:

現在,我們想利用 shape-outside,讓文本內容的偶數行,向內縮進 24px,怎麼實現呢?非常簡單:

p {
    position: relative;
    line-height: 36px;
    font-size: 24px;

    &::before {
        content: "";
        height: 100%;
        width: 24px;
        shape-outside: repeating-linear-gradient(
            transparent 0,
            transparent 36px,
            #000 36px,
            #000 72px
        );
        float: left;
    }
}

這樣,我們就實現了文字隔行縮進 24px 的效果:

一定有小伙伴會很好奇,為什麼呢?核心在於我們利用元素的偽元素實現了一個 shape-outside 圖形,如果我們把這個圖形用 background 繪製出來,其實它長這樣:


p {
    position: relative;
    line-height: 36px;
    font-size: 24px;

    &::before {
        content: "";
        height: 100%;
        width: 24px;
        shape-outside: repeating-linear-gradient(
            transparent 0,
            transparent 36px,
            #000 36px,
            #000 72px
        );
        float: left;
        background: repeating-linear-gradient(
            transparent 0,
            transparent 36px,
            #f00 36px,
            #f00 72px
        );
    }
}

效果如下:

因為文本的行高是 36px,這樣我們以 72 為一段,每 36px 繪製一段透明,另外 36px 繪製一段寬為 24px 的內容,這樣,結合 shape-outside 的特性,我們就實現了隔行將內容向裡面擠 24px 的效果!

非常的 Amazing 的技巧!完整的代碼你可以戳這裡:

CodePen Demo -- Shape-outside achieves even line indentation

基於這個技巧,我們就可以實現上述我們想要的效果了。我們回到正題,重新實現一個充滿六邊形的背景:

<ul class="wrap">
  <li></li>
  //... 非常多個 li
<ul>
:root {
  --s: 50px;  /* size  */
  --m: 4px;    /* margin */
  --perHeight: calc(calc(var(--s) * 2 * 1.1547) + calc(var(--m) * 4) - 0.4px)
}

.wrap {
    position: relative;
    height: 100%;
    font-size: 0;

    &::before {
        content: "";
        height: 100%;
        width: 27px;
        shape-outside: repeating-linear-gradient(
            transparent 0,
            transparent 70px,
            #000 70px,
            #000 var(--perHeight)
        );
        float: left;
    }
}

li {
    width: var(--s);
    height: calc(var(--s) * 1.1547); 
    background: #000;
    clip-path: polygon(0% 25%, 0% 75%, 50% 100%, 100% 75%, 100% 25%, 50% 0%);
    margin: var(--m);
    display: inline-block;
}

藉助 shape-outside,我們就實現了隔行讓我們的六邊形向內縮進的訴求!效果如下:

當然,有一些優化點:

  1. 為了讓兩邊不那麼空,我們可以讓整個容器更寬一點,譬如寬度為父元素的 120%,然後水平居中,這樣,兩側的留白就解決了
  2. 讓兩行直接貼緊,可以設置一個 margin-bottom

做完這兩點優化之後,效果如下:

可以做到任意屏幕寬度下的六邊形完美平鋪佈局:

完整的代碼你可以戳這裡:CodePen Demo -- Hexagon Layout

配置上色彩變換

有了上述的鋪墊後,要實現文章一開頭的效果就不難了。

是的,我們要實現這樣一個效果:

如何讓它們動態的實現顏色變換呢?是給每一個六邊形一個單獨的顏色,然後進行動畫嗎?不,藉助混合模式,我們可以非常快速的實現不同的顏色值。

首先,我們將上述效果,改成白底黑色六邊形色塊:

然後,利用父容器剩餘的一個偽元素,我們疊加一層漸變層上去:

.wrap {
    position: relative;
    // 代碼與上述保持一致

    &::before {
        content: "";
        // ... 實現 shape-outside 功能,代碼與上述保持一致
    }
    
    &::after {
        content: "";
        position: absolute;
        inset: 0;
        background: linear-gradient(45deg, #f44336, #ff9800, #ffe607, #09d7c4, #1cbed3, #1d8ae2, #bc24d6);
    }
}

這樣,我們就疊加了一層漸變色彩層在原本的六邊形背景之上:

接著,只需要一個混合模式 mix-blend-mode: darken,就能實現六邊形色塊與上層漸變顏色的融合效果:

.wrap {
    position: relative;
    // 代碼與上述保持一致

    &::before {
        content: "";
        // ... 實現 shape-outside 功能,代碼與上述保持一致
    }
    
    &::after {
        content: "";
        position: absolute;
        inset: 0;
        background: linear-gradient(45deg, #f44336, #ff9800, #ffe607, #09d7c4, #1cbed3, #1d8ae2, #bc24d6);
        z-index: 1;
      + mix-blend-mode: darken;
    }
}

效果如下:

好, 我們再給上層的漸變色塊,添加一個 filter: hue-rotate() 動畫,實現色彩的漸變動畫:

.wrap {
    position: relative;
    // 代碼與上述保持一致

    &::before {
        content: "";
        // ... 實現 shape-outside 功能,代碼與上述保持一致
    }
    
    &::after {
        content: "";
        position: absolute;
        inset: 0;
        background: linear-gradient(45deg, #f44336, #ff9800, #ffe607, #09d7c4, #1cbed3, #1d8ae2, #bc24d6);
        z-index: 1;
        mix-blend-mode: darken;
      + animation: change 10s infinite linear;
    }
}
@keyframes change {
    100% {
        filter: hue-rotate(360deg);
    }
}

這樣,我們就完美的實現了我們想要的效果:

完整的代碼,你可以戳這裡:CodePen Demo -- Hexagon Gradient Layout

擴展延伸

當然,有了這個基礎圖形之後,其實我們可以基於這個圖形,去做非常多有意思的效果。

下麵我是嘗試的一些效果示意,譬如,我們可以將顏色放置在六邊形背景的下方,製作這樣一種效果:

CodePen Demo -- Hexagon Gradient Layout

配合 mask 的蒙版效果及滑鼠定位,我們還能實現這樣一種有趣的交互效果:

CodePen Demo -- Hexagon Gradient & MASK Layout

當然,3D 效果也不在話下:

CodePen Demo -- 3D Hexagon Gradient Layout

最後

好了,本文到此結束,希望本文對你有所幫助

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 摘要:Spring框架對JDBC的簡單封裝。提供了一個JDBCTemplate對象簡化JDBC的開發。 本文分享自華為雲社區《Spring JdbcTemplate使用解析》,作者: 共飲一杯無 。 Spring框架對JDBC的簡單封裝。提供了一個JDBC Template對象簡化JDBC的開發 步 ...
  • 大數據時代,NoSQL資料庫是企業構建數據能力的核心工具之一。近期,在2022騰訊全球數字生態大會NoSQL資料庫專場上,騰訊雲發佈了多項NoSQL產品能力升級,並重點講解了其背後的自研技術要點及實現細節,分享了騰訊雲NoSQL為廣大企業提供的高可靠、高效率、低成本的企業級特性及行業解決方案。 開場 ...
  • 雖然說 MongoDB 是無模式的,但實際上模式設計在 MongoDB 中也非常重要。在實際開發中,大多數性能問題都可以追溯到糟糕的模式設計。 ...
  • 本文根據digoal(德哥)在〖2019 DAMS中國數據智能管理峰會〗現場演講內容整理而成。 講師介紹 digoal(德哥),PostgreSQL中國社區發起人之一、常委、兼任社區大學校長。阿裡雲資料庫首席專家團隊成員,提供資料庫首席專家服務。現任職於阿裡雲資料庫團隊,主要負責阿裡雲Postgre ...
  • 移動設備硬體的高速發展,讓游戲行業發生翻天覆地的變化,許多酷炫的游戲效果不再局限於電腦端,玩家在移動端就能享受到場景更逼真、畫質更清晰、體驗更流暢的游戲服務。但由於移動設備算力不足,為了實現真實感的水體效果,很多游戲廠商採用預計算的方法減少實時模擬的計算開銷,但水體場景在移動端的流體效果仍然不佳。 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 前段時間,對部門的個別項目進行Vue3.0+ts框架的遷移,剛開始研究的時候也是踩坑特別多,尤其我們的項目還有些特殊的webpack配置,所以,研究vue.config.js的配置的時候也是查閱了各種資料文檔,最終,完成了項目webpac ...
  • 在 JavaScript 中,有時候你可能會發現 0.1+0.2 不等於 0.3。這是因為 JavaScript 使用的是浮點數來表示小數,而浮點數在電腦內部是用二進位表示的,這導致了一些精度問題。 ...
  • 在 JavaScript 中,巨集任務和微任務是指在執行代碼的過程中的兩種不同的任務類型。 巨集任務(macro task)指的是瀏覽器在執行代碼的過程中會調度的任務,比如事件迴圈中的每一次迭代、setTimeout 和 setInterval 等。巨集任務會在瀏覽器完成當前同步任務之後執行。 微任務(m... ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...