24

У меня есть слово StackOverflow:

<h1>StackOverflow</h1>

Как создать эффект анимации для этого слова, например, в виде волны и одновременно переливания одного цвета в другой?

Я представляю себе следующий сценарий анимации:

  1. Последовательная слева направо смена цвета букв
  2. Последовательное увеличение от исходного размера шрифта для каждой буквы
  3. Изменение размера шрифта в исходный размер в обратном порядке
  4. Обратная смена цвета букв в начальный цвет
  5. Зацикливание анимации

Как реализовать подобный сценарий такой анимации, используя любую технологию, указанную в метках вопроса?

Sevastopol'
  • 28,195

12 Answers12

47

Не люблю рамки, ни на что не претендую, просто вот вам прикольный эффект:

let s = 620;

document.body.innerHTML += &lt;canvas id="canvas" width="${s}" height="${s/4}" &gt;&lt;/canvas&gt;;

let ctx = canvas.getContext('2d'); let dots = []; let mouse = {x:0, y:0} let startedAt = Date.now();

ctx.font = 'bold '+(s/7.5)+'px Arial'; ctx.fillStyle = 'red'; ctx.textBaseline = "middle"; ctx.textAlign = "center"; ctx.fillText('Стековерфлоу', s/2, s/8);

let mask = ctx.getImageData(0,0,s,s/4); for (let i = 0; dots.length < 3000; i++){ let x = sMath.random(); let y1 = sMath.random(); let y2 = -sMath.random(); let offset = parseInt(y1)s4 + parseInt(x)4; if (mask.data[offset]) dots.push({x, y1, y2, speed: {x:0, y:0}, i}) }

ctx.fillStyle = 'black';

requestAnimationFrame(function draw(){ let t = Date.now() - startedAt; ctx.clearRect(0,0,s,s); dots.forEach(dot => { let t1 = Math.min(1,(t-dot.x4)/(500+2000Math.abs(Math.sin(dot.i4)))); t1 = t1t1t1 let x = dot.x; let y = dot.y2 + (dot.y1-dot.y2) t1; let dx = mouse.x-x; let dy = mouse.y-y; let lenSq = dxdx + dydy; if (lenSq < 900) { let d = 30-Math.sqrt(lenSq); dot.speed.x += dx/30d; dot.speed.y += dy/30d; } x += dot.speed.x; y += dot.speed.y; dot.speed.x = 0.92; dot.speed.y = 0.92; ctx.fillRect(x-0.75, y-0.75, 1.5, 1.5); });

requestAnimationFrame(draw);

});

addEventListener('mousemove', e => { let bb = canvas.getBoundingClientRect(); mouse.x = e.x - bb.x; mouse.y = e.y - bb.y; });

['click','touchstart'].forEach(type => addEventListener(type, () => startedAt = Date.now()));

Чтобы расположить точки в виде букв, используется канва, на ней нарисован желаемый текст.

Первым шагом необходимо сгенерировать много точек, и каждую проверить на попадание в маску текста, сделать это можно проверив значение цвета пикселя по координатам точки, пусть это будет красный канал:

let mask = ctx.getImageData(0,0,s,s/4);
let red = mask.data[y*width*4 + x*4];

После того, как точки расставлены, можно их заанимировать, для этого каджую точку изначально поднимаем в область отрицательных значений у и со случайной скоростью двигаем вниз, до того, пока она не достигнет своего местоположения, так же к этому добавим задержку, пропорциональную x координате, чтобы анимация происходила слева-направо.

Финальный штрих - реакция на указатель: тут все относительно просто, считаем дистанцию от указателя до точки, и если она меньше определенного порога - меняем координату точки на значение, которое зависит от этой дистанции.

MobiDevices
  • 7,309
  • 11
    Ну вы как всегда, слов нет, превосходно! – MoloF Apr 03 '20 at 19:39
  • 2
    @Sevastopol' если честно, я давно собрал этот эффект, с подачи @ MaximLensky, он как то попросил повторить нечто такое, решил поделиться с народом, кажется тут его еще не публиковал, а вообще уже были эффекты с текстом по похожему принципу, в новогоднем конкурсе салют.. – Stranger in the Q Apr 03 '20 at 19:43
  • 11
    @Sevastopol' спасибо, я рад что Вам нравится, только это и мотивирует, людям нравится. жалко времени на это все совсем нет.. – Stranger in the Q Apr 03 '20 at 20:07
  • 12
    @StrangerintheQ Офигеть!!! Это просто потрясающе. Великолепно и удивительно!!! Я в полнейшем восторге! 2 раза КУ - жёлтые штаны!!! – Denis640Kb Apr 03 '20 at 22:35
  • 1
    Изумительный эффект, просидел сейчас минут 10 разгоняя точки курсором. –  Apr 10 '20 at 06:57
37

@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300&display=swap');
* {
  margin: 0;
  padding: 0;
}

body { display: flex; align-items: center; justify-content: center;

height: 100vh;

perspective: 1000px; overflow: hidden;

background-color: #212121; font-family: 'Roboto', sans-serif; }

h1 { --cb: cubic-bezier(0.71, 0.73, 0.58, 0.83); --adur: 4s;

position: relative;

font-size: 10vw; color: white; -webkit-box-reflect: below 10px linear-gradient(transparent, rgba(255, 255, 255, 0.1));

display: flex;

animation: whole_heading_animation var(--cb) var(--adur);

perspective: 1000px; }

h1::after { content: '';

position: absolute; bottom: -10%; left: 0;

display: block; width: 100%; height: 0.7vw;

background-color: #b3e5fc;

animation: draw_line 1.5s var(--adur) both; }

span { --cb-span: ease-out;

position: relative; margin: 0 0.5vw;

animation-timing-function: var(--cb); animation-duration: var(--adur); transform-style: preserve-3d; }

span::after, span::before { position: absolute; left: 0; top: 0; }

span::after { animation: after_animation var(--cb-span) var(--adur) both; }

span::before { animation: before_animation var(--cb-span) var(--adur) both; }

span:nth-child(1) { --tx-1: 30vw; --ty-1: -10vw; --tz-1: -3000px; --rz-1: 1080deg; --ry-1: 0deg; --rx-1: 620deg; animation-name: letter_1_animation; }

span:nth-child(1)::after, span:nth-child(1)::before { content: 'S'; }

span:nth-child(2) { --tx-2: 26vw; --ty-2: 10vw; --tz-2: -2600px; --rz-2: 0deg; --ry-2: -70deg; --rx-2: -620deg; animation-name: letter_2_animation; }

span:nth-child(2)::after, span:nth-child(2)::before { content: 't'; }

span:nth-child(3) { --tx-3: 22vw; --ty-3: -8vw; --tz-3: -2200px; --rz-3: 0deg; --ry-3: 40deg; --rx-3: 750deg; animation-name: letter_3_animation; }

span:nth-child(3)::after, span:nth-child(3)::before { content: 'a'; }

span:nth-child(4) { --tx-4: 18vw; --ty-4: 10vw; --tz-4: -1800px; --rz-4: 0deg; --ry-4: -50deg; --rx-4: -900deg; animation-name: letter_4_animation; }

span:nth-child(4)::after, span:nth-child(4)::before { content: 'c'; }

span:nth-child(5) { --tx-5: 14vw; --ty-5: 0vw; --tz-5: -1400px; --rz-5: 80deg; --ry-5: 1080deg; --rx-5: -620deg; animation-name: letter_5_animation; }

span:nth-child(5)::after, span:nth-child(5)::before { content: 'k'; }

span:nth-child(6) { --tx-6: 10vw; --ty-6: -8vw; --tz-6: -1000px; --rz-6: 100deg; --ry-6: 920deg; --rx-6: -720deg; animation-name: letter_6_animation; }

span:nth-child(6)::after, span:nth-child(6)::before { content: 'O'; }

span:nth-child(7) { --tx-7: 0vw; --ty-7: -5vw; --tz-7: -1000px; --rz-7: 380deg; --ry-7: -600deg; --rx-7: 0deg; animation-name: letter_7_animation; }

span:nth-child(7)::after, span:nth-child(7)::before { content: 'v'; }

span:nth-child(8) { --tx-8: -4vw; --ty-8: 8vw; --tz-8: -1400px; --rz-8: 20deg; --ry-8: 0deg; --rx-8: 820deg; animation-name: letter_8_animation; }

span:nth-child(8)::after, span:nth-child(8)::before { content: 'e'; }

span:nth-child(9) { --tx-9: -8vw; --ty-9: 0vw; --tz-9: -1800px; --rz-9: -100deg; --ry-9: 0deg; --rx-9: -1020deg; animation-name: letter_9_animation; }

span:nth-child(9)::after, span:nth-child(9)::before { content: 'r'; }

span:nth-child(10) { --tx-10: -12vw; --ty-10: -4vw; --tz-10: -2200px; --rz-10: 100deg; --ry-10: -500deg; --rx-10: 1000deg; animation-name: letter_10_animation; }

span:nth-child(10)::after, span:nth-child(10)::before { content: 'f'; }

span:nth-child(11) { --tx-11: -16vw; --ty-11: -15vw; --tz-11: -2600px; --rz-11: 0deg; --ry-11: 10deg; --rx-11: -1020deg; animation-name: letter_11_animation; }

span:nth-child(11)::after, span:nth-child(11)::before { content: 'l'; }

span:nth-child(12) { --tx-12: -20vw; --ty-12: 0vw; --tz-12: -3000px; --rz-12: 0deg; --ry-12: 60deg; --rx-12: -620deg; animation-name: letter_12_animation; }

span:nth-child(12)::after, span:nth-child(12)::before { content: 'o'; }

span:nth-child(13) { --tx-13: -24vw; --ty-13: 10vw; --tz-13: -3400px; --rz-13: -1080deg; --ry-13: 200deg; --rx-13: 0deg; animation-name: letter_13_animation; }

span:nth-child(13)::after, span:nth-child(13)::before { content: 'w'; }

@keyframes whole_heading_animation { from { transform: translateZ(-8000px) scale(0); opacity: 0; }

25% { transform: translateZ(-500px); opacity: 1; }

to { transform: translateZ(0); } }

@keyframes draw_line { from { transform: translateX(-100%); opacity: 0; }

to { transform: translateX(0); } }

@keyframes letter_1_animation { from { transform: translate3d(var(--tx-1), var(--ty-1), var(--tz-1)) rotateX(var(--rx-1)) rotateY(var(--ry-1)) rotateZ(var(--rz-1)); }

35% { transform: translate3d( calc(var(--tx-1) / 3), calc(var(--ty-1) / 3), calc(var(--tz-1) / 3) ) rotateX(calc(var(--rx-1) / 3)) rotateY(calc(var(--ry-1) / 3)) rotateZ(calc(var(--rz-1) / 3)); } }

@keyframes letter_2_animation { from { transform: translate3d(var(--tx-2), var(--ty-2), var(--tz-2)) rotateX(var(--rx-2)) rotateY(var(--ry-2)) rotateZ(var(--rz-2)); }

35% { transform: translate3d( calc(var(--tx-2) / 3), calc(var(--ty-2) / 3), calc(var(--tz-2) / 3) ) rotateX(calc(var(--rx-2) / 3)) rotateY(calc(var(--ry-2) / 3)) rotateZ(calc(var(--rz-2) / 3)); } }

@keyframes letter_3_animation { from { transform: translate3d(var(--tx-3), var(--ty-3), var(--tz-3)) rotateX(var(--rx-3)) rotateY(var(--ry-3)) rotateZ(var(--rz-3)); }

35% { transform: translate3d( calc(var(--tx-3) / 3), calc(var(--ty-3) / 3), calc(var(--tz-3) / 3) ) rotateX(calc(var(--rx-3) / 3)) rotateY(calc(var(--ry-3) / 3)) rotateZ(calc(var(--rz-3) / 3)); } }

@keyframes letter_4_animation { from { transform: translate3d(var(--tx-4), var(--ty-4), var(--tz-4)) rotateX(var(--rx-4)) rotateY(var(--ry-4)) rotateZ(var(--rz-4)); }

35% { transform: translate3d( calc(var(--tx-4) / 3), calc(var(--ty-4) / 3), calc(var(--tz-4) / 3) ) rotateX(calc(var(--rx-4) / 3)) rotateY(calc(var(--ry-4) / 3)) rotateZ(calc(var(--rz-4) / 3)); } }

@keyframes letter_5_animation { from { transform: translate3d(var(--tx-5), var(--ty-5), var(--tz-5)) rotateX(var(--rx-5)) rotateY(var(--ry-5)) rotateZ(var(--rz-5)); }

35% { transform: translate3d( calc(var(--tx-5) / 3), calc(var(--ty-5) / 3), calc(var(--tz-5) / 3) ) rotateX(calc(var(--rx-5) / 3)) rotateY(calc(var(--ry-5) / 3)) rotateZ(calc(var(--rz-5) / 3)); } }

@keyframes letter_6_animation { from { transform: translate3d(var(--tx-6), var(--ty-6), var(--tz-6)) rotateX(var(--rx-6)) rotateY(var(--ry-6)) rotateZ(var(--rz-6)); }

35% { transform: translate3d( calc(var(--tx-6) / 3), calc(var(--ty-6) / 3), calc(var(--tz-6) / 3) ) rotateX(calc(var(--rx-6) / 3)) rotateY(calc(var(--ry-6) / 3)) rotateZ(calc(var(--rz-6) / 3)); } }

@keyframes letter_7_animation { from { transform: translate3d(var(--tx-7), var(--ty-7), var(--tz-7)) rotateX(var(--rx-7)) rotateY(var(--ry-7)) rotateZ(var(--rz-7)); }

35% { transform: translate3d( calc(var(--tx-7) / 3), calc(var(--ty-7) / 3), calc(var(--tz-7) / 3) ) rotateX(calc(var(--rx-7) / 3)) rotateY(calc(var(--ry-7) / 3)) rotateZ(calc(var(--rz-7) / 3)); } }

@keyframes letter_8_animation { from { transform: translate3d(var(--tx-8), var(--ty-8), var(--tz-8)) rotateX(var(--rx-8)) rotateY(var(--ry-8)) rotateZ(var(--rz-8)); }

35% { transform: translate3d( calc(var(--tx-8) / 3), calc(var(--ty-8) / 3), calc(var(--tz-8) / 3) ) rotateX(calc(var(--rx-8) / 3)) rotateY(calc(var(--ry-8) / 3)) rotateZ(calc(var(--rz-8) / 3)); } }

@keyframes letter_9_animation { from { transform: translate3d(var(--tx-9), var(--ty-9), var(--tz-9)) rotateX(var(--rx-9)) rotateY(var(--ry-9)) rotateZ(var(--rz-9)); }

35% { transform: translate3d( calc(var(--tx-9) / 3), calc(var(--ty-9) / 3), calc(var(--tz-9) / 3) ) rotateX(calc(var(--rx-9) / 3)) rotateY(calc(var(--ry-9) / 3)) rotateZ(calc(var(--rz-9) / 3)); } }

@keyframes letter_10_animation { from { transform: translate3d(var(--tx-10), var(--ty-10), var(--tz-10)) rotateX(var(--rx-10)) rotateY(var(--ry-10)) rotateZ(var(--rz-10)); }

35% { transform: translate3d( calc(var(--tx-10) / 3), calc(var(--ty-10) / 3), calc(var(--tz-10) / 3) ) rotateX(calc(var(--rx-10) / 3)) rotateY(calc(var(--ry-10) / 3)) rotateZ(calc(var(--rz-10) / 3)); } }

@keyframes letter_11_animation { from { transform: translate3d(var(--tx-11), var(--ty-11), var(--tz-11)) rotateX(var(--rx-11)) rotateY(var(--ry-11)) rotateZ(var(--rz-11)); }

35% { transform: translate3d( calc(var(--tx-11) / 3), calc(var(--ty-11) / 3), calc(var(--tz-11) / 3) ) rotateX(calc(var(--rx-11) / 3)) rotateY(calc(var(--ry-11) / 3)) rotateZ(calc(var(--rz-11) / 3)); } }

@keyframes letter_12_animation { from { transform: translate3d(var(--tx-12), var(--ty-12), var(--tz-12)) rotateX(var(--rx-12)) rotateY(var(--ry-12)) rotateZ(var(--rz-12)); }

35% { transform: translate3d( calc(var(--tx-12) / 3), calc(var(--ty-12) / 3), calc(var(--tz-12) / 3) ) rotateX(calc(var(--rx-12) / 3)) rotateY(calc(var(--ry-12) / 3)) rotateZ(calc(var(--rz-12) / 3)); } }

@keyframes letter_13_animation { from { transform: translate3d(var(--tx-13), var(--ty-13), var(--tz-13)) rotateX(var(--rx-13)) rotateY(var(--ry-13)) rotateZ(var(--rz-13)); }

35% { transform: translate3d( calc(var(--tx-13) / 3), calc(var(--ty-13) / 3), calc(var(--tz-13) / 3) ) rotateX(calc(var(--rx-13) / 3)) rotateY(calc(var(--ry-13) / 3)) rotateZ(calc(var(--rz-13) / 3)); } }

@keyframes before_animation { 10% { transform: translate3d(0, 0, 0) scale(1); }

70% { transform: translate3d(-0, -10vw, -3vw) scale(0.9) skew(-20deg); opacity: 0.1; }

to { transform: translate3d(-0.4vw, -0.4vw, -0.4vw) scale(1); } }

@keyframes after_animation { 10% { transform: translate3d(0, 0, 0) scale(1); }

70% { transform: translate3d(2vw, 0, 3vw) scale(2) skew(-20deg); opacity: 0.5; }

to { transform: translate3d(0.4vw, 0.4vw, 0.4vw) scale(1); } }

<h1>
  <span>S</span>
  <span>t</span>
  <span>a</span>
  <span>c</span>
  <span>k</span>
  <span>O</span>
  <span>v</span>
  <span>e</span>
  <span>r</span>
  <span>f</span>
  <span>l</span>
  <span>o</span>
  <span>w</span>
</h1>
  • 7
    Классный эффект! сам придумал? Ну в смысле идеи – Alexandr_TT Apr 04 '20 at 14:21
  • 10
    @Alexandr_TT я даже не думаю об идеи просто сажусь и что то кручу-верчу, получается то , что получается ) –  Apr 04 '20 at 14:30
  • 6
    Кручу, верчу, запутать хочу! так? :)) https://avatars.mds.yandex.net/get-zen_doc/1244179/pub_5b026a7f5816699c7bdf201e_5b028141fd96b1d692d81c77/scale_1200 – Alexandr_TT Apr 04 '20 at 14:34
  • 8
    @Alexandr_TT не, вот так https://media.giphy.com/media/IfJg2g9nJUqd2/giphy.gif –  Apr 04 '20 at 14:43
  • 4
    @Alexandr_TT, почему от тебя еще нет ответа, думаешь? – SVE Apr 06 '20 at 07:51
  • 4
    @HamSter Ваш ответ, наравне с ответом Alexandr_TT, тоже было бы приятно увидеть ) – Denis640Kb Apr 06 '20 at 08:23
  • 4
    @Denis640Kb, жду вдохновения))) но моя муза подводит меня, видимо тоже на изоляции где-то )))) – SVE Apr 06 '20 at 08:25
  • 5
    @HamSter А Вы её шоколадкой подкормите ))) Я видел Ваши работы, и они вызывают восхищение. Не поверю, что у Вас нет идей ) – Denis640Kb Apr 06 '20 at 08:27
  • 4
    @HamSter Привет! Да дел было много в офлайне вчера и вопросов SVG в связи с вирусом вдруг стало много. Пытался везде успеть. А тут, хочется, что-нибудь посолидней сделать, сейчас займусь – Alexandr_TT Apr 06 '20 at 08:48
  • 2
    @Sevastopol', уже есть идея (примитивная) но как вариант постараюсь выложить) – SVE Apr 06 '20 at 12:04
