Жидкая кнопка на HTML5 и CSS3
Эффект желе при наведении на кнопку с использованием HTML5 и CSS3
Для начала посмотрите ДЕМО
Установка:
1#: В самый низ вашего 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 29 |
.button { position: relative; padding: 1.6em 2.8em; text-decoration: none; } .button__canvas { --offset: 32px; position: absolute; top: calc(var(--offset) * -1); left: calc(var(--offset) * -1); width: calc(100% + var(--offset) * 2); height: calc(100% + var(--offset) * 2); transition: opacity 2s ease; } .button__text { position: relative; color: white; font-weight: bold; letter-spacing: 0.02em; pointer-events: none; } .button:hover .button__canvas { opacity: 0.85; transition: opacity 0.2s ease; } .button:active .button__canvas { opacity: 1; transition: none; } |
2#: Между тегами <body> и </body> вставьте:
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 |
<a href="#" class="button"> <canvas class="button__canvas"></canvas> <span class="button__text">Я жидкая, а ты - нет...</span> </a> <script src='/js/npm_ola.js'></script> <script id="rendered-js" > document.querySelectorAll('.button').forEach(elem => { const canvas = elem.querySelector('.button__canvas'); const ctx = canvas.getContext('2d'); const offset = 32; const background = '#eef'; const foreground = '#7551e9'; let points = []; let position; const distance = new Ola({ value: offset }); const size = () => { canvas.width = canvas.getBoundingClientRect().width; canvas.height = canvas.getBoundingClientRect().height; position = new Ola({ x: canvas.width / 2, y: canvas.height / 2 }); const pixelsWidth = canvas.width - offset * 2; const pixelsHeight = canvas.height - offset * 2; const leftTop = [offset, offset]; const rightTop = [canvas.width - offset, offset]; const rightBottom = [canvas.width - offset, canvas.height - offset]; const leftBottom = [offset, canvas.height - offset]; points = []; Array(pixelsWidth).fill().forEach((_, index) => { points.push([ leftTop[0] + index, leftTop[1]]); }); Array(pixelsHeight).fill().forEach((_, index) => { points.push([ rightTop[0], rightTop[1] + index]); }); Array(pixelsWidth).fill().forEach((_, index) => { points.push([ rightBottom[0] - index, rightBottom[1]]); }); Array(pixelsHeight).fill().forEach((_, index) => { points.push([ leftBottom[0], leftBottom[1] - index]); }); }; size(); const reset = () => { ctx.fillStyle = background; ctx.fillRect(0, 0, canvas.width, canvas.height); }; const draw = () => { ctx.fillStyle = foreground; ctx.beginPath(); points.forEach((point, index) => { const [vx, vy] = attract(point); if (index === 0) ctx.moveTo(vx, vy);else ctx.lineTo(vx, vy); }); ctx.closePath(); ctx.fill(); }; const attract = point => { const [x, y] = point; const dx = x - position.x; const dy = y - position.y; const dist = Math.sqrt(dx * dx + dy * dy); const dist2 = Math.max(1, dist); const d = Math.min(dist2, Math.max(12, dist2 / 4 - dist2)); const D = dist2 * distance.value; return [ x + d / D * (position.x - x), y + d / D * (position.y - y)]; }; const loop = () => { reset(); draw(); requestAnimationFrame(loop); }; window.onresize = size; canvas.onmousemove = e => { position.set({ x: e.clientX - e.target.getBoundingClientRect().left, y: e.clientY - e.target.getBoundingClientRect().top }, 200); }; canvas.onmouseenter = () => { distance.set({ value: 1 }, 200); }; canvas.onmouseleave = () => { position.set({ x: canvas.width / 2, y: canvas.height / 2 }, 2000); distance.set({ value: offset }, 12000); }; loop(); }); </script> |
Осталось лишь залить JS файл из прикреплённого архива в папку js