搜尋
首頁web前端css教學聊聊怎麼利用CSS實現波浪進度條效果

聊聊怎麼利用CSS實現波浪進度條效果

Dec 28, 2022 pm 08:32 PM
cssjavascript前端

這篇文章跟大家分享CSS 高階技巧,介紹如何使用CSS達到波浪進度條效果,希望對大家有幫助!

聊聊怎麼利用CSS實現波浪進度條效果

本文是 CSS Houdini 之 CSS Painting API 系列第三篇。

在上兩篇中,我們詳細介紹了 CSS Painting API 是如何一步一步,實現自訂圖案甚至實現動畫效果的!

在這篇文章中,我們將繼續探索,嘗試使用 CSS Painting API,去實現一些過往純 CSS 無法實現的效果。 【推薦學習:css影片教學

CSS Painting API

再簡單快速的過一下,什麼是 CSS Painting API。

CSS Painting API 是 CSS Houdini 的一部分。而 Houdini 是一組底層 API,它們公開了 CSS 引擎的各個部分,從而使開發人員能夠透過加入瀏覽器渲染引擎的樣式和佈局流程來擴展 CSS。 Houdini 是一組API,它們使開發人員可以直接存取CSS 物件模型 (CSSOM),使開發人員可以編寫瀏覽器可以解析為CSS 的程式碼,從而創建新的CSS 功能,而無需等待它們在瀏覽器中本地實作。

CSS Paint API 目前的版本是 CSS Painting API Level 1。它也被稱為 CSS Custom Paint 或 Houdini's Paint Worklet。

我們可以把它理解為 JS In CSS,利用 JavaScript Canvas 畫布的強大能力,實現過往 CSS 無法實現的功能。

利用 CSS Painting API 實現波浪效果

CSS 實現波浪效果,一直是 CSS 的一個困難之一。在過往,雖然我們有很多方式利用Hack 出一些波浪效果,我在之前的多篇文章中有反复提及過:

是的,大部分時候,我們都是利用一些奇技淫巧實現波浪效果,像是這樣:

如今,有了CSS Painting API,我們已經可以繪製真實的波浪效果了。看看程式碼:

<div></div>