26

Update 14.04.

body {
  overflow: hidden;
  margin: 0;
  padding: 0;
  background-color: #2da8cb;
  background: rgb(24, 139, 172);
  background: linear-gradient(45deg, gold 0%, lavender 99%);
}

div { position: relative; width: 100%; height: 100vh; margin: 0 0 0 20px; }

h1, h2 { opacity: 1; display: block; position: absolute; top: 0; left: 0; margin: 0; padding: 0; font-family: Helvetica, Arial; font-weight: 900; font-size: 6em; letter-spacing: 0.01em; line-height: 1em; text-transform: uppercase; text-shadow: 10px 10px 8px rgba(0, 0, 0, 0.15); background: linear-gradient(45deg, red, orange, yellow, yellow, chocolate, yellow, orange, red, orange, yellow, yellow, chocolate, yellow, orange, red); background-size: 250% 500%; -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; text-fill-color: transparent; -webkit-backface-visibility: hidden; backface-visibility: hidden; -webkit-animation: animate 5s ease-out infinite; animation: animate 5s ease-out infinite; }

h2 { top: 20px; left: -100%; opacity: 1; font-size: 5em; }

@keyframes animate { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } }

div:hover h1 { left: -100%; animation: animate 5s ease-out infinite, animate__hover__h1 2s ease-in-out; }

div:hover h2 { left: 0; animation: animate 5s ease-out infinite, animate__hover__h2 4s ease-in-out; }

@keyframes animate__hover__h1 { from { left: 0; } to { left: -100%; } }

@keyframes animate__hover__h2 { from { left: -100%; } 50% { left: -100%; } to { left: 0; } }

<div><span></span><span></span><span></span><span></span><span></span><span></span><span></span><h1>Stack<br>Overflow</h1><h2>Спасибо<br>за участие</h2></div>

Ответ на вопрос

Подобный сценарий я реализовал следующим образом:

  1. Заключил в заголовке h1 каждую букву слова StackOverflow в отдельный строчный элемент span.
  2. Создал CSS анимацию и с помощью правила @keyframes установил общие ключевые кадры, включая в них нужные свойства (размер и цвет шрифта) при анимации для всех элементов. Так как подобный вариант анимации является средней сложности, поэтому вместо ключевых слов from и to я использовал проценты.
  3. Отдельно для каждого последующего элемента установил с помощью свойства animation-delay время ожидания перед воспроизведением анимации по возрастанию в промежутке равном 0,1 секунде.

И вот, что у меня получилось в результате:

h1 {
  position: absolute;
  top: 30%;
  left: 50%;
  transform: translate(-50%, -50%);
}

@keyframes animate { 0% { font-size: 60px; color: #f48024; } 10% { font-size: 80px; color: #242729 } 40% { font-size: 40px; color: #f48024; } 70% { font-size: 50px; color: #f48024; } 100% { font-size: 60px; color: #f48024; } }

h1>span { font-family: Helvetica, Arial; font-weight: 900; font-size: 60px; color: #f48024; animation: animate 2.5s ease infinite; }

h1>span:nth-child(2) { animation-delay: .1s; }

h1>span:nth-child(3) { animation-delay: .2s; }

h1>span:nth-child(4) { animation-delay: .3s; }

h1>span:nth-child(5) { animation-delay: .4s; }

h1>span:nth-child(6) { animation-delay: .5s; }

h1>span:nth-child(7) { animation-delay: .6s; }

h1>span:nth-child(8) { animation-delay: .7s; }

h1>span:nth-child(9) { animation-delay: .8s; }

h1>span:nth-child(10) { animation-delay: .9s; }

h1>span:nth-child(11) { animation-delay: 1s; }

h1>span:nth-child(12) { animation-delay: 1.1s; }

h1>span:nth-child(13) { animation-delay: 1.2s; }

<h1><span>S</span><span>t</span><span>a</span><span>c</span><span>k</span><span>O</span><span>v</span><span>e</span><span>r</span><span>f</span><span>l</span><span>o</span><span>w</span></h1>
Sevastopol'
  • 28,195
  • 11
    Диво дивное ))) – Denis640Kb Apr 03 '20 at 19:10
  • 3
    токо щас заметил что плюс я забыл посстаить - – Резидент Казахстана Apr 04 '20 at 10:42
  • 8
    Спасибо за приглашение! Постараюсь придумать что-то интересное! И как понимаю жестких рамок нет, любой энтузиазм приветствуется?!) – SVE Apr 04 '20 at 11:15
  • 5
    @Sevastopol' Да ну Вы что ))) Бросьте. Тут такие ответы, что я могу лишь наблюдать и ручками сучить от восторга ) Куда мне там позориться. Вы лучше ещё Alexandr_TT ещё спросите. Я бы и на его решение посмотрел бы ) И решение Hamster было бы интересно увидеть. – Denis640Kb Apr 04 '20 at 23:31
26

Тоже canvas

Автор скрипта: Ossama Rafique

