Содержание

Крутим наклоням и раскачиваем элементы через rotate, transform-origin
12 минут чтения
Статичные модули
Динамичные модули
Содержание
Вращение — это, пожалуй, самое «дизайнерское» свойство CSS. Один и тот же rotate(45deg) на квадрате, круге и треугольнике даёт три совершенно разных визуальных результата. Квадрат при вращении мерцает углами, рисуя воображаемую окружность. Круг выглядит так, будто ничего не происходит. Треугольник создаёт агрессивную, колющую динамику.
В модуле «Движение» мы уже касались вращения мельком — маятник, орбиты и тд. Здесь разберём свойство как самостоятельный приём. От простого кручения до 3D-переворотов и вращающихся типографических конструкций.
Объект крутится. Бесконечно, ровно, без остановки. Это самый простой паттерн вращения — и при этом один из самых выразительных, если правильно подобрать форму объекта.
Тайминг тоже влияет на характер. linear — механическое, роботическое кручение, как вентилятор. ease-in-out — более живое, органическое, с замедлением в крайних точках. Для декоративных элементов, которые крутятся на фоне, linear обычно подходит лучше — равномерное вращение меньше привлекает внимание и спокойно работает фоновым слоем.
Обратите внимание на calc(100% - 80px) — это способ сделать так, чтобы объект не вылезал за границы контейнера. Функция calc() вычитает ширину самого элемента из ширины родителя, и квадрат аккуратно доезжает до правого края. Без этого приёма объект частично уедет за пределы видимой области.
<div class="M_PreviewArea">
<div class="demo-spinner"></div>
</div>
@keyframes rotation-continuous {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.demo-spinner {
position: absolute;
top: 50%;
left: 50%;
width: 100px;
height: 100px;
margin-top: -50px;
margin-left: -50px;
/* Квадрат с прозрачной серединой —
чтобы вращение считывалось визуально */
border: 4px solid #fff;
animation: rotation-continuous 4s linear infinite;
}
Попробуйте поставить рядом три фигуры: круг, квадрат и треугольник с одной и той же анимацией вращения. Это хорошее упражнение, чтобы почувствовать, как геометрия формы меняет визуальное восприятие одного и того же технического приёма.
Одно и то же свойство rotate может выглядеть совершенно по-разному — всё зависит от того, где находится точка опоры. По умолчанию элемент вращается вокруг своего центра. Стоит сдвинуть transform-origin — и визуальный эффект меняется до неузнаваемости.
transform-origin: top left — элемент вращается как дверь на петлях, закреплённых в левом верхнем углу. transform-origin: top center — маятник, подвешенный за верхнюю грань. transform-origin: 200% center — объект описывает широкую дугу вокруг точки, которая находится далеко за его пределами.
<div class="demo-offset-pivot"></div>
<div class="demo-offset-line"></div>
@keyframes rotation-offset {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.demo-offset-line {
position: absolute;
top: 50%;
left: 50%;
width: 120px;
height: 4px;
background: #fff;
/* Точка вращения — левый край линии */
transform-origin: left center;
animation: rotation-offset 5s linear infinite;
}
/* Маленькая точка в центре для наглядности */
.demo-offset-pivot {
position: absolute;
top: 50%;
left: 50%;
width: 8px;
height: 8px;
margin-top: -4px;
margin-left: -4px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.4);
}
Этот паттерн особенно выразителен для прямоугольных элементов: полосок, линий, текстовых блоков. Линия, вращающаяся из своего левого края, работает как стрелка часов. Текстовая плашка, «откидывающаяся» из верхней грани — как крышка, которая открывается.
transform-origin задаёт точку опоры относительно самого элемента, а не родителя. Если вы пишете transform-origin: 0% 0%, это верхний левый угол элемента, а не контейнера. Чтобы вращать объект вокруг точки, лежащей за его пределами, используйте значения больше 100% или отрицательные — например, transform-origin: -50px center
Маленький диапазон вращения — от −3° до 3° — с коротким циклом. Объект крутится, дрожит, трясётся, вибрирует. Это приём обладает сильным эмоциональным зарядом, который хорошо передаёт тревогу, напряжение, нестабильность, короткое замыкание.
Хорошей идей применять эффект к нескольким элементам с разной скоростью или амплитудой. Один дрожит быстро и мелко, другой — чуть медленнее и крупнее. Вместе они создают ощущение, что вся композиция трясётся, хотя каждый объект анимирован по-своему.
CSS. Минимальный rotate() с отклонением в несколько градусов и коротким animation-duration (0.1–0.3s) создаёт убедительный эффект тремора. Для более органичной дрожи используйте многошаговый @keyframes с неравномерными углами. Если все кадры симметричны (−3°, 3°, −3°, 3°), дрожь выглядит механически. Добавьте неравномерность (−2°, 3°, −1°, 2.5°, −3°) и движение станет натуральнее, менее предсказуемым.
<div class="demo-wobble-rect"></div>
@keyframes rotation-wobble {
0% { transform: rotate(0deg); }
15% { transform: rotate(-3deg); }
30% { transform: rotate(2deg); }
45% { transform: rotate(-2.5deg); }
60% { transform: rotate(1.5deg); }
75% { transform: rotate(-1deg); }
100% { transform: rotate(0deg); }
}
.demo-wobble-rect {
position: absolute;
top: 30%;
left: 50%;
width: 120px;
height: 160px;
margin-left: -60px;
background: #fff;
border-radius: 4px;
animation: rotation-wobble 0.3s ease-in-out infinite;
}
Сила этого паттерна в сдержанности. Амплитуда дрожи в 3° достаточна, чтобы передать напряжение. Если увеличить до 10–15°, это уже будет раскачивание, а не дрожь, и эмоциональный эффект изменится. Не парься, если поначалу кажется, что ничего не происходит 2–3 градуса отклонения на маленьких объектах работают тонко, но считываются.
Группа объектов, каждый из которых вращается с нарастающей задержкой. Первый повернулся через мгновение второй, потом третий. Получается эффект раскрывающегося веера, жалюзи, домино из вращающихся карточек.
В сочетании с transform-origin каскад становится ещё выразительнее. Если все полоски вращаются из своего верхнего края, они падают вниз одна за другой. Из нижнего поднимаются. Из левого раскрываются как страницы книги.
Принцип тот же, что в каскадном паттерне из модуля «Движение», nth-child и animation-delay, но здесь анимируется именно rotate(). И вот в чём разница: каскад перемещений создаёт волну, каскад вращений создаёт раскрытие. Ряд вертикальных полосок, которые последовательно откидываются — это жалюзи.
<div class="demo-cascade-slat"></div>
<div class="demo-cascade-slat"></div>
<div class="demo-cascade-slat"></div>
<div class="demo-cascade-slat"></div>
<div class="demo-cascade-slat"></div>
<div class="demo-cascade-slat"></div>
<div class="demo-cascade-slat"></div>
<div class="demo-cascade-slat"></div>
@keyframes rotation-cascade {
0% { transform: rotate(-90deg); }
40% { transform: rotate(5deg); }
70% { transform: rotate(-2deg); }
100% { transform: rotate(0deg); }
}
.demo-cascade-slat {
position: absolute;
width: 50px;
height: 140px;
background: #fff;
border-radius: 3px;
transform-origin: top center;
/* Начальное состояние до старта анимации */
transform: rotate(-90deg);
animation: rotation-cascade 0.8s ease-out both;
}
.demo-cascade-slat:nth-child(1) { left: 8%; top: 25%; animation-delay: 0s; }
.demo-cascade-slat:nth-child(2) { left: 18%; top: 25%; animation-delay: 0.1s; }
.demo-cascade-slat:nth-child(3) { left: 28%; top: 25%; animation-delay: 0.2s; }
.demo-cascade-slat:nth-child(4) { left: 38%; top: 25%; animation-delay: 0.3s; }
.demo-cascade-slat:nth-child(5) { left: 48%; top: 25%; animation-delay: 0.4s; }
.demo-cascade-slat:nth-child(6) { left: 58%; top: 25%; animation-delay: 0.5s; }
.demo-cascade-slat:nth-child(7) { left: 68%; top: 25%; animation-delay: 0.6s; }
.demo-cascade-slat:nth-child(8) { left: 78%; top: 25%; animation-delay: 0.7s; }
Обратите внимание на animation-fill-mode: both и начальное значение transform: rotate(-90deg) на самом элементе. Без этого полоски на долю секунды мелькнут в своём конечном (вертикальном) положении, а потом прыгнут в начальное. bothгарантирует, что элемент принимает стили первого кадра ещё до того, как анимация стартует.
Два объекта вращаются одновременно в противоположных направлениях. Один — по часовой стрелке, другой — против. Этот паттерн сразу создаёт визуальное напряжение, ощущение механизма, сцепленных шестерёнок.
Техника элементарная — та же анимация, но с rotate(-360deg) вместо rotate(360deg). Разницу в скоростях тоже стоит попробовать: если один объект крутится в два раза быстрее другого, соотношение их углов постоянно меняется, и визуальный рисунок становится сложнее.
<div class="demo-counter-outer"></div>
<div class="demo-counter-inner"></div>
@keyframes rotation-cw {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
@keyframes rotation-ccw {
from { transform: rotate(0deg); }
to { transform: rotate(-360deg); }
}
.demo-counter-outer {
position: absolute;
top: 50%;
left: 50%;
width: 160px;
height: 160px;
margin-top: -80px;
margin-left: -80px;
border: 3px solid #fff;
animation: rotation-cw 8s linear infinite;
}
.demo-counter-inner {
position: absolute;
top: 50%;
left: 50%;
width: 90px;
height: 90px;
margin-top: -45px;
margin-left: -45px;
border: 3px solid rgba(255, 255, 255, 0.5);
animation: rotation-ccw 5s linear infinite;
}
Попробуйте добавить третий, ещё более мелкий элемент внутри со своей скоростью и направлением. Три слоя контр-вращения с разными длительностями создают гипнотический эффект, где паттерн повторения почти не считывается.
Комбинация rotate и scale в одном @keyframes. Объект закручивается и одновременно уменьшается — словно его засасывает в воронку. Или наоборот: раскручивается из точки, разворачиваясь в полный размер. Это сильный приём для появления и исчезновения элементов, который выглядит динамичнее, чем простое fade-in.
В @keyframes можно комбинировать rotate и scale в одном свойстве transform, через пробел: transform: rotate(720deg) scale(0). Браузер интерполирует оба значения одновременно, и объект плавно раскручивается из невидимости.
<div class="demo-scale-shape"></div>
@keyframes rotation-scale-in {
0% {
transform: rotate(540deg) scale(0);
opacity: 0;
}
70% {
transform: rotate(-20deg) scale(1.05);
opacity: 1;
}
100% {
transform: rotate(0deg) scale(1);
opacity: 1;
}
}
.demo-scale-shape {
position: absolute;
top: 50%;
left: 50%;
width: 80px;
height: 80px;
margin-top: -40px;
margin-left: -40px;
background: #fff;
border-radius: 8px;
animation: rotation-scale-in 2s ease-out infinite;
}
До сих пор все вращения происходили в плоскости экрана вокруг оси Z, которая смотрит на зрителя. Но в CSS можно вращать и вокруг осей X и Y, и тогда элемент переворачивается в пространстве.
Для 3D-эффекта нужны два дополнительных свойства. perspective на родительском контейнере задаёт расстояние от зрителя до сцены — чем меньше значение, тем интереснее перспектива. backface-visibility: hidden скрывает обратную сторону элемента, что нужно для двусторонних карточек (иначе зритель видит зеркально отражённое содержимое).rotateY(180deg) переворачивает элемент вокруг вертикальной оси — как дверь. rotateX(180deg) вокруг горизонтальной, как крышка рояля. rotate3d(1, 1, 0, 180deg) по диагональной оси, что выглядит менее привычно и потому интереснее для экспериментов.
<div class="demo-3d-scene">
<div class="demo-3d-card"></div>
</div>
@keyframes rotation-3d-flip {
0% { transform: rotateY(0deg); }
100% { transform: rotateY(360deg); }
}
/* Контейнер задаёт перспективу */
.demo-3d-scene {
position: absolute;
top: 50%;
left: 50%;
width: 120px;
height: 160px;
margin-top: -80px;
margin-left: -60px;
perspective: 600px;
}
.demo-3d-card {
width: 100%;
height: 100%;
background: #fff;
border-radius: 8px;
/* Сохраняем 3D-пространство для дочерних элементов */
transform-style: preserve-3d;
animation: rotation-3d-flip 4s ease-in-out infinite;
}
Не забывайте transform-style: preserve-3d на вращающемся элементе, если внутри него есть дочерние слои (передняя и задняя стороны карточки). Без этого свойства дочерние элементы схлопнутся в плоскость, и 3D-эффект исчезнет.
Несколько текстовых элементов, расставленных по кругу в 3D-пространстве, вращаются как карусель или барабан. Каждый элемент повёрнут на свою долю от 360° и смещён по оси Z через translateZ, что выстраивает их в окружность. С perspective и preserve-3d на родителе — конструкция вращается как единый цилиндр из слов.
Это выразительный приём для типографических веб-плакатов. Вращающийся барабан из названий, дат, цитат создаёт ощущение бесконечного потока.
Технически каждый элемент — это обычный div или span, повёрнутый через rotateY на свою долю полного оборота: первый на 0°, второй на 45°, третий на 90° и так далее (для 8 элементов — шаг 45°). translateZ задаёт радиус цилиндра. Вся конструкция вращается одной анимацией на контейнере — rotateY(0deg) rotateY(360deg). Отдельные элементы не анимируются, они просто расставлены в пространстве.
<div class="demo-cylinder-scene">
<div class="demo-cylinder-drum">
<div class="demo-cylinder-item">Плакат</div>
<div class="demo-cylinder-item">Дизайн</div>
<div class="demo-cylinder-item">Код</div>
<div class="demo-cylinder-item">Форма</div>
<div class="demo-cylinder-item">Ритм</div>
<div class="demo-cylinder-item">Экран</div>
<div class="demo-cylinder-item">Скролл</div>
<div class="demo-cylinder-item">Время</div>
</div>
</div>
@keyframes rotation-cylinder {
from { transform: rotateY(0deg); }
to { transform: rotateY(360deg); }
}
/* Контейнер перспективы */
.demo-cylinder-scene {
position: absolute;
top: 50%;
left: 50%;
width: 200px;
height: 40px;
margin-top: -20px;
margin-left: -100px;
perspective: 500px;
}
/* Вращающийся барабан */
.demo-cylinder-drum {
width: 100%;
height: 100%;
transform-style: preserve-3d;
animation: rotation-cylinder 12s linear infinite;
}
/* Каждый текстовый элемент на барабане */
.demo-cylinder-item {
position: absolute;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
font-weight: 700;
color: #fff;
text-transform: uppercase;
letter-spacing: 0.1em;
backface-visibility: hidden;
}
/* Расставляем 8 элементов по кругу */
.demo-cylinder-item:nth-child(1) { transform: rotateY(0deg) translateZ(130px); }
.demo-cylinder-item:nth-child(2) { transform: rotateY(45deg) translateZ(130px); }
.demo-cylinder-item:nth-child(3) { transform: rotateY(90deg) translateZ(130px); }
.demo-cylinder-item:nth-child(4) { transform: rotateY(135deg) translateZ(130px); }
.demo-cylinder-item:nth-child(5) { transform: rotateY(180deg) translateZ(130px); }
.demo-cylinder-item:nth-child(6) { transform: rotateY(225deg) translateZ(130px); }
.demo-cylinder-item:nth-child(7) { transform: rotateY(270deg) translateZ(130px); }
.demo-cylinder-item:nth-child(8) { transform: rotateY(315deg) translateZ(130px); }
Радиус цилиндра определяется значением translateZ. Чем больше значение тем шире цилиндр и дальше друг от друга стоят элементы. Подбирайте радиус в зависимости от длины текста: короткие слова допускают маленький радиус, длинные фразы потребуют больше пространства, чтобы не накладываться друг на друга.
backface-visibility: hidden на каждом элементе цилиндра скрывает текст, когда он оказывается на дальней стороне. Без этого свойства вы увидите зеркально отражённые слова с изнанки, что обычно выглядит неряшливо. Впрочем, в некоторых плакатах именно этот эффект может работать как осознанный визуальный приём. Экспериментируйте и дерзайте.