Порядок и комбинирование трансформаций

Когда в одном transform перечислено несколько функций через пробел, порядок между ними важен: браузер применяет их не слева направо, а наоборот - сначала крайнюю правую, затем следующую и так далее до крайней левой. Поэтому transform: translate(80px, 0) rotate(45deg) и transform: rotate(45deg) translate(80px, 0) дают разные результаты.

Попробуй прямо сейчас: пунктирная рамка - это исходное положение блока без трансформаций. Сейчас transform: translate(80px, 0) rotate(45deg) - блок сначала поворачивается на месте, а затем сдвигается ровно на 80px вправо. Поменяй порядок на rotate(45deg) translate(80px, 0) - блок окажется совсем в другом месте: сначала он сдвигается на 80px, а потом ЭТА УЖЕ СДВИНУТАЯ точка поворачивается вокруг исходного центра - в итоге блок смещается не только вправо, но и вниз, как будто проехал по дуге.

Порядок функций в transform: почему он важен

Собственная проверка через getComputedStyle().transform подтвердила именно такую механику: браузер применяет функции внутри одного transform не в том порядке, в котором они написаны (слева направо), а в ОБРАТНОМ - сначала крайняя правая функция, потом следующая слева от неё, и так далее. Это работает как вложенные математические функции: transform: A B C равносильно "сначала C, потом B, потом A" - так же, как в записи f(g(x)) сначала вычисляется g, а потом f. Именно поэтому translate(80px, 0) rotate(45deg) и rotate(45deg) translate(80px, 0) дают разные результаты: в первом случае поворот (правая функция) применяется первым - к ещё не сдвинутому блоку, а сдвиг (левая функция) - последним, как плоское смещение уже повёрнutой фигуры. Во втором случае всё наоборот.

.card { transform: translate(80px, 0) rotate(45deg); } - блок поворачивается на месте, потом сдвигается вправо ровно на 80px.

Неправильное ожидание - что порядок функций можно менять местами без последствий, как в обычной сумме:

.card { transform: rotate(45deg) translate(80px, 0); } - те же самые числа, но блок окажется в другом месте: сдвиг здесь применяется первым, а поворот - вторым, поворачивая уже сдвинутую точку вокруг исходного центра.

Из истории

Даже сама спецификация CSS Transforms когда-то ошибалась в этом вопросе: в одном из примеров текст спецификации описывал transform: translate(80px, 80px) scale(1.5, 1.5) rotate(45deg) как применяющийся слева направо ("сначала сдвиг, потом масштаб, потом поворот") - хотя на самом деле верно ровно наоборот. Ошибку заметили и обсудили в официальном багтрекере W3C в сентябре 2015 года, после чего формулировку в спецификации поправили на корректную. Обсуждение бага в архиве W3C.

Комбинирование: transform не суммируется само по себе

Частая неожиданность: если задать transform в обычном состоянии элемента, а другой transform - в :hover, второй НЕ добавляется к первому, а полностью его заменяет. Собственная проверка это подтвердила: у кнопки с transform: translateX(-50%) в обычном состоянии и transform: rotate(20deg) на :hover, при наведении матрица трансформации становится ЧИСТЫМ поворотом - смещение translateX(-50%) полностью исчезает, и кнопка заметно "прыгает" в сторону. Чтобы оба эффекта работали вместе, нужно перечислить ОБЕ функции в одном transform внутри :hover: transform: translateX(-50%) rotate(20deg). Отдельно можно вспомнить приём из урока про translate: отдельные свойства translate, rotate и scale (не функции внутри transform, а именно свойства) устроены иначе - собственная проверка показала, что translate: -50px 0 в обычном состоянии и rotate: 20deg на :hover прекрасно работают вместе, потому что это два РАЗНЫХ CSS-свойства, и одно не перезаписывает другое.

.btn:hover { transform: translateX(-50%) rotate(20deg); } - обе функции перечислены вместе, сдвиг сохраняется вместе с поворотом.

Неправильное ожидание - что transform на :hover добавится к transform из обычного состояния:

.btn { transform: translateX(-50%); } .btn:hover { transform: rotate(20deg); } - при наведении сдвиг translateX(-50%) полностью пропадёт, останется только поворот - кнопка сместится неожиданным образом.

Частые ошибки новичков

ОшибкаЧто происходитКак исправить
Думать, что порядок функций в transform не важен Функции применяются не слева направо, а наоборот - разный порядок обычно даёт разный результат Проверять результат в блокноте при любой смене порядка, не полагаться на интуицию
Считать, что порядок ВСЕГДА меняет результат, на основе одного примера с rotate() и scale() Редкое исключение: РАВНОМЕРНЫЙ scale() (одно число или два одинаковых) на самом деле коммутирует с rotate() - именно для этой пары порядок не важен Как только в цепочке появляется translate() или НЕравномерный scale(sx, sy), порядок снова становится важным - проверять каждый случай отдельно
Задать transform на :hover и ожидать, что он добавится к transform из обычного состояния transform на :hover полностью заменяет transform из базового правила, значения не суммируются Перечислять все нужные функции вместе в каждом правиле, где меняется transform
Каждый раз переписывать длинный список функций в transform, чтобы ничего не потерять между состояниями Работает, но громоздко, и легко забыть одну из функций при следующем изменении Использовать отдельные свойства translate/rotate/scale вместо функций внутри transform - они не перезаписывают друг друга между состояниями

Шпаргалка

ЗаписьЧто означает
transform: A B C;Применяются справа налево: сначала C, потом B, потом A
translate(80px,0) rotate(45deg)Сначала поворот на месте, потом сдвиг на ровные 80px
rotate(45deg) translate(80px,0)Сначала сдвиг, потом поворот всей конструкции вокруг центра - результат другой
rotate() + равномерный scale()Редкое исключение: эти двое коммутируют, порядок не важен
transform в :hoverПолностью заменяет transform из обычного состояния, а не суммируется с ним
Отдельные translate/rotate/scaleНе перезаписывают друг друга между состояниями - альтернатива ручному перечислению

Коротко: отвечаем на вопросы

Почему rotate() и scale() вместе дают эффект, похожий на перекос (skew), а не просто поворот с масштабом?

Скорее всего дело в порядке: функции внутри transform применяются справа налево, а не в том порядке, в котором написаны. Если порядок не тот, что задумывался, результат может выглядеть искажённым, похожим на наклон. Решение - поменять функции местами и сравнить результат в живом предпросмотре, а не угадывать.

Почему при наведении transform из :hover как будто "стирает" transform из обычного состояния?

Потому что transform - это одно CSS-свойство, и его новое значение в :hover полностью заменяет старое, а не добавляется к нему. Если в обычном состоянии был, например, сдвиг для центрирования, а в :hover задан только поворот, сдвиг исчезнет. Нужно писать обе функции вместе в правиле :hover: transform: translateX(-50%) rotate(20deg).

Категория
Поделиться в социальных сетях
1. Переходы: transition
2. Трансформации: transform
3. Ключевые кадры и animation
4. Фильтры: filter
5. Практика: живые интерфейсы
6. Производительность и доступность

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

0 Комментарии

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

#buttons=(Хорошо) #days=(20)

Мы используем файлы cookie для улучшения работы сайта. Подробнее
Хорошо
×