var ImageParticles = {
  density: 0,

produceDistance: 0, baseRadius: 0, maxLineThickness: 0, reactionSensitivity: 0, lineThickness: 0,

particles: [], mouse: { x: -1000, y: -1000, down: false },

animation: null,

canvas: null, context: null, bgImage: null, bgCanvas: null, bgContext: null, bgContextPixelData: null,

initialize: function(canvas_id, imageData, densityPara = 6, produceDistancePara = 28, baseRadiusPara = 2, maxLineThicknessPara = 1, reactionSensitivityPara = 2, lineThicknessPara = 1) { this.canvas = document.getElementById(canvas_id); this.context = canvas.getContext('2d'); this.context.globalCompositeOperation = "lighter"; this.canvas.width = window.innerWidth; this.canvas.height = window.innerHeight; this.canvas.style.display = 'block' this.canvas.addEventListener('mousemove', this.pointerMove, false); this.canvas.addEventListener('mousedown', this.pointerDown, false); this.canvas.addEventListener('mouseup', this.pointerUp, false); this.canvas.addEventListener('mouseout', this.pointerOut, false); this.density = densityPara; this.produceDistance = produceDistancePara; this.baseRadius = baseRadiusPara; this.maxLineThickness = maxLineThicknessPara; this.reactionSensitivity = reactionSensitivityPara; window.onresize = function(event) { ImageParticles.canvas.width = window.innerWidth; ImageParticles.canvas.height = window.innerHeight; ImageParticles.onWindowResize(); } this.getImageData(imageData); },

makeParticles: function() { this.particles = [];

var width, height, i, j;

var colors = this.bgContextPixelData.data;

for (i = 0; i &lt; this.canvas.height; i += this.density) {

  for (j = 0; j &lt; this.canvas.width; j += this.density) {

    var pixelPosition = (j + i * this.bgContextPixelData.width) * 4;
    if (colors[pixelPosition] &gt; 200 &amp;&amp; (colors[pixelPosition + 1]) &gt; 200 &amp;&amp; (colors[pixelPosition + 2]) &gt; 200 || colors[pixelPosition + 3] === 0) {
      continue;
    }

    var color = 'rgba(' + colors[pixelPosition] + ',' + colors[pixelPosition + 2] + ',' + colors[pixelPosition + 3] + ',' + '1)';
    this.particles.push({
      x: j,
      y: i,
      originalX: j,
      originalY: i,
      color: color
    });

  }
}

},

updateparticles: function() {

var i, currentPoint, theta, distance;

for (i = 0; i &lt; this.particles.length; i++) {

  currentPoint = this.particles[i];

  theta = Math.atan2(currentPoint.y - this.mouse.y, currentPoint.x - this.mouse.x);

  if (this.mouse.down) {
    distance = this.reactionSensitivity * 200 / Math.sqrt((this.mouse.x - currentPoint.x) * (this.mouse.x - currentPoint.x) +
      (this.mouse.y - currentPoint.y) * (this.mouse.y - currentPoint.y));
  } else {
    distance = this.reactionSensitivity * 100 / Math.sqrt((this.mouse.x - currentPoint.x) * (this.mouse.x - currentPoint.x) +
      (this.mouse.y - currentPoint.y) * (this.mouse.y - currentPoint.y));
  }


  currentPoint.x += Math.cos(theta) * distance + (currentPoint.originalX - currentPoint.x) * 0.10;
  currentPoint.y += Math.sin(theta) * distance + (currentPoint.originalY - currentPoint.y) * 0.10;

}

},

produceLines: function() {

var i, j, currentPoint, otherPoint, distance, lineThickness;

for (i = 0; i &lt; this.particles.length; i++) {

  currentPoint = this.particles[i];
  this.context.fillStyle = currentPoint.color;

  for (j = 0; j &lt; this.particles.length; j++) {
    otherPoint = this.particles[j];

    if (otherPoint == currentPoint) {
      continue;
    }

    distance = Math.sqrt((otherPoint.x - currentPoint.x) * (otherPoint.x - currentPoint.x) +
      (otherPoint.y - currentPoint.y) * (otherPoint.y - currentPoint.y));

    if (distance &lt;= this.produceDistance) {
      this.context.beginPath();
      this.context.moveTo(currentPoint.x, currentPoint.y);
    }
  }
}

},

produceparticles: function() {

var i, currentPoint;

for (i = 0; i &lt; this.particles.length; i++) {

  currentPoint = this.particles[i];
  this.context.fillStyle = currentPoint.color;

  this.context.beginPath();
  this.context.arc(currentPoint.x, currentPoint.y, this.baseRadius, 0, Math.PI * 2, true);
  this.context.closePath();
  this.context.fill();

}

},

produce: function() { this.animation = requestAnimationFrame(function() { ImageParticles.produce() });

this.remove();
this.updateparticles();
this.produceparticles();

},

remove: function() { this.canvas.width = this.canvas.width; }, getImageData: function(data) {

this.bgImage = new Image;
this.bgImage.src = data;

this.bgImage.onload = function() {
  ImageParticles.produceImageParticles();
}

}, produceImageParticles: function() {

this.bgCanvas = document.createElement('canvas');
this.bgCanvas.width = this.canvas.width;
this.bgCanvas.height = this.canvas.height;

var newWidth, newHeight;
if (this.bgImage.width &gt; this.bgCanvas.width - 100 || this.bgImage.height &gt; this.bgCanvas.height - 100) {

  var maxRatio = Math.max(this.bgImage.width / (this.bgCanvas.width - 100), this.bgImage.height / (this.bgCanvas.height - 100));
  newWidth = this.bgImage.width / maxRatio;
  newHeight = this.bgImage.height / maxRatio;

} else {
  newWidth = this.bgImage.width;
  newHeight = this.bgImage.height;
}
this.bgContext = this.bgCanvas.getContext('2d');
this.bgContext.drawImage(this.bgImage, (this.canvas.width - newWidth) / 2, (this.canvas.height - newHeight) / 2, newWidth, newHeight);
this.bgContextPixelData = this.bgContext.getImageData(0, 0, this.bgCanvas.width, this.bgCanvas.height);

this.makeParticles();
this.produce();

},

pointerDown: function(event) { ImageParticles.mouse.down = true; },

pointerUp: function(event) { ImageParticles.mouse.down = false; },

pointerMove: function(event) { ImageParticles.mouse.x = event.offsetX || (event.layerX - ImageParticles.canvas.offsetLeft); ImageParticles.mouse.y = event.offsetY || (event.layerY - ImageParticles.canvas.offsetTop); },

pointerOut: function(event) { ImageParticles.mouse.x = -1000; ImageParticles.mouse.y = -1000; ImageParticles.mouse.down = false; }, onWindowResize: function() { cancelAnimationFrame(this.animation); this.produceImageParticles(); } }

ImageParticles.initialize('canvas', 'data:image/png;base64,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');

canvas {
  min-width: 100vw;
  height: 100vh;
  position: fixed;
}
<canvas id="canvas"></canvas>
21
  1. Анимация обводки контуров букв stroke-dasharray

Используется гугловский шрифт Tangerine

Этот способ интересен прежде всего тем, что не нужно для каждой буквы вычислять stroke-dasharray и писать анимацию для каждой буквы. Достаточно одной для всей фразы

 <animate begin="svg1.click" dur="15s" repeatCount="indefinite"
        attributeName="stroke-dashoffset"
        values="500;0;0;500;500" fill="freeze" restart="whenNotActive" />

<head>
    <link rel="stylesheet"
          href="https://fonts.googleapis.com/css?family=Tangerine">
    <style>
      body {
        font-family: 'Tangerine', serif;
        font-size: 150px;
  font-weigth:bold;
  }
&lt;/style&gt;

</head> <body> <svg id="svg1" version="1.1" width="500" height="200" viewBox="0 0 500 200"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="background:dodgerblue">

   &lt;text stroke-dasharray="500 500" stroke-dashoffset="500" fill="none" stroke="white" stroke-width="2" dy="1em" &gt;
  Stackoverflow
  &lt;animate begin="svg1.click" dur="15s" repeatCount="indefinite"
    attributeName="stroke-dashoffset"
    values="500;0;0;500;500" fill="freeze" restart="whenNotActive" /&gt;
&lt;/text&gt;

</svg> </body>

  1. Анимация обводки букв из одной точки двумя линиями Эта техника тоже интересна и полезна для реализации текстовых эффектов. Ведь даже рисование одной линией контура смотрится довольно интересно, а если двумя линиями рисовать, то это будет смотреться вдвое интересней.

Суть этого метода заключается в использовании двух пар атрибута stroke-dasharray

Для первой буквы полная длина 355px
Скрываем линию до анимации
0,177.5 0,177.5 черта=0 пробел = 177.5 черта=0 пробел = 177.5 итого вся линия скрыта

Показываем линию:

0,0,355,0 - черта во второй паре атрибутов равна полной длине 355 поэтому линия полностью видна

<animate id="t1" attributeName="stroke-dasharray" begin="s1.end" dur="2s"
        values="0,177.5 0,177.5;0,0,355,0" fill="freeze" />
    </path>

<style>
.el{
     stroke:cyan;
 stroke-width:2;
 fill:none;

} .container { width:100vw; height:100vh; } </style>

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/animejs/2.2.0/anime.js"></script> <div class="line-drawing-demo"> <svg id="svg1" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="600" height="200" viewBox="0 0 350 100" style="border:1px solid grey;"> <rect width="100%" height="100%" fill="#111111" /> <g class="lines" >

&lt;path  class="el"  stroke-dasharray="0,317" d="m59.3 12.8 6.4 20.3q-5.3-4.5-9.5-6.9-4.2-2.4-6.8-2.4-2 0-3.1 1.1-1.1 1.1-1.1 3 0 2.4 2.4 4.3 2.4 1.9 7.5 3.4 11.3 3.4 15.3 6.7 4 3.3 4 8.4 0 8.3-8.1 13.6-8.1 5.3-20.9 5.3-6.5 0-12.9-2.3-6.4-2.4-11.8-6.7V69.6L13.9 49.3q4.7 3.8 9.2 5.9 4.6 2 8.3 2 4 0 6.2-1.7 2.2-1.7 2.2-4.7 0-2.8-1.8-4.5-1.8-1.7-8-3.6-9-2.9-13.5-6.8-4.4-4-4.4-9.3 0-6.7 5.9-11 5.9-4.3 15.4-4.3 6.2 0 12.2 2.2 5.9 2.2 12.2 6.9z" &gt; 

<animate id="s1" attributeName="stroke-dasharray" begin="svg1.click" dur="2s" values="0,158.5 0,158.5;0,0,317,0" fill="freeze" /> </path>

&lt;path  class="el"  stroke-dasharray="0,355" d="M136.9 11.5 118.6 47.3 116.2 20 105.6 61.9 121.7 69.6 87 67.7 98.2 64.3 85.5 19.2 81.9 52.3 74.5 15.7Z" &gt;

<animate id="t1" attributeName="stroke-dasharray" begin="s1.end" dur="2s" values="0,177.5 0,177.5;0,0,355,0" fill="freeze" /> </path>

&lt;path class="el"  stroke-dasharray="0,342" d="m171 38-5.3-15.1-5.1 18.6zm30.5 21.7-33 10.2 8.4-11.3-2.4-8.4-12.3 0.9-3.6 9.8 5.3 4.2-35.9 2.6 8.7-6.5 11.6-45.2-6.6-4.3 44.5 1.5-10.4 3.7 18.2 40.6z" &gt;

<animate id="a1" attributeName="stroke-dasharray" begin="t1.end" dur="2s" values="0,171 0,171;0,0,342,0" fill="freeze" /> </path>

&lt;path class="el"  stroke-dasharray="0,270" d="m256.7 40.5-4 26.3-1.6-10.7q-5.5 6.5-12.1 9.9-6.6 3.4-13.8 3.4-4.7 0-9.2-1.9-4.5-2-8.1-5.7-4.3-4.3-6.6-9.7-2.3-5.4-2.3-11 0-7.8 3.3-14.2 3.3-6.4 9.3-10.5 4-2.7 8.7-4 4.7-1.3 10.1-1.3 5 0 9.2 1.6 4.3 1.6 8 4.7l2.2-6.3 3.9 20.7q-2.5-3.6-5.9-5.5-3.4-1.9-7.3-1.9-4.5 0-7.3 2.7-2.8 2.6-2.8 7 0 4.6 3.4 7.8 3.4 3.1 8.6 3.1 3.2 0 6.6-1.1 3.4-1.1 7.4-3.4z" &gt;
&lt;animate id="c1" attributeName="stroke-dasharray" begin="a1.end" dur="2s" 
  values="0,135 0,135;0,0,270,0" fill="freeze" /&gt;

</path>

&lt;path class="el"  stroke-dasharray="0,375" d="m329.1 68.8-30.1-3.7 6-3.9-17.6-18.1-2 0.4 4.1 20.1 6.4 6.8-38.1-4.3 6.8-5 3.6-41.2-7.4-4.7 30.5-3.7-8.5 6.6 2.5 16 13.4-15.9-3.7-4.6 27.7 1-19.7 15.8z" &gt;

<animate id="c1" attributeName="stroke-dasharray" begin="c1.end" dur="2s" values="0,187.5 0,187.5;0,0,375,0" fill="freeze" /> </path> </g>
</svg>

</div>

  1. Анимация обводки, как в предыдущем примере плюс анимация собирания букв