<script>
if (CSS.paintWorklet) {              
    CSS.paintWorklet.addModule(&#39;/CSSHoudini.js&#39;);
}
</script>
div {
    position: relative;
    width: 300px;
    height: 300px;
    background: paint(waveDraw);
    border-radius: 50%;
    border: 2px solid rgba(255, 0, 0, 0.5);
}

我們定義了一個 waveDraw 方法,接下來,就透過利用 registerPaint 來實作這個方法即可。

// 文件名为 CSSHoudini.js
registerPaint(
    "waveDraw",
    class {
        static get inputProperties() {
            return [];
        }
        paint(ctx, size, properties) {
            const { width, height } = size;
            const initY = height * 0.5;
            ctx.beginPath();
            for (let i = 0; i <= width; i++) {
                ctx.lineTo(i, initY + Math.sin((i) / 20) * 10);
            }
            ctx.lineTo(width, height);
            ctx.lineTo(0, height);
            ctx.lineTo(0, initY);
            ctx.closePath();

            ctx.fillStyle = &#39;rgba(255, 0, 0, 0.9)&#39;;
            ctx.fill();
        }
    }
);

這樣,我們就得到了這樣一個波浪效果:

聊聊怎麼利用CSS實現波浪進度條效果

#上面的程式碼其實很好理解,簡單解釋一下,我們核心就是利用路徑繪製,基於Math.sin() 三角函數,繪製了一段sin(x) 三角函數的圖形。

  • 整個圖形從ctx.beginPath() 開始,第一個點是ctx.lineTo(0, initY Math.sin((i) / 20) * 10),不過Math.sin(0) = 0,所以等於ctx.lineTo(0, initY)

  • #initY 在這的作用是控制從什麼高度開始繪製波浪圖形,我們這裡的取值是initY = height * 0.5,也就是定義成了圖形的中間位置

  • 利用 for (let i = 0; i 循环,配合 <code>ctx.lineTo(i, initY + Math.sin((i) / 20) * 10),也就是在每一个 x 轴上的点,都绘制一个点

  • 随后三个在循环体外的 ctx.lineTo 的作用是让整个图形形成一个闭环

  • 最后 ctx.closePath() 完成整个路径,ctx.fill() 进行上色

如果不 ctx.fill() 上色,利用 ctx.stroke() 绘制边框,也是可以的,其实我们得到是这样一个图形:

聊聊怎麼利用CSS實現波浪進度條效果

上图是同时去掉了 CSS 代码里面的 border-radius: 50%,方便大家理解。

当然,上面的图形,有个很大的问题,没法动起来,所以,我们需要借助一个 CSS @Property 自定义变量,让它拥有一些动画效果。

我们需要改造一下代码,首先,添加一个 CSS @Property 自定义变量:

@property --animation-tick {
  syntax: &#39;<number>&#39;;
  inherits: false;
  initial-value: 1000;
}
div {
  // ... 代码与上述保持一致
  animation: move 20s infinite linear;
  --animation-tick: 1000;
}
@keyframes move {
    100% {
        --animation-tick: 0;
    }
}

我们添加了一个 --animation-tick 变量,并且利用 CSS 动画,让它从 1000 减至 0。

下一步,利用这个不断在变化的 CSS 自定义变量,我们在 waveDraw 方法中,把它利用上:

// 文件名为 CSSHoudini.js
registerPaint(
    "waveDraw",
    class {
        static get inputProperties() {
            return ["--animation-tick"];
        }
        paint(ctx, size, properties) {
            let tick = Number(properties.get("--animation-tick"));
            const { width, height } = size;
            const initY = height * 0.5;
            ctx.beginPath();
            for (let i = 0; i <= width; i++) {
                ctx.lineTo(i, initY + Math.sin((i + tick) / 20) * 10);
            }
            ctx.lineTo(width, height);
            ctx.lineTo(0, height);
            ctx.lineTo(0, initY);
            ctx.closePath();

            ctx.fillStyle = &#39;rgba(255, 0, 0, 0.9)&#39;;
            ctx.fill();
        }
    }
);

仔细看,和上述的代码变化不大,核心在于,利用三角函数绘制图形的时候,我们把这个变量加入进去。

从原来的 ctx.lineTo(i, initY + Math.sin((i) / 20) * 10),变成了 ctx.lineTo(i, initY + Math.sin((i + tick) / 20) * 10)

这样,在这个不断变化的变量的作用下,我们的波浪图形就能运动起来了:

CodePen Demo -- CSS Houdini Wave

虽然能动了,但是总是感觉还少了些什么。如果我们把这个波浪效果应用与进度条之类的效果上,我们可以需要可以快速定义波浪的振幅、每个波峰之间的间距、效果的颜色、百分比等等。

因此,我们需要再通过一个 CSS 变量,让它成为一个实际可用的封装良好的波浪进度条。我们再简单改造一下:

@property --animation-tick {
  syntax: &#39;<number>&#39;;
  inherits: false;
  initial-value: 1000;
}
@property --height {
  syntax: &#39;<number>&#39;;
  inherits: false;
  initial-value: .7;
}
div {
    position: relative;
    width: 300px;
    height: 300px;
    background: paint(waveDraw);
    animation: move 20s infinite linear;
    border-radius: 50%;
    border: 2px solid var(--color1);
    --amplitude: 15;
    --gap: 28;
    --animation-tick: 700;
    --height: 0.7;
    --color1: rgba(255, 0, 0, 0.5);
    --color2: rgba(255, 0, 0, 0.4);
    --color3: rgba(255, 0, 0, 0.3);
    
    transition: --height 8s;
}

可以看到,我们定义了非常多个 CSS 变量,每次,它们都是有意义的:

  • --animation-tick 表示波浪运动的速率
  • --amplitude 波浪的振幅
  • --gap 波峰间距
  • --initHeight 初始高度
  • --color1--color2--color3 我们会叠加 3 层波浪效果,显得更真实一点,这里 3 个颜色表示 3 层波浪的颜色

定义好这些 CSS 变量后,我们就可以把它们运用在实际的waveDraw 方法中。看看代码:

registerPaint(
    "waveDraw",
    class {
        static get inputProperties() {
            return [
                "--animation-tick", 
                "--height", 
                "--gap",
                "--amplitude",
                "--color1",
                "--color2",
                "--color3"
            ];
        }
        
        paint(ctx, size, properties) {
            let tick = Number(properties.get("--animation-tick"));
            let initHeight = Number(properties.get("--height"));
            let gap = Number(properties.get("--gap"));
            let amplitude = Number(properties.get("--amplitude"));
            let color1 = properties.get("--color1");
            let color2 = properties.get("--color2");
            let color3 = properties.get("--color3");
            
            this.drawWave(ctx, size, tick, amplitude, gap, initHeight, color1);
            this.drawWave(ctx, size, tick * 1.21, amplitude / 0.82, gap + 2, initHeight + 0.02, color2);
            this.drawWave(ctx, size, tick * 0.79, amplitude / 1.19, gap - 2, initHeight - 0.02, color3);
        }
        
        /**
         * ctx
         * size
         * tick 速率
         * amplitude 振幅
         * gap 波峰间距
         * initHeight 初始高度
         * color 颜色
         */
        drawWave(ctx, size, tick, amplitude, gap, initHeight, color) {
            const { width, height } = size;
            const initY = height * initHeight;
            tick = tick * 2;
            
            ctx.beginPath();
            for (let i = 0; i <= width; i++) {
                ctx.lineTo(i, initY + Math.sin((i + tick) / gap) * amplitude);
            }
            ctx.lineTo(width, height);
            ctx.lineTo(0, height);
            ctx.lineTo(0, initY);
            ctx.closePath();
            ctx.fillStyle = color;
            ctx.fill();
        }
    }
);

可以看到,我们在 paint() 方法中,调用了 this.drawWave()。每次调用 this.drawWave() 都会生成一个波浪图形,通过 3 层的叠加效果,生成 3 层波浪。并且,把我们在 CSS 中定义的变量全部的应用了起来,分别控制波浪效果的不同参数。

这样,我们就得到了这样一个波浪效果:

通过控制 CSS 中的 --height 变量,还可以实现高度的变化,从而完成真实的百分比,实现一种进度条效果。

div:hover {
    --height: 0;
}

效果如下:

很好,非常不错的效果。有了上述一些 CSS 自定义变量的帮助,我们就可以通过封装好的 waveDraw 方法,实现不同颜色,不同大小,不同速率的波浪进度条效果了。

我们只需要简单的改变一下传入的 CSS 变量参数即可:

<div></div>
<div></div>
<div></div>
div {
    position: relative;
    width: 300px;
    height: 300px;
    background: paint(waveDraw);
    animation: move 20s infinite linear;
    border-radius: 50%;
    border: 2px solid var(--color1);
    --amplitude: 15;
    --gap: 28;
    --animation-tick: 700;
    --height: 0.7;
    --color1: rgba(255, 0, 0, 0.5);
    --color2: rgba(255, 0, 0, 0.4);
    --color3: rgba(255, 0, 0, 0.3);
    
    transition: --height 8s;
}
div:nth-child(2) {
    --amplitude: 6;
    --gap: 25;
    --animation-tick: 300;
    --height: 0.5;
    --color1: rgba(28, 90, 199, 0.5);
    --color2: rgba(28, 90, 199, 0.4);
    --color3: rgba(28, 90, 199, 0.3);
}
div:nth-child(3) {
    --amplitude: 3;
    --gap: 30;
    --animation-tick: 1200;
    --height: 0.3;
    --color1: rgba(178, 120, 33, 0.5);
    --color2: rgba(178, 120, 33, 0.4);
    --color3: rgba(178, 120, 33, 0.3);
}

看看效果如何:

CodePen Demo -- CSS Hudini Custom Wave Effects !

這樣,借助 CSS Painting API,我們完美的實現了波浪圖形,並且藉助它,實現了波浪進度條效果。透過傳入不同的 CSS 變量,我們有了快速批量產生不同效果的能力。彌補了過往 CSS 在波浪效果上的缺陷!

當然,就基於上述的程式碼,還是有一些可以優化的空間的:

  • 在上述的CSS 程式碼中,可以看到,我們是傳入了3 個關於顏色的CSS 變量,--color1--color2--color3,正常而言,這裡傳入1 個顏色即可,轉換成HSL 顏色表示法,替換L 色值,得到近似的另外兩個色值即可。當然,這樣做的話會增添非常多的JavaScript 程式碼,所以,本文為了方便大家理解,偷懶直接傳入了3 個CSS 顏色變數值;

  • 整個波浪效果單輪的動畫持續時間我設定為了20s,但是在本文中,沒有去適配動畫的手尾銜接,也就是可能會出現每20s,波浪效果有一個明顯的跳動的感覺。解決這個問題,有兩個想法

    • 透過精確的計算,讓動畫的最後一格和動畫的第一幀銜接上
    • --animation- tick 的值設定的非常的大,然後把對應的單輪動畫時間設定的非常長,這樣,基本上也感受不到動畫的跳幀
  • 第三個問題可能就在於相容性

相容性?

好吧,其實上一篇文章也談到了相容問題,因為可能有很多看到這篇文章並沒有去翻閱前兩篇文章的同學。那麼,CSS Painting API 的兼容性到底如何呢?

CanIUse - registerPaint 資料如下(截止至2022-11-23):

聊聊怎麼利用CSS實現波浪進度條效果

Chrome 和Edge 基於Chromium 核心的瀏覽器很早就已經支持,而主流瀏覽器中,Firefox 和Safari 目前還不支援。

CSS Houdini 雖然強大,目前看來要大規模上生產環境,仍需一段時間的等待。讓我們給時間一點時間!

原文網址:https://juejin.cn/post/7170868201645932551

作者:ChokCoco

#(學習影片分享:web前端

以上是聊聊怎麼利用CSS實現波浪進度條效果的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:掘金社区。如有侵權,請聯絡admin@php.cn刪除
滑動頁腳滑動頁腳Apr 09, 2025 am 11:50 AM

剛剛推出了一個引人入勝的新網站。標語:Big Tech正在看著您。我們正在看大型技術。上升的出色工作。這

喜歡的頁面喜歡的頁面Apr 09, 2025 am 11:47 AM

前幾天,我發布了有關在JavaScript中解析RSS提要的內容。我還發布了有關RSS設置的信息,討論了Feedbin的核心。

重新創建Codepen Gutenberg嵌入塊以進行理智。重新創建Codepen Gutenberg嵌入塊以進行理智。Apr 09, 2025 am 11:43 AM

了解如何通過Chris Coyier實施WordPress的Gutenberg編輯器來創建一個自定義Codepen塊,並為Sanity Studio提供預覽。

如何使用CSS製作線路圖如何使用CSS製作線路圖Apr 09, 2025 am 11:36 AM

線,條和餅圖是儀表板的麵包和黃油,是任何數據可視化工具包的基本組成部分。當然,您可以使用SVG

編程SASS創建可訪問的顏色組合編程SASS創建可訪問的顏色組合Apr 09, 2025 am 11:30 AM

我們一直在尋求使網絡更容易訪問。顏色對比只是數學,因此Sass可以幫助涵蓋設計師可能錯過的邊緣案例。

我們如何創建一個在SVG中生成格子呢模式的靜態站點我們如何創建一個在SVG中生成格子呢模式的靜態站點Apr 09, 2025 am 11:29 AM

格子呢是一塊圖案布,通常與蘇格蘭有關,尤其是他們時尚的蘇格蘭語。在Tar​​tanify.com上,我們收集了5,000多個格子呢

PHP模板的後續行動PHP模板的後續行動Apr 09, 2025 am 11:14 AM

不久前,我僅以PHP(基本上是Heredoc語法)發布了有關PHP模板的信息。我從字面上使用該技術來進行某種超級基礎

使用Bootstrap組件創建模態圖像庫使用Bootstrap組件創建模態圖像庫Apr 09, 2025 am 11:10 AM

您是否曾經在網頁上單擊圖像,該圖像通過導航打開圖像的較大版本以查看其他照片?

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
3 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

SublimeText3 英文版

SublimeText3 英文版

推薦:為Win版本,支援程式碼提示!

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中