Страницы

Поиск по вопросам

понедельник, 25 ноября 2019 г.

Хаотичное движение букв, складывающихся в слово


Как реализовать хаотичное движение букв, которые на финише складываются в слово.  

В начале процесса слово, как единое целое находится на экране. Затем оно распадается на буквы, которые начинают хаотичное движение, затем буквы обратно складываются в слово.
С помощью Javascript это довольно просто сделать,- уже существуют такие скрипты.

Возможно ли реализовать такой же принцип, как в JS средствами HTML,CSSили SVG?  

Сразу же в голову приходит такое решение.
 С помощью средств HTML можно разделить слово на отдельные буквы:

S
t 
a
с
k


и затем с помощью css-animation, как-то их анимировать. Для придания реалистичности придется прописывать перемещение каждой буквы в несколько различных позиций.
Но это будут простыни кода.
Есть ли более эффективное решение без применения Javascript? 
    


Ответы

Ответ 1



Вариант с переменными — так можно обойтись одним описанием анимации и затем только менять коэффициенты для каждой из букв. @keyframes move { 0% { transform: translate(calc(250px / var(--c1)), calc(650px / var(--c1))); } 25% { transform: translate(calc(-150px / var(--c1)), calc(325px / var(--c1))); } 50% { transform: translate(calc(185px / var(--c1)), calc(-725px / var(--c1))); } 75% { transform: translate(calc(410px / var(--c1)), calc(145px / var(--c1))); } 100% { transform: translate(0, 0); } } body { min-height: 100vh; display: flex; margin: 0; overflow: hidden; } div { margin: auto; } span { font-size: 22px; position: relative; animation: move 5s; display: inline-block; } .letters__a { --c1: 2; --c2: 3; } .letters__b { --c1: -1.5; --c2: -0.8; } .letters__c { --c1: 5; --c2: 2; } .letters__d { --c1: -2.8; --c2: -7.3; } .letters__e { --c1: -4.1; --c2: -3.6; }
A B C D E


Ответ 2