.el{
     stroke:yellow;
 stroke-width:2;
 fill:none;

} .container { width:100vw; height:100vh; }

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/animejs/2.2.0/anime.js"></script>
<div class="line-drawing-demo">
<svg id="svg1" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="600" height="200" viewBox="0 0 350 100" style="border:1px solid grey;">
  <rect width="100%" height="100%" fill="#111111" />
  <g class="lines" >
                <!-- Буква "S" -->
    <path  class="el"  stroke-dasharray="0,317" d="m59.3 12.8 6.4 20.3q-5.3-4.5-9.5-6.9-4.2-2.4-6.8-2.4-2 0-3.1 1.1-1.1 1.1-1.1 3 0 2.4 2.4 4.3 2.4 1.9 7.5 3.4 11.3 3.4 15.3 6.7 4 3.3 4 8.4 0 8.3-8.1 13.6-8.1 5.3-20.9 5.3-6.5 0-12.9-2.3-6.4-2.4-11.8-6.7V69.6L13.9 49.3q4.7 3.8 9.2 5.9 4.6 2 8.3 2 4 0 6.2-1.7 2.2-1.7 2.2-4.7 0-2.8-1.8-4.5-1.8-1.7-8-3.6-9-2.9-13.5-6.8-4.4-4-4.4-9.3 0-6.7 5.9-11 5.9-4.3 15.4-4.3 6.2 0 12.2 2.2 5.9 2.2 12.2 6.9z" > 
   <animate id="s1" attributeName="stroke-dasharray" begin="svg1.click" dur="1.5s" values="0,158.5 0,158.5;0,0,317,0" fill="freeze" restart="whenNotActive" /> 
    <animateTransform id="st" attributeName="transform" type="translate" begin="k1.end" dur="1s" values="0;100" fill="freeze" restart="whenNotActive" /> 
      <animateTransform id="sBack" attributeName="transform" type="translate" begin="kt.end+1s" dur="1s" values="0;0" fill="freeze" restart="whenNotActive"  /> 
 </path>
      <!-- Буква "T" -->
    <path  class="el"  stroke-dasharray="0,355" d="M136.9 11.5 118.6 47.3 116.2 20 105.6 61.9 121.7 69.6 87 67.7 98.2 64.3 85.5 19.2 81.9 52.3 74.5 15.7Z" >
  <animate id="t1" attributeName="stroke-dasharray" begin="s1.end" dur="1.5s" 
      values="0,177.5 0,177.5;0,0,355,0" fill="freeze" restart="whenNotActive" />  
   <animateTransform id="tt" attributeName="transform" type="translate" 
       begin="st.end" dur="1s"    values="0;50" fill="freeze" restart="whenNotActive" />   
     <animateTransform id="tBack" attributeName="transform" type="translate" begin="sBack.end+1s" dur="1s" values="0;0" fill="freeze" restart="whenNotActive"  />  
 </path>
        <!-- Буква "A" -->
    <path class="el"  stroke-dasharray="0,342" d="m171 38-5.3-15.1-5.1 18.6zm30.5 21.7-33 10.2 8.4-11.3-2.4-8.4-12.3 0.9-3.6 9.8 5.3 4.2-35.9 2.6 8.7-6.5 11.6-45.2-6.6-4.3 44.5 1.5-10.4 3.7 18.2 40.6z" >
   <animate id="a1" attributeName="stroke-dasharray" begin="t1.end" dur="1.5s" 
      values="0,171 0,171;0,0,342,0" fill="freeze" restart="whenNotActive" /> 
   <animateTransform id="at" attributeName="transform" type="translate" begin="tt.end" dur="0.1s" values="0;0" fill="freeze" restart="whenNotActive" /> 
 </path>
        <!-- Буква "C" -->
    <path class="el"  stroke-dasharray="0,270" d="m256.7 40.5-4 26.3-1.6-10.7q-5.5 6.5-12.1 9.9-6.6 3.4-13.8 3.4-4.7 0-9.2-1.9-4.5-2-8.1-5.7-4.3-4.3-6.6-9.7-2.3-5.4-2.3-11 0-7.8 3.3-14.2 3.3-6.4 9.3-10.5 4-2.7 8.7-4 4.7-1.3 10.1-1.3 5 0 9.2 1.6 4.3 1.6 8 4.7l2.2-6.3 3.9 20.7q-2.5-3.6-5.9-5.5-3.4-1.9-7.3-1.9-4.5 0-7.3 2.7-2.8 2.6-2.8 7 0 4.6 3.4 7.8 3.4 3.1 8.6 3.1 3.2 0 6.6-1.1 3.4-1.1 7.4-3.4z" >

    <animate id="c1" attributeName="stroke-dasharray" begin="a1.end" dur="1.5s" 
      values="0,135 0,135;0,0,270,0" fill="freeze" restart="whenNotActive" />
   <animateTransform id="ct" attributeName="transform" type="translate" begin="at.end" dur="1s" values="0;-50" fill="freeze" restart="whenNotActive" />
            <animateTransform id="cBack" attributeName="transform" type="translate" begin="sBack.end+0.5s" dur="1s" values="0;0" fill="freeze" restart="whenNotActive" /> 
 </path>
      <!-- Буква "K" -->
    <path class="el"  stroke-dasharray="0,375" d="m329.1 68.8-30.1-3.7 6-3.9-17.6-18.1-2 0.4 4.1 20.1 6.4 6.8-38.1-4.3 6.8-5 3.6-41.2-7.4-4.7 30.5-3.7-8.5 6.6 2.5 16 13.4-15.9-3.7-4.6 27.7 1-19.7 15.8z" >
   <animate id="k1" attributeName="stroke-dasharray" begin="c1.end" dur="1.5s" 
      values="0,187.5 0,187.5;0,0,375,0" fill="freeze" restart="whenNotActive" />
       <animateTransform id="kt" attributeName="transform" type="translate" begin="ct.end" dur="1s" values="0;-100" fill="freeze" restart="whenNotActive" /> 
        <animateTransform id="kBack" attributeName="transform" type="translate" begin="kt.end+1s" dur="1s" values="0;0" fill="freeze" restart="whenNotActive" /> 
 </path>
</g>   
 </svg>

</div>
  1. Анимация хаотичного движения букв, вертикальный финиш сборки букв в слово

<style>
 #text1 {

fill:yellow; }

</style> <svg id="svg1" width="70%" height="70%" viewBox="0 0 1000 1000" xmlns="http://www.w3.org/2000/svg" version="1.1" baseProfile="tiny" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMinYMin meet">

<defs> <linearGradient id="grad" x1="0" y1="0" x2="0" y2="100%" gradientUnits="userSpaceOnUse"> <stop offset="2%" stop-color="black" /> <stop offset="75%" stop-color="red" /> </linearGradient> </defs> <rect width="100%" height="100%" fill="url(#grad)" /> <text x="200 " y="500" font-size="90" fill="#E4E4E4" stroke-width="1" stroke="#E4E4E4">Stackoverflow</text> <text id="text1" x="200" y="500" font-size="90">Stackoverflow</text>

<animate xlink:href="#text1" attributeName="x" attributeType="XML" values="200 233 266 299 332 365 400 431 464 497 530 563 596; 100 600 200 365 700 465 465 563 530 398 431 850 900; 200 500 900 950 150 531 300 620 150 266 365 650 900; 332 233 820 300 800 633 200 670 300 850 800 530 266; 464 900 900 900 820 670 430 900 530 600 233 365 100; 332 100 100 100 500 100 800 563 900 700 900 100 100; 200 233 266 299 332 365 400 431 464 497 530 563 596" dur="3s" begin="svg1.click" repeatCount="2" /> <animate xlink:href="#text1" attributeName="y" attributeType="XML" values="500 500 500 500 500 500 500 500 500 500 500 500 500; 100 200 850 100 250 175 750 100 750 720 850 500 50; 100 600 600 250 200 450 50 200 520 550 300 300 750; 500 100 650 650 600 150 550 50 150 550 200 550 400; 800 300 100 750 150 650 75 350 550 700 755 120 800; 800 600 300 150 750 350 700 650 200 250 500 650 100; 500 500 500 500 500 500 500 500 500 500 500 500 500" dur="4s" begin="svg1.click" repeatCount="2" />

</svg>

  1. Горизонтальный финиш сборки букв в слово

<style>
 #text1 {

fill:#D0FF00; }

</style> <svg id="svg1" width="50%" height="50%" viewBox="0 0 1000 1000" xmlns="http://www.w3.org/2000/svg" version="1.1" baseProfile="tiny" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMinYMin meet">

<title>Animation of text x and y attributes</title>

<defs> <linearGradient id="grad" x1="0" y1="0" x2="0" y2="100%" gradientUnits="userSpaceOnUse"> <stop offset="2%" stop-color="#151515" /> <stop offset="70%" stop-color="yellowgreen" /> </linearGradient> </defs> <rect width="100%" height="100%" fill="url(#grad)" /> <text x="200 " y="500" font-size="90" fill="#d3d3d3" stroke-width="1" stroke="#d3d3d3">Stackoverflow</text> <text id="text1" x="200" y="500" font-size="90">Stackoverflow</text>

<animate xlink:href="#text1" attributeName="x" attributeType="XML" values="200 233 266 299 332 365 400 431 464 497 530 563 596; 100 600 200 365 700 465 465 563 530 398 431 850 900; 200 500 900 950 150 531 300 620 150 266 365 650 900; 332 233 820 300 800 633 200 670 300 850 800 530 266; 464 900 900 900 820 670 430 900 530 600 233 365 100; 332 100 100 100 500 100 800 563 900 700 900 100 100; 200 233 266 299 332 365 400 431 464 497 530 563 596" dur="4s" begin="svg1.click" repeatCount="2" /> <animate xlink:href="#text1" attributeName="y" attributeType="XML" values="500 500 500 500 500 500 500 500 500 500 500 500 500; 100 200 850 100 250 175 750 100 750 720 850 500 50; 100 600 600 250 200 450 50 200 520 550 300 300 750; 500 100 650 650 600 150 550 50 150 550 200 550 400; 800 300 100 750 150 650 75 350 550 700 755 120 800; 800 600 300 150 750 350 700 650 200 250 500 650 100; 500 500 500 500 500 500 500 500 500 500 500 500 500" dur="3s" begin="svg1.click" repeatCount="2" />

</svg>

