【動畫進階】單標簽下多色塊隨機文字隨機顏色動畫

来源:https://www.cnblogs.com/coco1s/archive/2023/10/31/17799658.html
-Advertisement-
Play Games

我的小冊 《CSS 技術揭秘與實戰通關》上線了,想瞭解更多有趣、進階、系統化的 CSS 內容,可以猛擊 - LINK。 在 CSS 還原拉斯維加斯球數字動畫 - 掘金 一文中,我們利用純 CSS,實現了一個非常 Amazing 的動畫效果: 其中一個核心點就是,我們利用瞭如下的代碼,在一個 DIV ...


我的小冊 《CSS 技術揭秘與實戰通關》上線了,想瞭解更多有趣、進階、系統化的 CSS 內容,可以猛擊 - LINK

CSS 還原拉斯維加斯球數字動畫 - 掘金 一文中,我們利用純 CSS,實現了一個非常 Amazing 的動畫效果:

其中一個核心點就是,我們利用瞭如下的代碼,在一個 DIV 平面內,實現了單個平面下的隨機文字隨機顏色效果。

效果如下:

其中的 HTML 代碼大致如下:

<div class="g-container">
  <div></div>
  // ... 一個 32 個子 div
  <div></div>
</div>

這裡為了實現上述效果,其實是用了 32 列,每列是一個 DIV。

emmm,對於追求極致的我們,32 個 DIV 確實不太優雅了。那麼,CSS 有沒有什麼方式,能夠單個標簽實現多列多格子,每個格子顏色不一致呢?像是這樣:

答案當然是可以。本文,我們就將一起來探尋,使用 CSS 如何實現單標簽下多色塊,及單標簽下隨機文字隨機顏色動畫效果。

多重背景的威力

思考一下,單個 DIV,我們如何能夠實現下述效果呢,譬如一個 DIV 內,有 36 種不同的顏色:

這裡的核心,其實就是需要藉助多重背景。

正常而言,我們的 DIV 只能有一個 background,設置一種顏色,像是這樣:

<div></div>
div {
    width: 300px;
    height: 300px;
    background: #000;
}

效果如下:

但是,合理利用漸變語法的規則,利用多重漸變,我們就可以實現多重背景,我們改造一些上述代碼:

