Для более наглядного примера использования этого фона, я добавил поверх несколько блоков, кликая на которые, фон будет перерисовываться.
Пример:
Блок 1
Блок 2
Блок 3
HTML:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<div class="turbulence-container"> <div id="turbulence"> <div class="blocks"> <div class="block"> Блок 1 </div> <div class="block"> Блок 2 </div> <div class="block"> Блок 3 </div> </div> </div> </div> |
CSS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
.turbulence-container { position: relative; margin: 20px 0; box-shadow: 0 4px 12px rgba(0,0,0,0.2), 0 16px 20px rgba(0,0,0,0.2); } .blocks { display: flex; flex-wrap: wrap; justify-content: space-around; position: relative; z-index: 1; padding: 100px 0; } .block { margin: 20px; padding: 100px 50px; border: 6px solid #BFE2FF; border-radius: 10px; background-color: #fff; text-align: center; text-transform: uppercase; font-family: Verdana, sans-serif; font-size: 20px; font-weight: bold; color: #337AB7; cursor: pointer; box-shadow: 0 4px 12px rgba(0,0,0,0.2), 0 16px 20px rgba(0,0,0,0.2); } |
JS:
Раскомментировав строчку block[i].addEventListener('mouseenter', clickCanvas);
и удалив или закомментировав предыдущую (block[i].addEventListener('click', clickCanvas);
), капля будет меняться при заходе курсора на блок, а не по клику.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
const nbEddies = 5; const nbParticles = 1000; // Кол-во частиц const lifeTime = 1000; // Среднее время показа частицы let canv, ctx; let maxx, maxy; let dimx, dimy; let eddies; let particles; let requestID; let hueShift; const mrandom = Math.random; const mfloor = Math.floor; const mround = Math.round; const mceil = Math.ceil; const mabs = Math.abs; const mmin = Math.min; const mmax = Math.max; const mPI = Math.PI; const mPIS2 = Math.PI / 2; const m2PI = Math.PI * 2; const msin = Math.sin; const mcos = Math.cos; const matan2 = Math.atan2; const mexp = Math.exp; const mhypot = Math.hypot; const msqrt = Math.sqrt; const bcontainer = document.getElementById( 'turbulence' ); function alea (min, max) { if (typeof max == 'undefined') return min * mrandom(); return min + (max - min) * mrandom(); } function intAlea (min, max) { if (typeof max == 'undefined') { max = min; min = 0; } return mfloor(min + (max - min) * mrandom()); } function createEddy () { return { x: alea (dimx), y: alea (dimy), coeffR: 0.001 * (alea(0.7, 1.3)), radius: 150 + alea(-50, 50), coeffA1: 10000 * alea(0.8, 1.2), coeffA2: 0.01 * alea(0.8, 1.2), dir: (mrandom() > 0.5) ? 1 : -1 } } function createEddies() { eddies = []; for (let k = 0; k < nbEddies; ++k) { eddies.push(createEddy()); } } function createParticle() { return { x: alea (-100, dimx + 100), y: alea (-100, dimy + 100), sat: `${intAlea(50, 101)}%`, light: `${intAlea(30, 80)}%`, TTL: alea(lifeTime * 0.8, lifeTime * 1.2) } } function createParticles() { particles = []; for (let k = 0; k < nbParticles; ++k) { particles.push(createParticle()); } particles.forEach (part => { part.TTL = intAlea(lifeTime); }); } function move() { let part, prev, dx, dy, s, c, r, rv, av, deltar; let mindeltar; for (let k = 0; k < nbParticles; ++k) { part = particles[k]; if (part.TTL <= 0) { part = createParticle(); particles[k] = part; } prev = {x: part.x, y: part.y}; mindeltar = 10000; eddies.forEach ((eddy, ke) => { dx = prev.x - eddy.x; dy = prev.y - eddy.y; r = mhypot(dx, dy); if (r < 0.001) r = 0.001; s = dy / r; c = dx / r; deltar = r - eddy.radius; av = eddy.coeffA2 * mexp (- deltar * deltar / eddy.coeffA1) * eddy.dir; rv = - deltar * eddy.coeffR; part.x += rv * c - av * r * s; part.y += rv * s + av * r * c; }) --part.TTL; let speed =mhypot (prev.x - part.x, prev.y - part.y) ; let hue = mmin (speed * 100, 300); hue = (hue + hueShift) % 360; ctx.beginPath(); ctx.moveTo (prev.x, prev.y); ctx.lineTo (part.x, part.y); ctx.strokeStyle = `hsl(${hue},${part.sat},${part.light})`; // Цвет ctx.stroke(); } } function startOver() { maxx = bcontainer.offsetWidth; maxy = bcontainer.offsetHeight; dimx = maxx; dimy = maxy; canv.style.left = (maxx - dimx) / 2 + 'px'; canv.style.top = (maxy - dimy) / 2 + 'px'; canv.width = dimx; canv.height = dimy; ctx.lineWidth = 1.5; ctx.imageSmoothingEnabled = false; hueShift = intAlea(360); createEddies(); createParticles(); if (typeof requestID == 'number') window.cancelAnimationFrame(requestID); (function animate () { move(); requestID = window.requestAnimationFrame(animate); })(); } function clickCanvas() { startOver(); } { canv = document.createElement('canvas'); canv.style.position = "absolute"; bcontainer.appendChild(canv); ctx = canv.getContext('2d'); } startOver(); window.addEventListener('resize',startOver); let block = document.getElementsByClassName('block'); for (var i = 0; i < block.length; i++) { block[i].addEventListener('click', clickCanvas); // block[i].addEventListener('mouseenter', clickCanvas); } |
Найдено на codepen.io у пользователя Dillon
А как сделать такой фон фиксированным при прокручивании (чтобы было аналогично свойству background-attachment: fixed;)?
Сначала задал вопрос, а только потом подумал. Нужно слой сделать 100% высоты и ширины ,ну и позиция fixed. А весь контент вынести за пределы слоя.