Alexandr_TT
  • 110,146
  • 23
  • 114
  • 384
  • 4
    @Alexandr_TT Очень круто ))) Соглашусь с Sevastopol` - если собрать Ваши работы, то можно легко проводить обучение по svg, как для про, так и для таких чайников как я ))) – Denis640Kb Apr 06 '20 at 18:16
  • 1
    @Denis640Kb Благодарю :)) Давайте обменяемся чайными сервизами, у меня очень много вопросов по JS, но я, как и вы стесняюсь задавать, чтобы люди не смеялись. Ну, как, зададите первый вопрос по SVG? а я следом по JS Вот например в 4 и 6 примере здесь, можно было бы использовать массивы и случайные координаты букв – Alexandr_TT Apr 06 '20 at 18:31
  • @Alexandr_TT Я только за ) Правда, мне очень сложно пока даже тестовый пример сделать ) Всё на уровне - "Хотелось бы вот такое сделать" ) – Denis640Kb Apr 06 '20 at 18:36
  • StackoverAow))) – Qwertiy Apr 06 '20 at 21:31
  • @Sevastopol' Тогда уж надо ++благодарность ;) – USERNAME GOES HERE Apr 07 '20 at 16:02
  • Ни один из сниппетов не соответствует вопросу в текущем его виде. – andreymal Jun 29 '21 at 20:52
19

Такой короткий вариант:

* {
  box-sizing: border-box;
}

html, body, .project { padding: 0; margin: 0; width: 100%; height: 100%; overflow: hidden; }

.word-x { position: absolute; top: 50%; left: 50%; margin-top: -125px; margin-left: -125px; height: 250px; width: 250px; -webkit-transform-style: preserve-3d; transform-style: preserve-3d; -webkit-backface-visibility: visible; backface-visibility: visible; -webkit-transform-origin: 50% 50%; transform-origin: 50% 50%; -webkit-transform: rotateY(0deg) rotateZ(0deg) rotateX(0deg); transform: rotateY(0deg) rotateZ(0deg) rotateX(0deg); -webkit-animation: word-rotate 25s linear infinite; animation: word-rotate 25s linear infinite; } .word-x .word { position: absolute; width: 250px; height: 250px; margin-top: -125px; margin-left: -125px; top: 50%; left: 50%; -webkit-transform-style: preserve-3d; transform-style: preserve-3d; -webkit-backface-visibility: visible; backface-visibility: visible; -webkit-transform-origin: 50% 50%; transform-origin: 50% 50%; } .word-x .word .s { position: absolute; -webkit-transform-origin: 0% 50%; transform-origin: 0% 50%; -webkit-transform-style: preserve-3d; transform-style: preserve-3d; -webkit-backface-visibility: visible; backface-visibility: visible; top: 0%; left: 0%; } .word-x .word .s svg { position: absolute; top: 0; left: 0%; width: 250px; height: 250px; -webkit-transform-style: preserve-3d; transform-style: preserve-3d; -webkit-backface-visibility: visible; backface-visibility: visible; -webkit-transform-origin: 50% 50%; transform-origin: 50% 50%; } .word-x .word .s svg .p { fill: rgba(0, 0, 0, 0.1); stroke: rgba(0, 0, 0, 0.1); -webkit-animation: pulse 25s linear infinite; animation: pulse 25s linear infinite; }

.word .s:nth-of-type(1) { -webkit-transform: rotateY(0deg) translateZ(1px); transform: rotateY(0deg) translateZ(1px); } .word .s:nth-of-type(1) .p { -webkit-animation-delay: 0.1s; animation-delay: 0.1s; }

.word .s:nth-of-type(2) { -webkit-transform: rotateY(0deg) translateZ(2px); transform: rotateY(0deg) translateZ(2px); } .word .s:nth-of-type(2) .p { -webkit-animation-delay: 0.2s; animation-delay: 0.2s; }

.word .s:nth-of-type(3) { -webkit-transform: rotateY(0deg) translateZ(3px); transform: rotateY(0deg) translateZ(3px); } .word .s:nth-of-type(3) .p { -webkit-animation-delay: 0.3s; animation-delay: 0.3s; }

.word .s:nth-of-type(4) { -webkit-transform: rotateY(0deg) translateZ(4px); transform: rotateY(0deg) translateZ(4px); } .word .s:nth-of-type(4) .p { -webkit-animation-delay: 0.4s; animation-delay: 0.4s; }

.word .s:nth-of-type(5) { -webkit-transform: rotateY(0deg) translateZ(5px); transform: rotateY(0deg) translateZ(5px); } .word .s:nth-of-type(5) .p { -webkit-animation-delay: 0.5s; animation-delay: 0.5s; }

.word .s:nth-of-type(6) { -webkit-transform: rotateY(0deg) translateZ(6px); transform: rotateY(0deg) translateZ(6px); } .word .s:nth-of-type(6) .p { -webkit-animation-delay: 0.6s; animation-delay: 0.6s; }

.word .s:nth-of-type(7) { -webkit-transform: rotateY(0deg) translateZ(7px); transform: rotateY(0deg) translateZ(7px); } .word .s:nth-of-type(7) .p { -webkit-animation-delay: 0.7s; animation-delay: 0.7s; }

.word .s:nth-of-type(8) { -webkit-transform: rotateY(0deg) translateZ(8px); transform: rotateY(0deg) translateZ(8px); } .word .s:nth-of-type(8) .p { -webkit-animation-delay: 0.8s; animation-delay: 0.8s; }

.word .s:nth-of-type(9) { -webkit-transform: rotateY(0deg) translateZ(9px); transform: rotateY(0deg) translateZ(9px); } .word .s:nth-of-type(9) .p { -webkit-animation-delay: 0.9s; animation-delay: 0.9s; }

.word .s:nth-of-type(10) { -webkit-transform: rotateY(0deg) translateZ(10px); transform: rotateY(0deg) translateZ(10px); } .word .s:nth-of-type(10) .p { -webkit-animation-delay: 1s; animation-delay: 1s; }

@-webkit-keyframes pulse { 50% { fill: rgba(0, 0, 0, 0.08); stroke: rgba(0, 0, 0, 0.08); } }

@keyframes pulse { 50% { fill: rgba(0, 0, 0, 0.08); stroke: rgba(0, 0, 0, 0.08); } } @-webkit-keyframes word-rotate { 50% { -webkit-transform: rotateY(360deg) rotateZ(36deg) rotateX(18deg); transform: rotateY(360deg) rotateZ(36deg) rotateX(18deg); } } @keyframes word-rotate { 50% { -webkit-transform: rotateY(360deg) rotateZ(36deg) rotateX(18deg); transform: rotateY(360deg) rotateZ(36deg) rotateX(18deg); } }

<div class="project">
  <div class="word-x">
    <div class="word">
      <div class="s"><svg width="154" height="182" viewBox="0 0 154 182" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M129.781 165.477V116.945H145.958V181.656H0.461548V116.945H16.6379V165.477H129.781Z" fill="#BCBBBC"/>
<path d="M32.8323 149.298H113.714V133.122H32.8323V149.298ZM105.323 0.349084L92.3429 10.0028L140.614 74.9019L153.594 65.248L105.323 0.349084ZM65.2014 38.6106L127.352 90.3718L137.704 77.9411L75.5537 26.1802L65.2014 38.6106ZM44.9115 74.581L118.232 108.728L125.062 94.0641L51.7409 59.917L44.9115 74.581ZM34.4385 112.481L113.592 129.117L116.919 113.286L37.7655 96.6501L34.4385 112.481Z" fill="#F48023"/>
      </div>
      <div class="s"><svg width="154" height="182" viewBox="0 0 154 182" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M129.781 165.477V116.945H145.958V181.656H0.461548V116.945H16.6379V165.477H129.781Z" fill="#BCBBBC"/>
<path d="M32.8323 149.298H113.714V133.122H32.8323V149.298ZM105.323 0.349084L92.3429 10.0028L140.614 74.9019L153.594 65.248L105.323 0.349084ZM65.2014 38.6106L127.352 90.3718L137.704 77.9411L75.5537 26.1802L65.2014 38.6106ZM44.9115 74.581L118.232 108.728L125.062 94.0641L51.7409 59.917L44.9115 74.581ZM34.4385 112.481L113.592 129.117L116.919 113.286L37.7655 96.6501L34.4385 112.481Z" fill="#F48023"/>
      </div>
      <div class="s"><svg width="154" height="182" viewBox="0 0 154 182" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M129.781 165.477V116.945H145.958V181.656H0.461548V116.945H16.6379V165.477H129.781Z" fill="#BCBBBC"/>
<path d="M32.8323 149.298H113.714V133.122H32.8323V149.298ZM105.323 0.349084L92.3429 10.0028L140.614 74.9019L153.594 65.248L105.323 0.349084ZM65.2014 38.6106L127.352 90.3718L137.704 77.9411L75.5537 26.1802L65.2014 38.6106ZM44.9115 74.581L118.232 108.728L125.062 94.0641L51.7409 59.917L44.9115 74.581ZM34.4385 112.481L113.592 129.117L116.919 113.286L37.7655 96.6501L34.4385 112.481Z" fill="#F48023"/>
      </div>
      <div class="s"><svg width="154" height="182" viewBox="0 0 154 182" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M129.781 165.477V116.945H145.958V181.656H0.461548V116.945H16.6379V165.477H129.781Z" fill="#BCBBBC"/>
<path d="M32.8323 149.298H113.714V133.122H32.8323V149.298ZM105.323 0.349084L92.3429 10.0028L140.614 74.9019L153.594 65.248L105.323 0.349084ZM65.2014 38.6106L127.352 90.3718L137.704 77.9411L75.5537 26.1802L65.2014 38.6106ZM44.9115 74.581L118.232 108.728L125.062 94.0641L51.7409 59.917L44.9115 74.581ZM34.4385 112.481L113.592 129.117L116.919 113.286L37.7655 96.6501L34.4385 112.481Z" fill="#F48023"/>
      </div>
      <div class="s"><svg width="154" height="182" viewBox="0 0 154 182" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M129.781 165.477V116.945H145.958V181.656H0.461548V116.945H16.6379V165.477H129.781Z" fill="#BCBBBC"/>
<path d="M32.8323 149.298H113.714V133.122H32.8323V149.298ZM105.323 0.349084L92.3429 10.0028L140.614 74.9019L153.594 65.248L105.323 0.349084ZM65.2014 38.6106L127.352 90.3718L137.704 77.9411L75.5537 26.1802L65.2014 38.6106ZM44.9115 74.581L118.232 108.728L125.062 94.0641L51.7409 59.917L44.9115 74.581ZM34.4385 112.481L113.592 129.117L116.919 113.286L37.7655 96.6501L34.4385 112.481Z" fill="#F48023"/>
      </div>
      <div class="s"><svg width="154" height="182" viewBox="0 0 154 182" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M129.781 165.477V116.945H145.958V181.656H0.461548V116.945H16.6379V165.477H129.781Z" fill="#BCBBBC"/>
<path d="M32.8323 149.298H113.714V133.122H32.8323V149.298ZM105.323 0.349084L92.3429 10.0028L140.614 74.9019L153.594 65.248L105.323 0.349084ZM65.2014 38.6106L127.352 90.3718L137.704 77.9411L75.5537 26.1802L65.2014 38.6106ZM44.9115 74.581L118.232 108.728L125.062 94.0641L51.7409 59.917L44.9115 74.581ZM34.4385 112.481L113.592 129.117L116.919 113.286L37.7655 96.6501L34.4385 112.481Z" fill="#F48023"/>
      </div>
      <div class="s"><svg width="154" height="182" viewBox="0 0 154 182" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M129.781 165.477V116.945H145.958V181.656H0.461548V116.945H16.6379V165.477H129.781Z" fill="#BCBBBC"/>
<path d="M32.8323 149.298H113.714V133.122H32.8323V149.298ZM105.323 0.349084L92.3429 10.0028L140.614 74.9019L153.594 65.248L105.323 0.349084ZM65.2014 38.6106L127.352 90.3718L137.704 77.9411L75.5537 26.1802L65.2014 38.6106ZM44.9115 74.581L118.232 108.728L125.062 94.0641L51.7409 59.917L44.9115 74.581ZM34.4385 112.481L113.592 129.117L116.919 113.286L37.7655 96.6501L34.4385 112.481Z" fill="#F48023"/>
      </div>
      <div class="s"><svg width="154" height="182" viewBox="0 0 154 182" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M129.781 165.477V116.945H145.958V181.656H0.461548V116.945H16.6379V165.477H129.781Z" fill="#BCBBBC"/>
<path d="M32.8323 149.298H113.714V133.122H32.8323V149.298ZM105.323 0.349084L92.3429 10.0028L140.614 74.9019L153.594 65.248L105.323 0.349084ZM65.2014 38.6106L127.352 90.3718L137.704 77.9411L75.5537 26.1802L65.2014 38.6106ZM44.9115 74.581L118.232 108.728L125.062 94.0641L51.7409 59.917L44.9115 74.581ZM34.4385 112.481L113.592 129.117L116.919 113.286L37.7655 96.6501L34.4385 112.481Z" fill="#F48023"/>
      </div>
      <div class="s"><svg width="154" height="182" viewBox="0 0 154 182" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M129.781 165.477V116.945H145.958V181.656H0.461548V116.945H16.6379V165.477H129.781Z" fill="#BCBBBC"/>
<path d="M32.8323 149.298H113.714V133.122H32.8323V149.298ZM105.323 0.349084L92.3429 10.0028L140.614 74.9019L153.594 65.248L105.323 0.349084ZM65.2014 38.6106L127.352 90.3718L137.704 77.9411L75.5537 26.1802L65.2014 38.6106ZM44.9115 74.581L118.232 108.728L125.062 94.0641L51.7409 59.917L44.9115 74.581ZM34.4385 112.481L113.592 129.117L116.919 113.286L37.7655 96.6501L34.4385 112.481Z" fill="#F48023"/>
      </div>
      <div class="s"><svg width="154" height="182" viewBox="0 0 154 182" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M129.781 165.477V116.945H145.958V181.656H0.461548V116.945H16.6379V165.477H129.781Z" fill="#BCBBBC"/>
<path d="M32.8323 149.298H113.714V133.122H32.8323V149.298ZM105.323 0.349084L92.3429 10.0028L140.614 74.9019L153.594 65.248L105.323 0.349084ZM65.2014 38.6106L127.352 90.3718L137.704 77.9411L75.5537 26.1802L65.2014 38.6106ZM44.9115 74.581L118.232 108.728L125.062 94.0641L51.7409 59.917L44.9115 74.581ZM34.4385 112.481L113.592 129.117L116.919 113.286L37.7655 96.6501L34.4385 112.481Z" fill="#F48023"/>
      </div>
    </div>
  </div>
</div>

И полный вариант на CodePen

SVE
  • 22,387
18

Простенькая анимация, которую я нашел на CodePen и решил поделиться ею с Вами. Автор кода: клик

body{
    margin: 0;
    padding: 0;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    background: #000;
}
p{
    position: relative;
    font-family: sans-serif;
    text-transform: uppercase;
    font-size: 2em;
    letter-spacing: 4px;
    overflow: hidden;
    background: linear-gradient(90deg, #000, #fff, #000);
    background-repeat: no-repeat;
    animation: animate 3s linear infinite;
    background-size: 80%;
    -webkit-background-clip: text;
    -webkit-text-fill-color: rgba(255, 255, 255, 0);
}
@keyframes animate{
    0%
    {
        background-position: -500%;
    }
    100%
    {
        background-position: 500%;
    }
}
<p>StackOverflow</p>

UPD: Сделал что-то свое по примеру выше, на конкурс не претендую, но все же, прошу оценить.

body{
    margin: 0;
    padding: 0;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    background: #000;
}
p{
    position: relative;
    color: white;
    font-family: sans-serif;
    text-transform: uppercase;
    font-size: 2em;
    letter-spacing: 4px;
    animation: animate 3s linear infinite;
    background-size: 80%;
}
@keyframes animate{
    50%{color: white;}
    50%{color: orange; text-shadow: 0 0 5px orange, 0 0 10px orange;}
 <img src="https://upload.wikimedia.org/wikipedia/commons/8/81/Stackoverflow_icon.png">
 <p>StackOverflow</p>
18

const nearDist = 0.1;
const farDist = 30000;
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75,
window.innerWidth / window.innerHeight, nearDist, farDist);
camera.position.x = farDist * -10;
camera.position.z = 500;
const renderer = new THREE.WebGLRenderer();
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.querySelector("#canvas-wrapper").appendChild(renderer.domElement);
const cubeSize = 200;
const radius = 4;  
const detail = 2;  
var rectLight = new THREE.RectAreaLight( 0xffffff50, 110, 110, 110 );
rectLight.position.set( 0, 5, 5 );
scene.add( rectLight );
const geometry = new THREE.TetrahedronBufferGeometry(radius, detail);
const material = new THREE.MeshNormalMaterial(); 
const group = new THREE.Group();
for (let i = 0; i < 4000; i++) 
{
const mesh = new THREE.Mesh(geometry, material);
const dist = farDist / 3;
const distDouble = dist * 2;
const tau = 2 * Math.PI; 
mesh.position.x = Math.random() * distDouble - dist;
mesh.position.y = Math.random() * distDouble - dist;
mesh.position.z = Math.random() * distDouble - dist;
mesh.rotation.x = Math.random() * tau;
mesh.rotation.y = Math.random() * tau;
mesh.rotation.z = Math.random() * tau;
mesh.matrixAutoUpdate = false;
mesh.updateMatrix();
group.add(mesh);
}

scene.add(group); const loader = new THREE.FontLoader(); const textMesh = new THREE.Mesh(); const createTypo = font => { const word = "StackOverflow"; const typoProperties = { font: font, size: cubeSize, height: cubeSize / 2, curveSegments: 20, bevelEnabled: true, bevelSize: 6, bevelOffset: 1, bevelSegments: 0 };

const text = new THREE.TextGeometry(word, typoProperties, rectLight); textMesh.geometry = text; textMesh.material = material; textMesh.position.x = cubeSize * -2; textMesh.position.z = cubeSize * -1; scene.add(textMesh); };

let mouseX = 0; let mouseY = 0; const mouseFX = { windowHalfX: window.innerWidth / 2, windowHalfY: window.innerHeight / 2, coordinates: function (coordX, coordY) { mouseX = (coordX - mouseFX.windowHalfX) * 10; mouseY = (coordY - mouseFX.windowHalfY) * 10; }, onMouseMove: function (e) { mouseFX.coordinates(e.clientX, e.clientY); }, onTouchMove: function (e) { mouseFX.coordinates(e.changedTouches[0].clientX, e.changedTouches[0].clientY); } }; const render = () => { requestAnimationFrame(render); camera.position.x += (mouseX - camera.position.x) * 0.04; camera.position.y += (mouseY * -1 - camera.position.y) * 0.04; camera.lookAt(scene.position); const t = Date.now() * 0.0005; const rx = Math.sin(t * 0.5) * 0.1; const ry = Math.sin(t * 0.0) * 0.1; const rz = Math.sin(t * 0.0) * 0.1; group.rotation.x = rx; group.rotation.y = ry; group.rotation.z = rz; textMesh.rotation.x = rx; textMesh.rotation.y = ry; textMesh.rotation.z = rx; renderer.render(scene, camera); }; render();

document.addEventListener("mousemove", mouseFX.onMouseMove, false); document.addEventListener("touchmove", mouseFX.onTouchMove, false); loader.load("https://threejs.org/examples/fonts/helvetiker_regular.typeface.json", createTypo);

body {
=
  margin: 0;
  padding: 0;
  overflow: hidden;
}

*{
  border: 0;
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
  <script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/108/three.min.js'></script>
  <div id="canvas-wrapper">

Не успел полностью доделать, не разобрался с подсветкой bloom Shader, хотел сделать звезды реалестичными))

O K
  • 1,117
  • 6
  • 2
    Это уже похоже на анимацию для какой-нибудь игры про звездные войны :) Ставлю плюс, круто получилось – h4cktivist Apr 14 '20 at 07:50
  • 1
    ну так ну так ну так ну так – countervector Apr 14 '20 at 07:57
  • 1
    Звезды все таки лучше спрайтами рисовать, PointsMaterial(https://ru.stackoverflow.com/a/1083474/188366) или точками на поверхности сферы - шейдером. – Stranger in the Q Apr 14 '20 at 13:11
  • Буду изучать) Хотел сделать наподобие такого свечения, там где подписаны звезды: http://stars.chromeexperiments.com но не уложился по времени. В следующий раз как нибудь похвастаюсь достижениями) – O K Apr 14 '20 at 13:58
  • Не соответствует вопросу в текущем его виде. – andreymal Jun 29 '21 at 20:50
17

Код писался на скорую руку и там мало что будет разборчиво и хоть немного понятно, просто хотел поучаствовать :^

const h1 = document.querySelector('h1');
const h1Bound = h1.getBoundingClientRect();
charming(h1, {
 tagName: 'div',
 setClassName: () => {}
});
gsap.set(h1, {
 width: h1Bound.width,
 height: h1Bound.width
});

const divs = h1.querySelectorAll('div'); const angle = 360 / divs.length;

divs.forEach((div, index) => { charming(div, { tagName: 'span', setClassName: () => {} }); const span = div.querySelector('span'); gsap.set(div, { rotate: angle * index });

gsap.set(span, { rotate: - angle * index, opacity: 0, scale: 0 }) });

const circle = document.querySelector('.circle');

gsap.set(circle, { width: h1Bound.width, height: h1Bound.width });

const inner = circle.querySelector('.inner');

const config = { holdDuration: 1 * 1000, holdStatus: false, holdComplete: false };

circle.addEventListener('mouseenter', function() { if (config.holdComplete) return; gsap.to(this, { scale: 1.1, duration: 0.5 }); config.holdStatus = true; const date = Date.now(); const callback = () => { const difference = Date.now() - date; const percentHold = 100 * difference / config.holdDuration; gsap.set(inner, { height: percentHold + '%' }); if (percentHold >= 100) return holdHandle(); if (config.holdStatus) requestAnimationFrame(callback); } requestAnimationFrame(callback); });

circle.addEventListener('mouseleave', function() { if (config.holdComplete) return; gsap.to(this, { scale: 1, duration: 0.5, ease: "elastic.out(1, 0.4)" }); config.holdStatus = false; gsap.to(inner, { duration: 0.1, height: 0 }); });

const holdHandle = () => { config.holdComplete = true; config.holdStatus = false; const tl = new gsap.timeline({ delay: 0.5 }); tl.resume(); tl.add(gsap.to(inner, { duration: 1, opacity: 0 })); tl.add(gsap.to(circle, { duration: 0.5, scale: 1, cursor: 'default' }), '-=1'); divs.forEach(div => { const span = div.querySelector('span'); tl.add(gsap.to(span, { duration: 0.3, opacity: 1, scale: 1, ease: "back.out(3)" }), '-=0.2'); }); tl.play(); }

@import url("https://fonts.googleapis.com/css2?family=Open+Sans:wght@800&display=swap");
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  margin: 0;
  padding: 0;
  font-family: "Open Sans", sans-serif;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.circle {
  width: 25vw;
  height: 25vw;
  background-color: #bcbbbb;
  border-radius: 50%;
  cursor: pointer;
  overflow: hidden;
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
}
.circle .logo {
  width: 50%;
  height: 50%;
  object-fit: contain;
  -webkit-mask-image: url("https://image.flaticon.com/icons/svg/2111/2111806.svg");
  -webkit-mask-size: contain;
  background-color: #f48023;
}
.circle .inner {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  height: 0;
  background-color: #f48023;
}

h1 {
  /* display: none */
  font-weight: 800;
  font-size: 35px;
  transform-origin: center;
  transform-style: preserve-3d;
  position: absolute;
  pointer-events: none;
}
h1 div {
  position: absolute;
  display: block;
  height: 100%;
  width: 100%;
}
h1 div span {
  display: block;
  position: absolute;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.2.6/gsap.min.js"></script>
<script src="https://bundle.run/charming"></script>

<div class="circle">
 <div class="logo"></div>
 <div class="inner"></div>
</div>
<h1>STACKOVERFLOW</h1>
MoloF
  • 4,588
17

Анимация раскраски и оживления слова STACK

Мы собираемся все вместе на Stackoverflow, со всех русскоговорящих территорий, чтобы получить удовольствие от любимого занятия программированием. Вот эту идею в условиях конкурса я попробовал выразить в анимации.

Буквы S T A C K двигаются по одной с различных направлений карты, чтобы собраться в слово STACK и уже вместе продолжить движение,

Для того, чтобы взаимное расположение карты и маршрутов движения, были всегда жестко связаны я использовал следующий приём:

Загрузил карту в векторный редактор и нарисовал маршруты для каждой буквы (красные линии) и маршрут движения для слова целиком.(синяя линия)

введите сюда описание изображения

Скопировал все path маршрутов в отдельный файл, в котором буду делать анимацию движения.

У каждой буквы несколько анимаций:

  • движение вдоль траектории
<animateMotion xlink:href="#Sgroup" begin="btn1.click" dur="36s" restart="whenNotActive">
  <mpath xlink:href="#Strack" />
 </animateMotion>
  • Покачивание самой буквы влево-вправо при ходьбе
      <!-- Покачивание буквы S -->
   <animateTransform attributeName="transform" type="rotate" begin="btn1.click+0.5s" dur="2s"
    values="
    0, 43.25,51.14;
    10, 43.25,51.14;
    0, 43.25,51.14;
    0, 43.25,51.14"
    fill="freeze"
    repeatCount="indefinite"
    additive="sum"
    restart="whenNotActive" />
  • Имитация движения ног буквы при ходьбе

 - Чтобы цветные буквы при движении не сливались с одинаковыми цветными
   зонами карт, добавил тень с помощью SVG filter

Анимации покачивания ног требуют точного указания точки вращения, иначе нога будет летать отдельно от туловища буквы. Понадобится крайняя точка ноги. 
<p>Рассчитать координаты этой точки поможет метод JS - <code>getBBox()</code></p>
<pre><code>&lt;script&gt; 
let bb = Aright.getBBox()
console.log(bb.x);
console.log(bb.y);
&lt;/script&gt;
</code></pre>
<p>Для анимации покачивания туловища вместе с ножками, понадобится центр вращения группы элементов, обернутых в тег <code>&lt;g&gt;</code></p>
<pre><code>&lt;script&gt;
let bb = Agroup.getBBox(); 

console.log(bb.x + bb.width /2);
console.log(bb.y + bb.height /2);
&lt;/script&gt;
</code></pre>
<p>Если есть желание разобраться, как работает приложение, прочитайте пожалуйста комментарии в коде</p>
<p>Чтобы выразить настроение, помогающее программированию, - выбрал трек  <code>Bobby McFerrin don't worry be happy</code></p>
<h2>Update</h2>
<p>Сделал анимацию более динамичной.<br />
Усилил покачивание букв при движении, ускорил болтание ногами, чтобы попасть в ритм музыки, но не совсем это удалось.<br />
Добавил анимацию закраски градиентом первой буквы</p>
<p><div class="snippet" data-lang="js" data-hide="true" data-console="true" data-babel="false">
<div class="snippet-code snippet-currently-hidden">
<pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;style&gt;
.container {
width:100vw;
height:100vh;
}
&lt;/style&gt;
&lt;div class="container"&gt;
&lt;svg id="svg1" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1"  viewBox="-10 150 1800 1253" &gt;

&lt;defs&gt;
 &lt;path id="Strack" d="m322.1 281.9c0 0 75.6 16 97.2 44.3 38 49.7-13.2 140.2 30.3 185.2 32.5 33.6 94.4 9.6 137.7 27.2 26.4 10.7 44.3 38.6 71.6 46.7 7 2.1 21.8 0 21.8 0" fill="none" stroke="black" /&gt; 

 &lt;path id="Ttrack" d="m 144.7062,657.68616 c 0,0 37.753,-102.00963 83.24497,-115.92056 40.72325,-12.4527 79.61954,30.26928 119.81051,44.34545 31.19139,10.92423 61.09073,30.67633 94.13684,31.11961 25.18481,0.33783 47.2325,-23.61256 72.3531,-21.78373 26.84437,1.95434 48.54017,23.28963 73.1311,34.23157 11.57342,5.1497 19.26927,7.93532 35.00956,14.78182 32.47733,14.12656 11.1456,44.34609 68.43253,-59.12726" fill="none" /&gt;  

 &lt;path id="Atrack" d="m1145.2 859.2c0 0 25.7-28.7 27.2-46.7 2.4-27.5-8.5-59-28.8-77.8-31.6-29.4-89.6-10.3-124.5-35.8-36.7-26.9-35.4-92.1-75.5-113.6-74.3-39.8-252.9 0-252.9 0" fill="none" /&gt; 

 &lt;path id="Ctrack" d="m220 368.1c0 0 73.9 53.2 89.1 93.5 16.5 43.6-26.4 98.1-5.5 139.7 22.7 45.3 76.6 72.2 125.4 85.8 51.6 14.4 107.1-12.2 160.6-8.8 82.6 5.3 206.4 118.7 244.3 45.1 30.3-59-143.2-138.1-143.2-138.1" fill="none" /&gt; 

 &lt;path id="Ktrack" d="m1555.7 922.6c0 0 25.2-71.8 14.3-105.6-10.8-33.6-51.3-48.9-72.6-77-39.7-52.5-75.9-108.7-101.2-169.4-12.5-30.1 11.3-48.4-24.2-94.6-64.2-83.6-204.6-76.2-246.5-5.5-54.4 91.9 207.9 181.5 160.6 277.3-45.5 92.2-206 64.1-305.9 39.6C866 759.3 690.8 585.3 690.8 585.3" fill="none" /&gt;    

   &lt;path id="all_Letter" transfotm="translate(0 -55)" d="M690.8 585.3H505c0 0-229.3 55.3-267.8-25.7-23.1-48.7 71.5-83.7 89.7-134.4 16-44.7-28.4-120.8 14.2-141.8 71.8-35.4 126 108.5 204 126.5 82.6 19.1 169.7-41.5 253.1-25.9 75.4 14.1 128.4 101.5 205 104.4 94.6 3.5 169.3-129.2 261.9-109.6 92.6 19.6 181 112.9 194.9 206.5 6.8 45.6-19.5 105-61.6 123.8-60.4 27-125.4-55.6-191.5-52.5-84.9 3.9-157.1 113.9-238.7 90-64.3-18.9-60.1-131.1-119.9-161.2-46.9-23.6-157.5 0-157.5 0z" style="fill:none;stroke-width:3;stroke:#0000f1"/&gt;

         &lt;!-- Тень для букв --&gt;
    &lt;filter id="dropShadow"&gt;
      &lt;feDropShadow dx="4" dy="4" stdDeviation="8" result="shadow"/&gt;
       &lt;feComposite in2="mask" in="shadow" operator="in" result="comp" /&gt;
      &lt;feMerge result="merge"&gt;
        &lt;feMergeNode in="SourceGraphic" /&gt;
        &lt;feMergeNode in="comp" /&gt;
      &lt;/feMerge&gt; 
    &lt;/filter&gt;
    &lt;linearGradient id="gradEarth"&gt;
            &lt;stop offset="40%" stop-color="dodgerblue"&gt;&lt;/stop&gt;
            &lt;stop offset="100%" stop-color="yellowgreen" &gt;&lt;/stop&gt;
        &lt;/linearGradient&gt;   
      &lt;linearGradient id="Lg" x2="0" y2="0%"&gt;
            &lt;stop offset="10%" stop-color="yellow"&gt;&lt;/stop&gt;
            &lt;stop offset="25%" stop-color="#F437FE"&gt;&lt;/stop&gt;
            &lt;stop offset="50%" stop-color="dodgerblue"&gt;&lt;/stop&gt;
            &lt;stop offset="75%" stop-color="#1EFE6B"&gt;&lt;/stop&gt;
            &lt;stop offset="100%" stop-color="red"&gt;&lt;/stop&gt;
            &lt;animate attributeName="y2" dur="8s" values="0%;100%;100%;0%;0%" repeatCount="indefinite" /&gt;
               &lt;!-- &lt;animate attributeName="x2" dur="6s" values="0%;100%;100%;0%;0%" repeatCount="indefinite" /&gt;  --&gt;
        &lt;/linearGradient&gt;   
&lt;/defs&gt;  
   &lt;image xlink:href="https://i.stack.imgur.com/lDCcN.jpg" width="1800px" height="1253px" opacity="0.8" /&gt;

 &lt;g id="Gr_All" &gt;
   &lt;!-- Буква S --&gt;
&lt;g id="Sgroup"  transform="scale(1.5)" filter="url(#dropShadow)"&gt;
       &lt;!-- Левая нога --&gt;
 &lt;path id="leftF" fill="crimson"  d="m31.9 64.5c0 0-5.6 18.1 0 23.7 3.1 3.1 12.4 4.3 12.9 0 0.4-3.4-9.9-2.6-9.9-2.6l-3-21.2M58.7 64.5" class="leg"&gt;
    &lt;animateTransform attributeName="transform" type="rotate" begin="btn1.click" dur="0.5s"
    values="0, 29.41,64.39;30, 29.41,64.39;0, 29.41,64.39" fill="freeze" repeatCount="indefinite" /&gt;
  &lt;/path&gt;
       &lt;!-- Правая нога  --&gt;
 &lt;path id="rightF" fill="crimson" d="m58.7 64.5c0 0-5.6 18.1 0 23.7 3.1 3.1 12.4 4.3 12.9 0 0.4-3.4-9.9-2.6-9.9-2.6l-3-21.2" class="leg"&gt;
     &lt;animateTransform attributeName="transform" type="rotate" begin="btn1.click+0.25s" dur="0.5s"
    values="0, 56.21,64.39;30, 56.21,64.39;0, 29.41,64.39" fill="freeze" repeatCount="indefinite" /&gt;
&lt;/path&gt; 
          &lt;!-- Контур буквы S --&gt;  
 &lt;path  class="Sbody" fill="url(#Lg)"  d="m59.3 12.8 6.4 20.3q-5.3-4.5-9.5-6.9-4.2-2.4-6.8-2.4-2 0-3.1 1.1-1.1 1.1-1.1 3 0 2.4 2.4 4.3 2.4 1.9 7.5 3.4 11.3 3.4 15.3 6.7 4 3.3 4 8.4 0 8.3-8.1 13.6-8.1 5.3-20.9 5.3-6.5 0-12.9-2.3-6.4-2.4-11.8-6.7V69.6L13.9 49.3q4.7 3.8 9.2 5.9 4.6 2 8.3 2 4 0 6.2-1.7 2.2-1.7 2.2-4.7 0-2.8-1.8-4.5-1.8-1.7-8-3.6-9-2.9-13.5-6.8-4.4-4-4.4-9.3 0-6.7 5.9-11 5.9-4.3 15.4-4.3 6.2 0 12.2 2.2 5.9 2.2 12.2 6.9z"&gt; 
       &lt;!-- Покачивание буквы S --&gt;
   &lt;animateTransform attributeName="transform" type="rotate" begin="btn1.click+0.5s" dur="1.5s"
    values="
    0, 43.25,51.14;
    30, 43.25,51.14;
    0, 43.25,51.14;
    -30, 43.25,51.14;
    0, 43.25,51.14"
    fill="freeze"
    repeatCount="indefinite"
    additive="sum"
    restart="whenNotActive" /&gt;
&lt;/path&gt; 
&lt;/g&gt; 
   &lt;animateMotion xlink:href="#Sgroup" begin="btn1.click" dur="18s" restart="whenNotActive"&gt;
    &lt;mpath xlink:href="#Strack" /&gt;
   &lt;/animateMotion&gt;

          &lt;!-- Буква T --&gt;
&lt;g id="Tgroup" transform="scale(1.5)" filter="url(#dropShadow)"&gt;
 &lt;path id="Tleft" fill="#F437FE" d="m90.2 66.8c0 0-5.6 18.1 0 23.7 3.1 3.1 12.4 4.3 12.9 0 0.4-3.4-9.9-2.6-9.9-2.6l-3-21.2m26.8 0.1M117 66.8" class="leg"&gt;
    &lt;animateTransform attributeName="transform" type="rotate" begin="btn1.click" dur="1s"
    values="0, 87.71,66.69;30, 87.71,66.69;0, 87.71,66.69" fill="freeze" repeatCount="indefinite" /&gt;
  &lt;/path&gt;
  &lt;path id="Tright" fill="#F437FE" d="m117 66.8c0 0-5.6 18.1 0 23.7 3.1 3.1 12.4 4.3 12.9 0 0.4-3.4-9.9-2.6-9.9-2.6l-3-21.2" class="leg"&gt;
     &lt;animateTransform attributeName="transform" type="rotate" begin="btn1.click+0.5s" dur="1s"
    values="0,114.51,66.69;30, 114.51,66.69;0,114.51,66.69" fill="freeze" repeatCount="indefinite" /&gt;
&lt;/path&gt; 
 &lt;path  class="TBody" fill="#F437FE"  d="M136.9 11.5 118.6 47.3 116.2 20 108.9 60.1 121.7 69.6 87 67.7 96.1 61 85.5 19.2 81.9 52.3 74.5 15.7Z"&gt; 
      &lt;!-- Покачивание буквы T --&gt;
   &lt;animateTransform attributeName="transform" type="rotate" begin="btn1.click+0.5s" dur="2s"
    values="
           10, 105.69,52.39;
           -10, 105.69,52.39;
           -10, 105.69,52.39;
           10, 105.69,52.39"
           fill="freeze"
           repeatCount="indefinite"
           additive="sum"
           restart="whenNotActive" /&gt;
  &lt;/path&gt;          
&lt;/g&gt; 
   &lt;animateMotion xlink:href="#Tgroup" begin="btn1.click" dur="18s" restart="whenNotActive"&gt;
    &lt;mpath xlink:href="#Ttrack" /&gt;
   &lt;/animateMotion&gt;


            &lt;!-- Буква A --&gt;
&lt;g id="Agroup" transform="scale(1.5)" filter="url(#dropShadow)"&gt;
 &lt;path id="Aleft" fill="dodgerblue" d="m147.4 64.5c0 0-5.6 18.1 0 23.7 3.1 3.1 12.4 4.3 12.9 0 0.4-3.4-9.9-2.6-9.9-2.6l-3-21.2m26.8 0.1M183.5 64.5" class="leg"&gt;
    &lt;animateTransform attributeName="transform" type="rotate" begin="btn1.click" dur="0.5s"
    values="0, 144.91,64.39;30, 144.91,64.39;0, 144.91,64.39" fill="freeze" repeatCount="indefinite" /&gt;
  &lt;/path&gt;
  &lt;path id="Aright" fill="dodgerblue" d="m183.5 64.5c0 0-5.6 18.1 0 23.7 3.1 3.1 12.4 4.3 12.9 0 0.4-3.4-9.9-2.6-9.9-2.6l-3-21.2" class="leg"&gt;
     &lt;animateTransform attributeName="transform" type="rotate" begin="btn1.click+0.25s" dur="0.5s"
    values="0,181.01,64.39;30, 181.01,64.39;0,181.01,64.39" fill="freeze" repeatCount="indefinite" /&gt;
&lt;/path&gt; 
 &lt;path  class="ABody"  fill="dodgerblue" d="m171 38-5.3-15.1-5.1 18.6zm30.5 21.7-33 10.2 8.4-11.3-2.4-8.4-12.3 0.9-3.6 9.8 5.3 4.2-35.9 2.6 8.7-6.5 11.6-45.2-6.6-4.3 44.5 1.5-10.4 3.7 18.2 40.6z"&gt;
      &lt;!-- Покачивание буквы A --&gt;
   &lt;animateTransform attributeName="transform" type="rotate" begin="btn1.click+0.5s" dur="2s"
    values="
    0,164.7,51.4;
    30,164.7,51.4;
    0,164.7,51.4;
    -30,164.7,51.4;
    0,164.7,51.4"
    fill="freeze"
    repeatCount="indefinite"
    additive="sum"
    restart="whenNotActive" /&gt;
    &lt;/path&gt;
&lt;/g&gt; 
   &lt;animateMotion xlink:href="#Agroup" begin="btn1.click" dur="18s" restart="whenNotActive"&gt;
    &lt;mpath xlink:href="#Atrack" /&gt;
   &lt;/animateMotion&gt;


            &lt;!-- Буква C --&gt;
&lt;g id="Cgroup" transform="scale(1.5)" filter="url(#dropShadow)"&gt;
 &lt;path id="Cleft" fill="#1EFE6B" d="m212.7 64.5c0 0-5.6 18.1 0 23.7 3.1 3.1 12.4 4.3 12.9 0 0.4-3.4-9.9-2.6-9.9-2.6l-3-21.2m26.8 0.1M238.4 64.5" class="leg"&gt;
    &lt;animateTransform attributeName="transform" type="rotate" begin="btn1.click" dur="1s"
    values="0,210.21,64.39;30, 210.21,64.39;0,210.21,64.39" fill="freeze" repeatCount="indefinite" /&gt;
  &lt;/path&gt;
  &lt;path id="Cright" fill="#1EFE6B" d="m238.4 64.5c0 0-5.6 18.1 0 23.7 3.1 3.1 12.4 4.3 12.9 0 0.4-3.4-9.9-2.6-9.9-2.6l-3-21.2" class="leg"&gt;
     &lt;animateTransform attributeName="transform" type="rotate" begin="btn1.click+0.5s" dur="1s"
    values="0,235.91,64.39;30, 235.91,64.39;0,235.91,64.39" fill="freeze" repeatCount="indefinite" /&gt;
&lt;/path&gt; 
 &lt;path  class="CBody" fill="#1EFE6B"  d="m256.7 40.5-4 26.3-1.6-10.7q-5.5 6.5-12.1 9.9-6.6 3.4-13.8 3.4-4.7 0-9.2-1.9-4.5-2-8.1-5.7-4.3-4.3-6.6-9.7-2.3-5.4-2.3-11 0-7.8 3.3-14.2 3.3-6.4 9.3-10.5 4-2.7 8.7-4 4.7-1.3 10.1-1.3 5 0 9.2 1.6 4.3 1.6 8 4.7l2.2-6.3 3.9 20.7q-2.5-3.6-5.9-5.5-3.4-1.9-7.3-1.9-4.5 0-7.3 2.7-2.8 2.6-2.8 7 0 4.6 3.4 7.8 3.4 3.1 8.6 3.1 3.2 0 6.6-1.1 3.4-1.1 7.4-3.4z"&gt;
      &lt;!-- Покачивание буквы C --&gt;
   &lt;animateTransform attributeName="transform" type="rotate" begin="btn1.click+0.5s" dur="2s"
    values="
    10, 227.9,51.1;
    -10,227.9,51.1;
    -10, 227.9,51.1;
    10, 227.9,51.1"
    fill="freeze"
    repeatCount="indefinite"
    additive="sum"
    restart="whenNotActive" /&gt;
&lt;/path&gt;     
&lt;/g&gt; 
   &lt;animateMotion xlink:href="#Cgroup" begin="btn1.click" dur="18s" restart="whenNotActive"   &gt;
    &lt;mpath xlink:href="#Ctrack" /&gt;
   &lt;/animateMotion&gt;


            &lt;!-- Буква K --&gt;
&lt;g id="Kgroup" transform="scale(1.5)" filter="url(#dropShadow)"&gt;
 &lt;path id="Kleft" fill="#FFDD00" d="m274.6 64.5c0 0-5.6 18.1 0 23.7 3.1 3.1 12.4 4.3 12.9 0 0.4-3.4-9.9-2.6-9.9-2.6l-3-21.2m26.8 0.1M313 64.5" class="leg"&gt;
    &lt;animateTransform attributeName="transform" type="rotate" begin="btn1.click" dur="0.5s"
    values="0,272.11,64.39;30, 272.11,64.39;0,272.11,64.39"  repeatCount="indefinite" /&gt;
  &lt;/path&gt;
  &lt;path id="Kright" fill="#FFDD00" d="m313 64.5c0 0-5.6 18.1 0 23.7 3.1 3.1 12.4 4.3 12.9 0 0.4-3.4-9.9-2.6-9.9-2.6l-3-21.2" class="leg"&gt;
     &lt;animateTransform attributeName="transform" type="rotate" begin="btn1.click+0.25s" dur="0.5s"
    values="0,310.51,64.39;30, 310.51,64.39;0,310.51,64.39" fill="freeze" repeatCount="indefinite" /&gt;
&lt;/path&gt; 
 &lt;path  class="KBody" fill="#FFDD00" d="m329.1 68.8-30.1-3.7 6-3.9-17.6-18.1-2 0.4 4.1 20.1 6.4 6.8-38.1-4.3 6.8-5 3.6-41.2-7.4-4.7 30.5-3.7-8.5 6.6 2.5 16 13.4-15.9-3.7-4.6 27.7 1-19.7 15.8z"&gt;
         &lt;!-- Покачивание буквы K --&gt;
   &lt;animateTransform attributeName="transform" type="rotate" begin="btn1.click+0.5s" dur="2s"
    values="
    0, 293.5,51.3;
    30,293.5,51.3;
    0,293.5,51.3;
    -30, 293.5,51.3;
    0, 293.5,51.3"
    fill="freeze"
    repeatCount="indefinite"
    additive="sum"
    restart="whenNotActive" /&gt;
&lt;/path&gt; 
&lt;/g&gt; 
   &lt;animateMotion id="an_k" xlink:href="#Kgroup" begin="btn1.click" dur="18s" restart="whenNotActive"   &gt;
    &lt;mpath xlink:href="#Ktrack" /&gt;
   &lt;/animateMotion&gt;

       &lt;!-- Анимация всех букв вместе --&gt;
   &lt;animateMotion xlink:href="#Gr_All" begin="an_k.end" dur="18s" repeatCount="7" &gt;
    &lt;mpath xlink:href="#all_Letter" fill="freeze" additive="sum" restart="whenNotActive" /&gt;
   &lt;/animateMotion&gt;
 &lt;/g&gt;  &lt;!-- Все буквы вместе--&gt;  

 &lt;g id="btn1" transform="translate(-300,150)" onclick='play()' &gt;
     &lt;circle  cx="736" cy="263" r="8" fill="url(#gradEarth)" filter="url(#dropShadow)" /&gt; 
     &lt;text id="txt1" x="750" y="270" font-size="2rem" fill="crimson" &gt;Start&lt;/text&gt;
 &lt;/g&gt;
&lt;/svg&gt;

&lt;script&gt;
var zodiac = new Audio();
zodiac.src = src="https://ruv.hotmo.org/get/music/20170902/Bobby_McFerrin_-_Dont_Worry_Be_Happy_47980580.mp3";

function play() {
  zodiac.play();
}
&lt;/script&gt;
&lt;/div&gt;</code></pre>
</div>
</div>
</p>
Alexandr_TT
  • 110,146
  • 23
  • 114
  • 384
13

body {
 font-family: "Oswald", sans-serif;
 color: #fff;
 background: #000;
}
#wrapper {
 width: 800px;
 height: 300px;
 text-align: center;
 position: relative;
 overflow: hidden;
 font-weight: 400;
 text-transform: uppercase;
}
#t1 {
 width: 100%;
 font-size: 40px;
 letter-spacing: 15px;
 animation: t1 5000ms infinite alternate;
}
#t2 {
 width: 200%;
 position: absolute;
    top: 0;
    font-size: 80px;
    filter: blur(5px);
    letter-spacing: 45px;
    left: -50%;
    animation: t1 5000ms infinite alternate;
} 
@keyframes t1 {
 0% {
  transform: translateX(-4%);
 }
 20% {
  transform: translateX(-1%);
 }
 21.6% {
  text-shadow: none;
  font-weight: 400;
 }
 22% {
  text-shadow: 0 0 14px #fff;
  font-weight: 900;
 }
 22.4% {
  text-shadow: none;
  font-weight: 400;
 }
 30% {
  transform: translateX(-2%);
 }
 40% {
  transform: translateX(0%);
 }
 50% {
  transform: translateX(2%);
 }
 60% {
  transform: translateX(1%);
 }
 61.6% {
  text-shadow: none;
  font-weight: 400;
 }
 62% {
  text-shadow: 0 0 14px #fff;
  font-weight: 900;
 }
 62.4% {
  text-shadow: none;
  font-weight: 400;
 }
 70% {
  transform: translateX(2%);
 }
 80% {
  transform: translateX(-1%);
 }
 84.6% {
  text-shadow: none;
  font-weight: 400;
 }
 85% {
  text-shadow: 0 0 14px #fff;
  font-weight: 900;
 }
 85.4% {
  text-shadow: none;
  font-weight: 400;
 }
 90% {
  transform: translateX(1%);
 }
 100% {
  transform: translateX(4%);
 }
}
<link href="https://fonts.googleapis.com/css2?family=Oswald:wght@400;700&display=swap" rel="stylesheet">
<div id="wrapper">
<div id="t1">Stackoverflow</div>
<div id="t2">Stackoverflow</div>
</div>
br3t
  • 4,379
9

Хоть и поздно, не совсем по правилам и не так красиво, но сам недавно столкнулся с необходимостью анимировать градиент текста. Да, моё решение весьма затратно по ресурсам, не такое оригинальное, как у остальных, но очень часто нужно в реальных проектах.

Нужно было сделать просто вращение градиента с плавным переливом цветов с разной насыщенностью и яркостью. Очевидно, что в данном случае было бы логично использовать HSL. По синусоиде менять значения, только чтобы синусоиды были немного разные. В общем, вот, реализация.

Живые примеры доступны на hate-m.tk и imgay.design (просто демонстрационные страницы, переходить не рекомендую и не призываю)

Код не идеален, я не фронтендер, один из первых опытов работы с JS

let deg = Math.random() * 360;
document.documentElement.style.setProperty('--deg', `${deg}deg`);
let hues = [[145, 195], [230, 240], [320, 350], [45, 65], [75, 150], [250, 290]];
let hue1 = hues[Math.floor(Math.random() * hues.length)];
let hue2 = hues[Math.floor(Math.random() * hues.length)];
while (hue1 === hue2) {
    hue2 = hues[Math.floor(Math.random() * hues.length)];
}

function degrot() { function rot(variable, ary) { let nv = ary.shift(); ary.push(nv); let pf = "%"; if (variable.indexOf("--hue") + 1) { pf = ""; } document.documentElement.style.setProperty(variable, ${nv}${pf}); return ary }

hues1 = rot('--hue1', hues1);
hues2 = rot('--hue2', hues2);
sats1 = rot('--sat1', sats1);
sats2 = rot('--sat2', sats2);
ligs1 = rot('--lig1', ligs1);
ligs2 = rot('--lig2', ligs2);

}

let hues1 = Array.from(Array(121).keys(), x => (Math.cos(x / 120 * 2 * Math.PI) + 1) / 2 * (hue1[1] - hue1[0]) + hue1[0]); let hues2 = Array.from(Array(91).keys(), x => (Math.cos(x / 90 * 2 * Math.PI) + 1) / 2 * (hue2[1] - hue2[0]) + hue2[0]) let sats1 = Array.from(Array(61).keys(), x => (Math.cos(x / 60 * 2 * Math.PI + 1.4) + 1) / 2 * (100 - 65) + 65); let sats2 = Array.from(Array(91).keys(), x => (Math.cos(x / 90 * 2 * Math.PI) + 1) / 2 * (100 - 65) + 65); let ligs1 = Array.from(Array(151).keys(), x => (Math.cos(x / 150 * 2 * Math.PI + 1.9) + 1) / 2 * (85 - 60) + 60); let ligs2 = Array.from(Array(81).keys(), x => (Math.cos(x / 80 * 2 * Math.PI) + 1) / 2 * (85 - 60) + 60); setInterval('deg = deg + (Math.random());document.documentElement.style.setProperty("--deg", ${deg%360}deg);', 20); setInterval(degrot, 66);

#body {
  background-color: black;
  padding: 2em;
}
#text {
  font-weight: 800;
  background: linear-gradient(var(--deg, 45deg), hsl(var(--hue1), var(--sat1), var(--lig1)) 0%, hsl(var(--hue2), var(--sat2), var(--lig2)) 100%);
  display: inline;
  font-size: 3em;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}
<!--<script src="https://imgay.design/imgay.js"></script>-->
<div id="body"><h1 id="text">StackOverflow</h1></div>
  • прошу прощения - а здесь что то должно произойти ? или это просто надпись ? – Резидент Казахстана Apr 15 '20 at 05:08
  • 2
    @MaximLensky, у меня градиент переливатеся – SVE Apr 15 '20 at 05:11
  • @HamSter сорри - очевидно у меня не прогрузился скрипт - ждал около минуты - щас заработало - переливание градиента - анимация градиента - svg animation в разы шустрее - за попытку + – Резидент Казахстана Apr 15 '20 at 05:11
  • @MaximLensky, просто нет префикса для лисы, возможно, из-за этого! Я в хроме и у меня работает! Лично меня сама реализация заинтересовала ... – SVE Apr 15 '20 at 05:14
  • @HamSter я не такой вредный как инекоторые на sO и на toster но скрипт не заинтересовал меня - это делается проще ... – Резидент Казахстана Apr 15 '20 at 05:15
  • @MaximLensky, было бы интересно взглянуть на более простую реализацию)))) Потому как тут рандомные цвета, но в определенном диапазоне. Что-то подобное можно через sass сделать, но не проще, тоже с функциями и циклами. Если просто из одного цвета в другой, то да можно просто css применить – SVE Apr 15 '20 at 05:52
  • @HamSter тут уже на всех видах/способах реализация - – Резидент Казахстана Apr 15 '20 at 05:54
  • @MaximLensky, мои поиски более легкого способа не увенчились успехом, однако буду безмерно рад простому решению =-) – WhiteApfel Apr 15 '20 at 17:41
  • @HamSter, в лисе работает даже так - и на компьютере, и на обеих версиях мобильного браузера – WhiteApfel Apr 15 '20 at 17:43
  • 1
    @WhiteApfel всё нормально - не переживайте - плюсик я то поставил – Резидент Казахстана Apr 15 '20 at 17:49