div {
    position: relative;
    margin: auto;
    width: 300px;
    height: 300px;
    background-image: 
        linear-gradient(90deg, #000, #000),
        linear-gradient(90deg, #f00, #f00);
    background-size: 50% 100%, 50% 100%;
    background-position: 0 0, 150px 0;
    background-repeat: no-repeat;
}

利用多重背景的能力,我們就得到了黑色和紅色兩個色塊:

我們還可以繼續拆分,1 拆 4:

div {
    position: relative;
    margin: auto;
    width: 300px;
    height: 300px;
    background-image: 
        linear-gradient(90deg, #000, #000),
        linear-gradient(90deg, #0f0, #0f0),
        linear-gradient(90deg, #00f, #00f),
        linear-gradient(90deg, #f00, #f00);
    background-size: 50% 50%, 50% 50%, 50% 50%, 50% 50%;
    background-position: 0 0, 150px 0, 0 150px, 150px 150px;
    background-repeat: no-repeat;
}

效果如下:

它其實是這麼個意思,看下麵這張圖就能很好的理解:

這裡我們只標識出了黑色色塊和紅色色塊,另外兩個色塊的原理也是一樣的。

理解了這一點之後,我們要實現如下這個圖形就非常輕鬆了:

當然,這裡有個問題,我們手動去寫那麼多重漸變的代碼,工作量是非常之大的,因此,我們可以嘗試封裝一個 SCSS 函數或者 mixin 幫助我們減輕代碼量。

@use "sass:string";


@function randomNum($max, $min: 0, $u: 1) {
    @return ($min + random($max)) * $u;
}

@mixin randomLinear($rows: 6, $cols: 8) {
  $bg: null;
  $pos: null;

  $px: 100% / ($cols - 1);
  $py: 100% / ($rows - 1);

  @for $i from 0 through $rows - 1 {
    @for $j from 0 through $cols - 1 {
      @if ($bg) {
        $bg: $bg + string.unquote(",");  
        $pos: $pos + string.unquote(",");  
      }
      $color: randomColor();
      $bg: $bg + linear-gradient(to right, $color, $color);
      $pos: $pos + string.unquote("#{$j * $px} #{$i * $py}");
    }
  }
  background: {
    image: $bg;
    size: (100% / $cols) (100% / $rows);
    repeat: no-repeat;
    position: $pos;
  }
}

@function randomColor() {
    @return rgb(randomNum(205, 50), randomNum(255), randomNum(255));
}

div {
    @include randomLinear(6, 6);
}

這裡,我們藉助 SCSS 封裝了一個 randomLinear 的 mixin,它接收兩個參數,分別表示行數和列數,基於上面的 background 拆分,實現了多重漸變,如此一來,我們就能在單個 DIV 下得到這樣一個隨機的多色塊格子圖:

審查元素,SCSS 編譯後的 CSS 代碼其實就是這樣的:

好,在此基礎上要實現顏色的隨機變化也非常簡單,我們只需要配合 filter: hue-rotate() 變換即可。

代碼如下:

div {
    @include randomLinear(6, 6);
    animation: colorChange 1s infinite steps(10);
}

@keyframes colorChange {
    100% {
        filter: hue-rotate(360deg);
    }
}

這裡巧妙的利用了 steps(10),讓整個圖形在 1s 內進行 10 次 hue-rotate() 變化。

這裡的核心點有兩個:

  1. 利用 filter: hue-rotate(360deg) 濾鏡,能夠實現顏色的切換
  2. 利用 steps(10) 實現了逐幀動畫而不是連續的補間動畫

如此一來,我們就能得到如下效果,實現了單個標簽內多個不同色塊,並且可以實現動畫變換

結合 background-clip: text 實現文字效果

接下來,我們需要實現單個標簽下的隨機文字、隨機顏色的動畫效果。也就是下圖右邊的效果:

有了上面的鋪墊,其實整個效果就剩下兩步:

  1. 利用 background-clip: text 實現從色塊到文字的裁剪變化
  2. 藉助 SCSS 函數及 CSS 變數,實現隨機文字的變化

首先,與 CSS 還原拉斯維加斯球數字動畫 - 掘金 一文中一樣,藉助 SCSS 函數,編寫一個隨機字元的函數,通過元素的偽元素 content 進行設置,並且,我們把背景色,也設置給元素的偽元素:

$str: 'QWERTYUIOPASDFGHJKLZXCVBNMabcdefghigklmnopqrstuvwxyz123456789';
$length: str-length($str);

@function randomChar() {
    $r: random($length);
    @return str-slice($str, $r, $r);
}

@function randomChars($number) {
    $value: '';

    @if $number > 0 {
        @for $i from 1 through $number {
            $value: $value + randomChar();
        }
    }
    @return $value;
}

div  {
    width: 300px;
    height: 300px;
    font-size: 50px;
    line-height: 50px;
    letter-spacing: 25px;
    word-wrap: break-word;
    font-family: monospace;
    
    &::before {
        content: randomChars(36);
        position: absolute;
        inset: 0;
        @include randomLinear(6, 6);
        color: transparent;
    }
}

這裡,有幾個細節點再簡單講解一下:

  1. 為了讓每個字元對齊,我們使用了 font-family: monospace 等寬字元,並且利用 font-sizeletter-spacing 確保一行只能放下 6 個字元
  2. 利用 randomChars SCSS 函數,隨機從我們定義的 $str SCSS 字元串變數中取 36 個隨機字元
  3. @include randomLinear(6, 6) 就是上面鋪墊的隨機漸變背景

如此一來,我們就能得到這麼一個效果:

此時,我們只需要再給元素的偽元素設置一個 background-clip: text 配合文字顏色 transparent,即可得到色塊裁剪到只剩下文字部分的效果:

div  {
    // ...
    
    &::before {
        //...
        color: transparent;
        background-clip: text;
    }
}

效果如下:

好,那如何再讓整個文字隨機變換起來呢?我們只需提前生成多個不同的隨機文字 content,然後進行動畫切換即可,像是這樣:

div  {
    // ...
    
    &::before {
        content: randomChars(36);
        --content1: "#{randomChars(36)}";
        --content2: "#{randomChars(36)}";
         --content3: "#{randomChars(36)}";
        --content4: "#{randomChars(36)}";
        --content5: "#{randomChars(36)}";
        --content6: "#{randomChars(36)}";
        --content7: "#{randomChars(36)}";
        --content8: "#{randomChars(36)}";
        --content9: "#{randomChars(36)}";
        color: transparent;
        background-clip: text;
        animation: contentChange 1.5s infinite linear;
    }
}
@keyframes contentChange {
    10% {
        content: var(--content1);
    }
    20% {
        content: var(--content2);
    }
    30% {
        content: var(--content3);
    }
    40% {
        content: var(--content4);
    }
    50% {
        content: var(--content5);
    }
    60% {
        content: var(--content6);
    }
    70% {
        content: var(--content7);
    }
    80% {
        content: var(--content8);
    }
    90% {
        content: var(--content9);
    }
}

這樣,文字也能隨機動起來了(當然,此處其實是偽隨機):

最後,把上面的 hue-rotate 動畫重新打開,就能讓文字顏色也隨機變換!

至此,完整的代碼如下:

<div></div>
@use "sass:string";
@import url('https://fonts.googleapis.com/css2?family=Righteous&family=Ubuntu+Mono&display=swap');

$str: 'QWERTYUIOPASDFGHJKLZXCVBNMabcdefghigklmnopqrstuvwxyz123456789';
$length: str-length($str);

@function randomNum($max, $min: 0, $u: 1) {
    @return ($min + random($max)) * $u;
}

@mixin randomLinear($rows: 6, $cols: 8) {
  $bg: null;
  $pos: null;

  $px: 100% / ($cols - 1);
  $py: 100% / ($rows - 1);

  @for $i from 0 through $rows - 1 {
    @for $j from 0 through $cols - 1 {
      @if ($bg) {
        $bg: $bg + string.unquote(",");  
        $pos: $pos + string.unquote(",");  
      }
      $color: randomColor();
      $bg: $bg + linear-gradient(to right, $color, $color);
      $pos: $pos + string.unquote("#{$j * $px} #{$i * $py}");
    }
  }
  background: {
    image: $bg;
    size: (100% / $cols) (100% / $rows);
    repeat: no-repeat;
    position: $pos;
  }
}

@function randomColor() {
    @return rgb(randomNum(205, 50), randomNum(255), randomNum(255));
}

@function randomChar() {
    $r: random($length);
    @return str-slice($str, $r, $r);
}

@function randomChars($number) {
    $value: '';

    @if $number > 0 {
        @for $i from 1 through $number {
            $value: $value + randomChar();
        }
    }
    @return $value;
}

div {
    width: 300px;
    height: 300px;
    color: #fff;
    font-size: 50px;
    line-height: 50px;
    letter-spacing: 25px;
    word-wrap: break-word;
    animation: colorChange 1.5s infinite steps(10);
    
    &::before {
        --content1: "#{randomChars(36)}";
        --content2: "#{randomChars(36)}";
        --content3: "#{randomChars(36)}";
        --content4: "#{randomChars(36)}";
        --content5: "#{randomChars(36)}";
        --content6: "#{randomChars(36)}";
        --content7: "#{randomChars(36)}";
        --content8: "#{randomChars(36)}";
        --content9: "#{randomChars(36)}";
        content: randomChars(36);
        position: absolute;
        inset: 0;
        color: transparent;
        background-clip: text;
        animation: contentChange 1.5s infinite linear;
    }
}

@keyframes colorChange {
    100% {
        filter: hue-rotate(340deg);
    }
}
@keyframes contentChange {
    10% {
        content: var(--content1);
    }
    20% {
        content: var(--content2);
    }
    30% {
        content: var(--content3);
    }
    40% {
        content: var(--content4);
    }
    50% {
        content: var(--content5);
    }
    60% {
        content: var(--content6);
    }
    70% {
        content: var(--content7);
    }
    80% {
        content: var(--content8);
    }
    90% {
        content: var(--content9);
    }
}

效果如下:

完整的代碼,你可以戳這裡:CodePen Demo -- Single Div Random Text And Random Color

多色塊的其他解決方案?

我們繼續擴展延伸一下,本效果的核心還是如何在一個 DIV 下實現多種不同的顏色。

那麼,除了上述的技巧,還有其他方式能夠在一個 DIV 下實現多種不同顏色嗎?

這裡,我們還可以利用內聯元素的 background 展示特性來實現。

什麼意思呢?其實 background 的展示,在 塊級元素狀態內聯元素狀態 下的展示規則是不一樣的。

表現為 display: inline 內聯元素的 background 展現形式與 display: block 塊級元素(或者 inline-blockflexgrid)不一致。

簡單看個例子:

<p>Lorem .....</p><a>Lorem .....</a>

這裡需要註意,<p> 元素是塊級元素,而 <a>內聯元素

我們給它們統一添加上一個從綠色到藍色的漸變背景色:

p, a {
  background: linear-gradient(90deg, blue, green);
}

看看效果:

什麼意思呢?區別很明顯:

  1. 塊級元素的背景整體是一個漸變整體
  2. 內聯元素的背景效果是以行為單位進行串連的,每一行都是會有不一樣的效果,每行連起來整體組成一個完整的背景效果

基於這一點,我們同樣可以實現單個 DIV 下的多重背景。

舉個例子:

<div class="g-container">
    <span>ABCDEFGHIJKL</span>
</div>
div {
    width: 300px;
}
span{
    color: #000;
    font-size: 50px;
    line-height: 50px;
    letter-spacing: 25px;
    word-wrap: break-word;
    background: #fc0;
}

此時,我們只設置了一個背景 background: #fc0,效果如下:

基於上面說的技巧,我們改造一下 background: #fc0,拆分成多段漸變背景:

span{
    //...
    background: linear-gradient(
        90deg, 
        #fc0 0 25%, 
        #0f0 0 50%, 
        #00f 0 75%, 
        #f00 0 100%
    );
}

這裡,我們每隔 25%,設置了一段不同的顏色,如此一來,整個背景色就變成了 4 塊:

基於這個技巧,我們同樣可以封裝一個 SCSS 函數,用於在單個 DIV 下生成多段色塊。代碼如下:

@use "sass:string";
@import url('https://fonts.googleapis.com/css2?family=Righteous&family=Ubuntu+Mono&display=swap');

$str: 'QWERTYUIOPASDFGHJKLZXCVBNMabcdefghigklmnopqrstuvwxyz123456789';
$length: str-length($str);


@function randomNum($max, $min: 0, $u: 1) {
    @return ($min + random($max)) * $u;
}
@function randomColor() {
    @return rgb(randomNum(205, 50), randomNum(255), randomNum(255));
}
@function randomLinear($count) {
    $value: '';
    
    @for $i from 0 through ($count - 1) {
        $j: $i - 1;
        $value: $value + randomColor() + string.unquote(" #{$j * 50}px #{$i * 50}px,");
    }
    
    @return linear-gradient(90deg, string.unquote(#{$value}) randomColor() 0 100%);
}

span {
    background: randomLinear(36, 50);
}

上面的代碼,我們實現了一個 randomLinear($count, $width) 的 SCSS 函數,其中:

  1. $count 表示需要的色塊個數
  2. $width 表示每個色塊的寬度

如此一來,在一個 300px x 300px 的內聯元素內,我們同樣可以實現多個不同的隨機顏色。利用這個技巧,一樣可以實現單個平面下的隨機文字隨機顏色效果:

剩餘的技巧都是相同的,這裡就不再贅述,此技巧的完整代碼,你可以戳這裡:CodePen Demo -- Single Div Random Text And Random Color

最後

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

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

-Advertisement-
Play Games
更多相關文章
  • Redis是基於記憶體的K-V鍵值對記憶體資料庫 淺談Redis7新特性 主要是自身底層性能和資源利用率上的提高和優化。 多AOF文件支持 config命令增強 限制客戶端記憶體使用 listpack緊湊列表調整 訪問安全性增強 Redis Functions(要搶Lua腳本的飯碗) RDB保存時間調整, ...
  • 本文記錄如何在Linux系統上進行MongoDB資料庫的導出和導入(備份和還原),Windows系統上的命令基本一樣,僅文件路徑不同。 ...
  • 本文分享自華為雲社區《華為雲GaussDB城市沙龍活動走進安徽,助力金融行業數字化轉型》,作者: GaussDB 資料庫 。 近日,華為雲GaussDB資料庫城市沙龍·安徽站圈層活動順利舉行。活動邀請了金融行業代表及伙伴,一起圍繞資料庫展開了金融行業數字化轉型解決方案與成功實踐交流,共同推動國內數據 ...
  • 背景 1、在ArkTS的架構中,沒有明確的可管理的載入請求狀態的腳手架,在進行網路請求過程中,無法簡單的進行交互響應。 2、參考Android中的LoadState寫了一個簡單的腳手架,以便在日常開發過程中,管理載入請求狀態和UI交互。 腳手架說明與源碼 1、狀態機LoadState 使用一個狀態機 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 一,問題起因 最新在開發小程式的時候,調用微信小程式來獲取用戶信息的時候經常報錯一個問題 fail api scope is not declared in the privacy agreement,api 更具公告,是微信更新對應的隱 ...
  • 在建設博客的初期,我採用GitBook構建了編碼專家的專欄系統。GitBook是基於Node.js的靜態頁構建組件,可以將Markdown文檔渲染為靜態頁,支持插件擴展,使用非常簡單。由於它不支持深度的定製,使用了一段時間後,無法滿足我的要求了。有一天我看到某博客採用VuePress,簡潔美觀、功能... ...
  • 我們是袋鼠雲數棧 UED 團隊,致力於打造優秀的一站式數據中台產品。我們始終保持工匠精神,探索前端道路,為社區積累並傳播經驗價值。 本文作者:修能 朝聞道,夕死可矣 何為 Molecule? 輕量級的 Web IDE UI 框架——Molecule 我們開源了一個輕量的 Web IDE UI 框架 ...
  • 環境說明 macOS 13.5 % sw_vers ProductName: macOS ProductVersion: 13.5 BuildVersion: 22G74 Brew % brew --version Homebrew 4.1.2-33-gc531a35 安裝 安裝 nvm 使用 br ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...