Is it possible to use an HTML canvas as a CSS mask? [closed]

1 week ago 17
ARTICLE AD BOX

I am working on a website, and I want to make the headings have an underline with an animated fog mask so random parts gradually fade in and out. Below is a mock-up of what I want to achieve:

Animated GIF of a line with the effects described above.

I was able to get pretty close to the effect I want using SVG feTurbulence filters as CSS masks, but it absolutely tanks the performance of the webpage. While looking for more performant options for creating animated image noise I found jwagner's simplex-noise.js project, which seems to be substantially more efficient than SVG filters as well as much more flexible. However, it uses the HTML <canvas> element, and I can't figure out how to make that element act as the CSS mask.

Is using a canvas as a CSS mask possible?

Below is a code snippet of a canvas with the noise effect applied and a header with my current underline effect. The id of the canvas is set as a mask for the underline in CSS, but it isn't being used as such (in Firefox or Chrome, at least).

:root { background: #1e1e1e; font-size: 16px; margin: 0 1.25rem; } h1 { width: 100%; display: inline-flex; position: relative; color: #bdbdbd; font-weight: 400; padding-bottom: 0.75em; margin-bottom: 0; } h1::after, h2::after { content: ""; position: absolute; left: -1.25rem; width: calc(100% + 2.5rem); height: calc(100% + 2rem); background: linear-gradient(to right, #e6bd64, #e6bd64) no-repeat; background-size: 100% 2px; background-position: center calc(100% - 1.375em); filter: drop-shadow(0 0 0.5rem #e6bd64) drop-shadow(0 0 0.5rem #e6bd64); mask: linear-gradient(white, white) luminance no-clip, linear-gradient(0.25turn, white 0%, black 6.25%, black 93.75%, white 100%) luminance no-clip, url(#noise-mask) luminance no-clip; mask-composite: subtract; } p { color: #d9dde5; } <body> <canvas id="noise-mask" width="512px" height="512px"></canvas> <h1><span class="mw-headline">Example Heading</span></h1> <p>Body text.</p> </body> <footer> <script type="module"> import {createNoise3D} from "https://cdn.skypack.dev/[email protected]"; const noise3D = createNoise3D(); const canvas = document.getElementById('noise-mask'); const ctx = canvas.getContext('2d'); const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); const data = imageData.data; let t = 0; function drawPlasma(){ for (let x = 0; x < 512; x++) { for (let y = 0; y < 512; y++) { const r = noise3D(x / 128, y / 128, t/512) * 0.5 + 0.5; data[(x + y * 512) * 4 + 0] = r * 255; data[(x + y * 512) * 4 + 1] = r * 255; data[(x + y * 512) * 4 + 2] = r * 255; data[(x + y * 512) * 4 + 3] = 255; } } t++; ctx.putImageData(imageData, 0, 0); requestAnimationFrame(drawPlasma); } drawPlasma(); </script> </footer>
Read Entire Article