您好,登錄后才能下訂單哦!
怎么在CSS中利用Houdini實現一個動態波浪紋效果?針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
css是一種用來表現HTML或XML等文件樣式的計算機語言,主要是用來設計網頁的樣式,使網頁更加美化。它也是一種定義樣式結構如字體、顏色、位置等的語言,并且css樣式可以直接存儲于HTML網頁或者單獨的樣式單文件中,而樣式規則的優先級由css根據這個層次結構決定,從而實現級聯效果,發展至今,css不僅能裝飾網頁,也可以配合各種腳本對于網頁進行格式化。
什么是 CSS Houdini?
CSS Houdini 對外開放了瀏覽器解析流程的一系列 API,這些 API 允許開發者介入瀏覽器的 CSS engine 運作,帶來了更多的 CSS 解決方案。
CSS Houdini 主要提供了以下幾個 API:
CSS Properties and Values API
允許在 CSS 中定義變量和使用變量,是目前兼容性最好的一個 API;
Layout API
允許開發者編寫自己的 Layout Module,自定義諸如 display 這類的布局屬性;
Painting API
允許開發者編寫自己的 Paint Module,自定義諸如 background-image 這類的繪制屬性。
基礎:三步用上 Painting API
1、HTML 中通過 Worklets 載入樣式的自定義代碼:
<div class="rect"></div> <script> if ("paintWorklet" in CSS) { CSS.paintWorklet.addModule("paintworklet.js"); } </script>
Worklets 也是 Houdini 提供的 API 之一,負責加載和執行樣式的自定義 JS 代碼。它類似于 Web Worker,是一個運行于主代碼之外的獨立工作進程,但比 Worker 更為輕量,負責 CSS 渲染任務最為合適。
2、新建一個 paintworklet.js,利用 registerPaint 方法注冊一個 paint 類 rect,定義 paint 屬性的繪制邏輯:
registerPaint( "rect", class { static get inputProperties() { return ["--rect-color"]; } paint(ctx, geom, properties) { const color = properties.get("--rect-color")[0]; ctx.fillStyle = color; ctx.fillRect(0, 0, geom.width, geom.height); } } );
上邊定義了一個名為 rect 的 paint 屬性類,當 rect 被使用時,會實例化 rect 并自動觸發 paint 方法執行渲染。paint 方法中,我們獲取節點 CSS 定義的 --rect-color 變量,并將元素的背景填充為指定顏色。ctx 參數是一個 Canvas 的 Context 對象,因此 paint 的邏輯跟 Canvas 的繪制方式一樣。
3、CSS 中使用的時候,只需要調用 paint 方法:
.rect { width: 100vw; height: 100vh; background-image: paint(rect); --rect-color: rgb(255, 64, 129); }
這是一個自定義 CSS 背景色屬性的簡單實現,看得出利用 CSS Houdini,我們可以像操作 canvas 一樣靈活自如地實現我們想要的樣式功能。
進階:實現動態波紋
根據上述步驟,我們演示一下如何用 CSS Painting API 實現一個動態波浪的效果:
<!-- index.html --> <div id="wave"></div> <style> #wave { width: 20%; height: 70vh; margin: 10vh auto; background-color: #ff3e81; background-image: paint(wave); } </style> <script> if ("paintWorklet" in CSS) { CSS.paintWorklet.addModule("paintworklet.js"); const wave = document.querySelector("#wave"); let tick = 0; requestAnimationFrame(function raf(now) { tick += 1; wave.style.cssText = `--animation-tick: ${tick};`; requestAnimationFrame(raf); }); } </script> // paintworklet.js registerPaint('wave', class { static get inputProperties() { return ['--animation-tick']; } paint(ctx, geom, properties) { let tick = Number(properties.get('--animation-tick')); const { width, height } = geom; const initY = height * 0.4; tick = tick * 2; ctx.beginPath(); ctx.moveTo(0, initY + Math.sin(tick / 20) * 10); for (let i = 1; 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 + Math.sin(tick / 20) * 10); ctx.closePath(); ctx.fillStyle = 'rgba(255, 255, 255, 0.5)'; ctx.fill(); } })
paintworklet 中,利用 sin 函數繪制波浪線,由于 AnimationWorklets 尚處于實驗階段,開放較少,這里我們在 worklet 外部用 requestAnimationFrame API 來做動畫驅動,讓波浪紋動起來。完成后能看到下邊這樣的效果。
然而事實上這個效果略顯僵硬,sin 函數太過于規則了,現實中的波浪應該是不規則波動的,這種不規則主要體現在兩個方面:
1)波紋高度(Y)隨位置(X)變化而不規則變化
把圖按照 x-y 正交分解之后,我們希望的不規則,可以認為是固定某一時刻,隨著 x 軸變化,波紋高度 y 呈現不規則變化;
2)固定某點(X 固定),波紋高度(Y)隨時間推進而不規則變化
動態過程需要考慮時間維度,我們希望的不規則,還需要體現在時間的影響中,比如風吹過的前一秒和后一秒,同一個位置的波浪高度肯定是不規則變化的。
提到不規則,有朋友可能想到了用 Math.random 方法,然而這里的不規則并不適合用隨機數來實現,因為前后兩次取的隨機數是不連續的,而前后兩個點的波浪是連續的。這個不難理解,你見過長成鋸齒狀的波浪嗎?又或者你見過上一刻 10 米高、下一刻就掉到 2 米的波浪嗎?
為了實現這種連續不規則的特征,我們棄用 sin 函數,引入了一個包 simplex-noise。由于影響波高的有兩個維度,位置 X 和時間 T,這里需要用到 noise2D 方法,它提前在一個三維的空間中,構建了一個連續的不規則曲面:
// paintworklet.js import SimplexNoise from 'simplex-noise'; const sim = new SimplexNoise(() => 1); registerPaint('wave', class { static get inputProperties() { return ['--animation-tick']; } paint(ctx, geom, properties) { const tick = Number(properties.get('--animation-tick')); this.drawWave(ctx, geom, 'rgba(255, 255, 255, 0.4)', 0.004, tick, 15, 0.4); this.drawWave(ctx, geom, 'rgba(255, 255, 255, 0.5)', 0.006, tick, 12, 0.4); } /** * 繪制波紋 */ drawWave(ctx, geom, fillColor, ratio, tick, amp, ih) { const { width, height } = geom; const initY = height * ih; const speedT = tick * ratio; ctx.beginPath(); for (let x = 0, speedX = 0; x <= width; x++) { speedX += ratio * 1; var y = initY + sim.noise2D(speedX, speedT) * amp; ctx[x === 0 ? 'moveTo' : 'lineTo'](x, y); } ctx.lineTo(width, height); ctx.lineTo(0, height); ctx.lineTo(0, initY + sim.noise2D(0, speedT) * amp); ctx.closePath(); ctx.fillStyle = fillColor; ctx.fill(); } })
關于怎么在CSS中利用Houdini實現一個動態波浪紋效果問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。