Вариант на css * { box-sizing: border-box; margin: 0; } body { text-align: center; display: flex; justify-content: center; align-items: center; height: 100vh; } span { display: inline-block; position: relative; font-size: 30px; } span:before { position: absolute; color: #F48024; } #s:before { content: 'S'; animation: animLetterS 5s linear forwards; } #t:before { content: 't'; animation: animLetterT 5s linear forwards; } #a:before { content: 'a'; animation: animLetterA 5s linear forwards; } #c:before { content: 'c'; animation: animLetterC 5s linear forwards; } #k:before { content: 'k'; animation: animLetterK 5s linear forwards; } @keyframes animLetterS { 0% { transform: translateY(-50px) translateX(-50px) rotate(35deg); } 20% { transform: translateY(-100px) translateX(50px) rotate(15deg); } 40% { transform: translateY(50px) translateX(-50px) rotate(-15deg); } 60% { transform: translateY(100px) translateX(50px) rotate(-155deg); } 80% { transform: translateY(-50px) translateX(150px) rotate(55deg); } 100% { transform: translateY(0) rotate(0); } } @keyframes animLetterT { 0% { transform: translateY(-100px) translateX(50px) rotate(15deg); } 20% { transform: translateY(-50px) translateX(-50px) rotate(35deg); } 40% { transform: translateY(-50px) translateX(150px) rotate(55deg); } 60% { transform: translateY(10px) translateX(50px) rotate(-1deg); } 80% { transform: translateY(50px) translateX(-50px) rotate(-15deg); } 100% { transform: translateY(0) rotate(0); } } @keyframes animLetterA { 0% { transform: translateY(50px) translateX(-50px) rotate(-15deg); } 20% { transform: translateY(10px) translateX(50px) rotate(-1deg); } 40% { transform: translateY(-150px) translateX(150px) rotate(55deg); } 60% { transform: translateY(-50px) translateX(-50px) rotate(95deg); } 80% { transform: translateY(-100px) translateX(50px) rotate(15deg); } 100% { transform: translateY(0) rotate(0); } } @keyframes animLetterC { 0% { transform: translateY(-50px) translateX(-50px) rotate(15deg); } 20% { transform: translateY(100px) translateX(0px) rotate(-100deg); } 40% { transform: translateY(-15px) translateX(200px) rotate(135deg); } 60% { transform: translateY(-50px) translateX(-150px) rotate(95deg); } 80% { transform: translateY(100px) translateX(-69px) rotate(15deg); } 100% { transform: translateY(0) rotate(0); } } @keyframes animLetterK { 0% { transform: translateY(250px) translateX(150px) rotate(45deg); } 20% { transform: translateY(-150px) translateX(-150px) rotate(-45deg); } 40% { transform: translateY(-50px) translateX(50px) rotate(90deg); } 60% { transform: translateY(150px) translateX(-150px) rotate(-90deg); } 80% { transform: translateY(30px) translateX(-30px) rotate(180deg); } 100% { transform: translateY(0) rotate(0); } } S t a с k

Ответ 3



Решение SVG В svg есть аналог HTML ,- S Он более функционален, но если пойти по пути решения, предложенного в вопросе, то тоже будет очень много кода. Есть более эффективное решение, но чтобы понять его, наверное надо пойти от простого к сложному. Анимация движения слова целиком Команда SVG вывода слова на экран: Stackoverflow где xи y координаты первого символа слова. Для анимации перемещения слова, нужно как-то динамически изменять или считывать эти координаты. Но в SVG нет переменных, тем более массивов как в JS Но есть возможность организовать их подобие в команде Цифры через точку с запятой указывают несколько положений по оси Х, которое будет последовательно занимать слово. Аналогичная команда пишется для координаты Y. Ниже полный код для перемещения слова целиком: Stackoverflow Stackoverflow Разбивка слова на отдельные буквы В SVG есть очень мощное средство для этой цели. Оно скрыто в команде так как каждый символ является векторным объектом, то у него есть свои координаты, используя которые, можно разбить слово на отдельные буквы. Если продолжать аналогию с JS, то это будет похоже на двумерный массив, где кажды столбец это изменяемые значения перемещения, соответствующего этому столбцу символа. S t a c k o v e r f l o w 1поз. |200 233 266 299 332 365 400 431 464 497 530 563 596; 2поз. |100 600 200 365 700 465 465 563 530 398 431 850 900; 3поз. |200 500 900 950 150 531 300 620 150 266 365 650 900; 4поз. |332 233 820 300 800 633 200 670 300 850 800 530 266; 5поз. |464 900 900 900 820 670 430 900 530 600 233 365 100; 6поз. |332 100 100 100 500 100 800 563 900 700 900 100 100; 7поз. |200 233 266 299 332 365 400 431 464 497 530 563 596 Другими словами: первый столбец, первая строка,- это координата x=200 в первой позиции перемещения, первого символа слова - "S" Затем символ "S" перемещается на 2-ю позицию x=100 и т.д. до возвращения на первоначальное место в поз.7 Второй столбец для второго символа "t", который начинает перемещение с первой позиции x="233" переходит на 2-ую позицию x="600" В процессе анимации происходит считывание первой строки, все символы расставляются в соответствии с указанными для них координатами. Далее считывается вторая строка, символы независимо друг от друга занимают свои места Каждая строка должна быть отделена от другой строки точкой с запятой. У последней строки точка с запятой не указывается. По аналогии точно такая же таблица составляется для задания координаты Y. Обе команды предназначенные для изменения координат X и Y начинают работат одновременно, обеспечивая тем самым одновременное изменение координат в каждой позиции движения, для каждой буквы. Ниже код анимации иммитируюшей хаотичное движение букв: Animation of text x and y attributes Stackoverflow Stackoverflow Получился очень мощный инструмент для этого вида анимации. Можно поиграться с ним изменять скорость, время начала, добавляя события сделать анимацию интерактивной, изменяя время продолжительности для анимации можно достичь эффекта, "горизонтальной" и "вертикальной парковки" букв на финише анимации. Можно заменить текст анимации на другой. Если будет короче исходного, то будет работат точно также. Если будет длиннее 13 символов, то лишние символы будут приклеены к 13 символу и будут двигаться вместе с ним одной группой. Ниже примеры: Горизонтальная парковка букв Эффект достигается разницей времени выполнения двух анимаций. Горизонтальная анимация на 1сек. длится больше. Animation of text x and y attributes Stackoverflow Stackoverflow Вертикальная парковка букв Animation of text x and y attributes Stackoverflow Stackoverflow Подставляем другие буквы: Animation of text x and y attributes Svg-art.ru Svg-art.ru

Ответ 4



Пример с использованием GSAP и псевдо-рандомайзом. Все параметры, начиная от скорости каждого шага и до временной функции настраиваемые, очень удобная штука. var master = new TimelineMax(), boxWidth = $('body').outerWidth(), boxHeight = $('body').outerHeight(), duration = 3; master.add(step1()) .add(step2()) .add(step3()); function step1() { var letters = new TimelineMax(), letter = $('span'), minX = -$('div').offset().left, minY = -$('div').offset().top, maxX = boxWidth - $('div').offset().left, maxY = boxHeight - $('div').offset().top; letter.each(function(index, $item) { TweenLite.set($item, { left: Math.random() * (maxX - minX) + minX, top: Math.random() * (maxY - minY) + minY }); letters.to($item, duration, { left: Math.random() * (maxX - minX) + minX, top: Math.random() * (maxY - minY) + minY, ease: Linear.easeNone }, 0); }); return letters; } function step2() { var letters = new TimelineMax(), letter = $('span'), minX = -$('div').offset().left, minY = -$('div').offset().top, maxX = boxWidth - $('div').offset().left, maxY = boxHeight - $('div').offset().top; letter.each(function(index, $item) { letters.to($item, duration, { left: Math.random() * (maxX - minX) + minX, top: Math.random() * (maxX - minX) + minX, ease: Linear.easeNone }, 0); }); return letters; } function step3() { var letters = new TimelineMax(), letter = $('span'); letter.each(function(index, $item) { letters.to($item, duration, { left: 0, top: 0, ease: Linear.easeNone }, 0); }); return letters; } body { min-height: 100vh; display: flex; margin: 0; overflow: hidden; } div { margin: auto; } span { font-size: 22px; position: relative; }
A B C D E


Ответ 5



Вариант с использованием препроцессора SCSS SCSS - 85 строк кода /* ----- variables ----- */ $font-family: 'Segoe UI', Arial, sans-serif; $fw700: 700; $color-default: #ccc; $letter-size: 13vh; $letter-count: 13; $full-height: 100vh; $colors: #fd6347, #008080, #6a5acd, #2e8b57, #ff4500, #32cd32, #f48024; $letters: S, t, a, c, k, o, v, e, r, f, l, o, w; /* ----- mixin ----- */ @mixin box-sizing($box-model) { -webkit-box-sizing: $box-model; box-sizing: $box-model; } @mixin centered { display: flex; justify-content: center; align-items: center; } @mixin reset { margin: 0; padding: 0; } *, *:after, *:before { @include box-sizing(border-box); } * { @include reset; } body { height: $full-height; @include centered; overflow: hidden; font-family: $font-family; } .letter { display: inline-block; position: relative; color: $color-default; font-size: $letter-size; } @for $i from 1 through $letter-count { $rotation: random(360); $colors-random: nth($colors, random(length($colors))); @keyframes animLetter-#{$i} { 0% { transform: translate(random(200) - 100 + px, random(200) - 100 + px) rotate(#{$rotation}deg); } 20% { transform: translate(random(200) - 100 + px, random(200) - 100 + px) rotate(#{$rotation}deg); } 40% { transform: translate(random(200) - 100 + px, random(200) - 100 + px) rotate(#{$rotation}deg); } 60% { transform: translate(random(200) - 100 + px, random(200) - 100 + px) rotate(#{$rotation}deg); } 80% { transform: translate(random(200) - 100 + px, random(200) - 100 + px) rotate(#{$rotation}deg); } 100% { transform: translate(0) rotate(0); color: #f48024; } } .letter { &:nth-child(n + 6){ font-weight: $fw700; } &:nth-child(#{$i}):before { content: "#{nth($letters, $i)}"; position: absolute; color: $colors-random; animation-name: animLetter-#{$i}; animation-duration: 5s; animation-timing-function: linear; animation-fill-mode: forwards; } } } CSS - 430 строк Рандомно изменяется position transform translate Рандомно изменяется position transform rotate Рандомно изменяется color letters Codepen Скомпилированный вариант на css (т.к здесь нет поддержки scss) *, *:after, *:before { -webkit-box-sizing: border-box; box-sizing: border-box; } * { margin: 0; padding: 0; } body { height: 100vh; display: flex; justify-content: center; align-items: center; overflow: hidden; } .letter { display: inline-block; position: relative; font-size: 30px; } @keyframes animLetter-1 { 0% { transform: translate(67px, -41px) rotate(303deg); } 20% { transform: translate(-80px, -88px) rotate(303deg); } 40% { transform: translate(-79px, 76px) rotate(303deg); } 60% { transform: translate(-28px, -2px) rotate(303deg); } 80% { transform: translate(34px, -17px) rotate(303deg); } 100% { transform: translate(0) rotate(0); color: #F48024; } } .letter:nth-child(1):before { content: "S"; position: absolute; color: #FF4500; animation-name: animLetter-1; animation-duration: 5s; animation-timing-function: linear; animation-fill-mode: forwards; } @keyframes animLetter-2 { 0% { transform: translate(-94px, 94px) rotate(272deg); } 20% { transform: translate(-18px, -14px) rotate(272deg); } 40% { transform: translate(-32px, -6px) rotate(272deg); } 60% { transform: translate(86px, 38px) rotate(272deg); } 80% { transform: translate(-19px, -88px) rotate(272deg); } 100% { transform: translate(0) rotate(0); color: #F48024; } } .letter:nth-child(2):before { content: "t"; position: absolute; color: #008080; animation-name: animLetter-2; animation-duration: 5s; animation-timing-function: linear; animation-fill-mode: forwards; } @keyframes animLetter-3 { 0% { transform: translate(77px, 93px) rotate(140deg); } 20% { transform: translate(-56px, -45px) rotate(140deg); } 40% { transform: translate(66px, -8px) rotate(140deg); } 60% { transform: translate(-89px, -26px) rotate(140deg); } 80% { transform: translate(96px, 31px) rotate(140deg); } 100% { transform: translate(0) rotate(0); color: #F48024; } } .letter:nth-child(3):before { content: "a"; position: absolute; color: #32CD32; animation-name: animLetter-3; animation-duration: 5s; animation-timing-function: linear; animation-fill-mode: forwards; } @keyframes animLetter-4 { 0% { transform: translate(-54px, 32px) rotate(316deg); } 20% { transform: translate(-15px, -53px) rotate(316deg); } 40% { transform: translate(56px, -34px) rotate(316deg); } 60% { transform: translate(-21px, 6px) rotate(316deg); } 80% { transform: translate(55px, 3px) rotate(316deg); } 100% { transform: translate(0) rotate(0); color: #F48024; } } .letter:nth-child(4):before { content: "c"; position: absolute; color: #008080; animation-name: animLetter-4; animation-duration: 5s; animation-timing-function: linear; animation-fill-mode: forwards; } @keyframes animLetter-5 { 0% { transform: translate(82px, 81px) rotate(224deg); } 20% { transform: translate(-44px, -43px) rotate(224deg); } 40% { transform: translate(-82px, 30px) rotate(224deg); } 60% { transform: translate(90px, 98px) rotate(224deg); } 80% { transform: translate(30px, 27px) rotate(224deg); } 100% { transform: translate(0) rotate(0); color: #F48024; } } .letter:nth-child(5):before { content: "k"; position: absolute; color: #008080; animation-name: animLetter-5; animation-duration: 5s; animation-timing-function: linear; animation-fill-mode: forwards; } @keyframes animLetter-6 { 0% { transform: translate(-44px, 35px) rotate(109deg); } 20% { transform: translate(51px, -76px) rotate(109deg); } 40% { transform: translate(14px, 71px) rotate(109deg); } 60% { transform: translate(19px, 16px) rotate(109deg); } 80% { transform: translate(97px, 52px) rotate(109deg); } 100% { transform: translate(0) rotate(0); color: #F48024; } } .letter:nth-child(6):before { content: "o"; position: absolute; color: #008080; animation-name: animLetter-6; animation-duration: 5s; animation-timing-function: linear; animation-fill-mode: forwards; } @keyframes animLetter-7 { 0% { transform: translate(37px, 28px) rotate(146deg); } 20% { transform: translate(-72px, -70px) rotate(146deg); } 40% { transform: translate(66px, 29px) rotate(146deg); } 60% { transform: translate(-9px, 42px) rotate(146deg); } 80% { transform: translate(-25px, -6px) rotate(146deg); } 100% { transform: translate(0) rotate(0); color: #F48024; } } .letter:nth-child(7):before { content: "v"; position: absolute; color: #008080; animation-name: animLetter-7; animation-duration: 5s; animation-timing-function: linear; animation-fill-mode: forwards; } @keyframes animLetter-8 { 0% { transform: translate(22px, -10px) rotate(203deg); } 20% { transform: translate(-94px, -60px) rotate(203deg); } 40% { transform: translate(7px, -12px) rotate(203deg); } 60% { transform: translate(98px, 95px) rotate(203deg); } 80% { transform: translate(58px, 99px) rotate(203deg); } 100% { transform: translate(0) rotate(0); color: #F48024; } } .letter:nth-child(8):before { content: "e"; position: absolute; color: #FF4500; animation-name: animLetter-8; animation-duration: 5s; animation-timing-function: linear; animation-fill-mode: forwards; } @keyframes animLetter-9 { 0% { transform: translate(67px, 51px) rotate(303deg); } 20% { transform: translate(-21px, 30px) rotate(303deg); } 40% { transform: translate(-52px, -29px) rotate(303deg); } 60% { transform: translate(-32px, -53px) rotate(303deg); } 80% { transform: translate(-43px, -90px) rotate(303deg); } 100% { transform: translate(0) rotate(0); color: #F48024; } } .letter:nth-child(9):before { content: "r"; position: absolute; color: #6A5ACD; animation-name: animLetter-9; animation-duration: 5s; animation-timing-function: linear; animation-fill-mode: forwards; } @keyframes animLetter-10 { 0% { transform: translate(30px, -96px) rotate(344deg); } 20% { transform: translate(31px, 60px) rotate(344deg); } 40% { transform: translate(10px, 5px) rotate(344deg); } 60% { transform: translate(-34px, 32px) rotate(344deg); } 80% { transform: translate(-81px, 43px) rotate(344deg); } 100% { transform: translate(0) rotate(0); color: #F48024; } } .letter:nth-child(10):before { content: "f"; position: absolute; color: #008080; animation-name: animLetter-10; animation-duration: 5s; animation-timing-function: linear; animation-fill-mode: forwards; } @keyframes animLetter-11 { 0% { transform: translate(52px, 32px) rotate(320deg); } 20% { transform: translate(59px, -45px) rotate(320deg); } 40% { transform: translate(-92px, 52px) rotate(320deg); } 60% { transform: translate(72px, -88px) rotate(320deg); } 80% { transform: translate(-24px, -94px) rotate(320deg); } 100% { transform: translate(0) rotate(0); color: #F48024; } } .letter:nth-child(11):before { content: "l"; position: absolute; color: #FF4500; animation-name: animLetter-11; animation-duration: 5s; animation-timing-function: linear; animation-fill-mode: forwards; } @keyframes animLetter-12 { 0% { transform: translate(35px, -70px) rotate(359deg); } 20% { transform: translate(83px, -53px) rotate(359deg); } 40% { transform: translate(-59px, 34px) rotate(359deg); } 60% { transform: translate(-9px, -34px) rotate(359deg); } 80% { transform: translate(-5px, -6px) rotate(359deg); } 100% { transform: translate(0) rotate(0); color: #F48024; } } .letter:nth-child(12):before { content: "o"; position: absolute; color: #FD6347; animation-name: animLetter-12; animation-duration: 5s; animation-timing-function: linear; animation-fill-mode: forwards; } @keyframes animLetter-13 { 0% { transform: translate(19px, 94px) rotate(200deg); } 20% { transform: translate(-57px, 99px) rotate(200deg); } 40% { transform: translate(67px, 64px) rotate(200deg); } 60% { transform: translate(-20px, -25px) rotate(200deg); } 80% { transform: translate(93px, -8px) rotate(200deg); } 100% { transform: translate(0) rotate(0); color: #F48024; } } .letter:nth-child(13):before { content: "w"; position: absolute; color: #2E8B57; animation-name: animLetter-13; animation-duration: 5s; animation-timing-function: linear; animation-fill-mode: forwards; }
S t a с k o v e r f l o w


Комментариев нет:

Отправить комментарий