Почему анимация в Zero Block не работает, хотя CSS написан верно
Zero Block выписывает для каждого элемента артборда собственное правило, в селекторе которого стоит id секции. Его вес — (1,3,0), и ваше правило по классу с весом (0,2,0) проигрывает ему всегда. Проигрывает молча: скрипт отработал, атрибуты на месте, в консоли чисто, анимации нет. Разбираем, что именно пишет Zero Block, почему !important закрывает симптом, а не задачу, и почему прозрачность в Тильде ставят инлайном, а сдвиг — только правилом.
Симптом всегда один и тот же. Вы пишете в блок T123 несколько строк CSS — спрятать текст и показать его по скроллу, — публикуете страницу, и текст просто стоит на месте. В консоли пусто. Селектор в инспекторе находится. Правило написано верно. Ничего не происходит.
Короткий ответ
Ваше правило есть, но браузер его отбросил. Zero Block выписывает для каждого
элемента артборда своё правило, и в селекторе стоит id секции — вес (1,3,0).
Правило по классу секции весит (0,2,0) и проигрывает по первому же разряду.
Отброшены и opacity, и transition, которым собирались показать текст. Решение
зависит от свойства: прозрачность ставят только инлайном, сдвиг — только
правилом.
Сначала: не занята ли анимация самой Тильдой
Проверка на тридцать секунд, которая иногда закрывает вопрос целиком. У элемента Zero Block есть своя панель «Анимация», и если дизайнер её включил, то движением элемента уже владеет Тильда. Ваш эффект в этом случае не «не работает» — он воюет с её эффектом за один и тот же элемент, и результат зависит от того, кто успел последним.
Систем анимации у Тильды не одна, и по одному признаку их не видно:
data-animate-style— обычное появление;data-animate-sbs-event,-sbs-opts,-sbs-trgels— пошаговая анимация; она ещё и заворачивает содержимое элемента в свою обёртку.tn-atom__sbs-anim-wrapper;data-animate-prx,-prx-dx— параллакс, он тоже правитtransformна скролле;data-animate-fix,data-animate-chain— фиксация и связки.
Поэтому смотреть надо не на конкретный атрибут, а на приставку:
function animatedByTilda(el) {
for (var node = el; node && node.nodeType === 1; node = node.parentElement) {
for (var i = 0; i < node.attributes.length; i++) {
if (node.attributes[i].name.indexOf('data-animate-') === 0) return true;
}
}
return false;
}
Проверять надо и родителей: анимацию дизайнер включает и группе. Если функция
вернула true — правильный ответ лежит не в CSS, а в той же панели «Анимация».
Она умеет больше, чем принято думать: у пошаговой анимации есть и события
hover/click, и список элементов-триггеров, так что «наводишь на пункт
списка — двигается картинка рядом» делается настройками. Начинать стоит со
справки Тильды про пошаговую анимацию,
а не со скрипта.
Что Zero Block пишет для каждого элемента
Откройте инспектор на опубликованной странице с артбордом и посмотрите на любой текстовый элемент. Рядом с вашими правилами найдётся такое:
#rec1024570506 .tn-elem[data-elem-id="1738663428334"] .tn-atom {
opacity: 0.8;
transition:
background-color 0.3s ease-in-out,
color 0.3s ease-in-out,
border-color 0.3s ease-in-out,
box-shadow 0.3s ease-in-out;
}
Здесь важно каждое слово селектора:
#rec1024570506— id секции. Один идентификатор в селекторе..tn-elem[data-elem-id="…"]— класс и атрибут. Ещё два разряда среднего веса..tn-atom— третий.
Итого (1,3,0): один идентификатор, три класса-атрибута, ноль элементов.
opacity в этом правиле появляется не всегда — только если дизайнер выставил
элементу прозрачность в панели. transition для ховера — почти всегда.
Почему .my-class .tn-atom проигрывает — и почему этого не видно
Правило, которое обычно пишут в T123, выглядит так:
.my-reveal .tn-atom {
opacity: 0;
transition: opacity 0.6s ease;
}
Вес — (0,2,0): два класса. Сравнение специфичности идёт по разрядам слева
направо, и первый же разряд решает всё: 1 против 0. Ни второй разряд, ни
третий, ни порядок правил в документе уже не рассматриваются. Ваше правило
проиграет, даже если оно написано ниже, даже если оно подключено позже.
Отдельная беда — то, как это выглядит со стороны. Скрипт, который навешивает класс, отработал без ошибок. Класс на секции стоит. Селектор в инспекторе находится — и в панели «Styles» его даже видно, только перечёркнутым. Проверка «мод сработал» проходит. Не проходит только сама анимация, и об этом браузер никому не сообщает.
Это и есть характер всей работы с Тильдой: почти все поломки здесь молчаливые. Ничего не падает — просто ничего не происходит.
Что пробуют дальше и почему это не помогает
Дописать ещё один класс. .t396 .my-reveal .tn-atom — это (0,3,0). Первый
разряд остался нулём, сравнение снова заканчивается на нём. Классов можно
приписать пять, результат не изменится.
Поставить в селектор id записи. #rec1024570506 .my-reveal .tn-atom даёт
(1,3,0) — ровно столько же, сколько у правила Тильды, и дальше исход решает
порядок в документе. Правило начинает применяться, и это худший из возможных
исходов: id записи принадлежит не вам. Он меняется, когда страницу дублируют,
когда блок копируют в другую страницу, когда секцию пересоздают. Тот же код в
общем для сайта блоке T123 сработает на одной странице и промолчит на остальных.
Через полгода никто не свяжет «анимация пропала» с тем, что страницу копировали.
Подключить свой CSS ниже. Порядок в каскаде рассматривается только при равном весе. При разном — не рассматривается вообще, где бы ваше правило ни стояло.
Почему !important «работает» и всё равно неверный ответ
!important поднимает объявление выше любой специфичности, и правило начинает
применяться. Симптом уходит. Проблема — в том, что вы перебиваете не только
opacity.
Посмотрите на правило Zero Block ещё раз: в нём вместе с прозрачностью лежит
transition для ховера — тот, который дизайнер настроил в панели «При
наведении». Ваше transition: opacity 0.6s ease !important его затрёт, и ховер
элемента перестанет работать. Не сломается заметно — просто станет мгновенным.
Никто не свяжет это с анимацией появления, добавленной три месяца назад.
Вторая причина серьёзнее. !important в таблице стилей остаётся там навсегда.
Анимация появления нужна на шестьсот миллисекунд, а перебитая специфичность
живёт всё время, пока страница открыта. Инлайновый стиль даёт ровно тот же
приоритет и при этом снимается одной строкой:
el.style.removeProperty('opacity');
el.style.removeProperty('transition');
После этого элемент снова живёт по правилам дизайнера — со своей прозрачностью и своим ховером.
opacity — только инлайном, transform — только правилом
Дальше начинается неочевидное. Правило «пишите инлайном» верно не для всех свойств: у прозрачности и у сдвига опасности зеркальные.
| Свойство | Где его пишет Тильда | Где можно писать вам |
|---|---|---|
opacity | В правиле элемента, вес (1,3,0). Инлайном — никогда. | Только инлайном. Инлайн перебивает правило, и Тильда его не затирает. |
transition | В правиле элемента (ховер). Инлайном — никогда. | Только инлайном, и снимать, когда анимация кончилась. |
transform | Инлайном, при каждой перерисовке артборда. В правиле — нет. | Только правилом. Инлайн затрёт следующая перерисовка. |
height, width, left, top | Инлайном, при каждой перерисовке. | Нигде. Раскладка артборда принадлежит Zero Block. |
Прозрачность и переход Zero Block инлайном не пишет никогда — это место
свободно, и занять его безопасно. А вот transform он пишет инлайном сам: этим
он позиционирует элементы артборда и пересчитывает их при изменении размера
окна. Ваш инлайновый transform доживёт до первой перерисовки — то есть до
поворота телефона, до открытия клавиатуры, до любого события, на которое Zero
Block пересчитывает артборд.
Поэтому сдвиг остаётся правилом. Правило Тильда не затирает, потому что своего
transform в правилах она не держит:
.mk-reveal [data-mk-reveal]:not([data-mk-fade]) {
transform: translate3d(var(--mk-x, 0px), var(--mk-y, 0px), 0);
}
.mk-reveal [data-mk-reveal='in']:not([data-mk-fade]) {
transform: translate3d(0, 0, 0);
}
Состояние здесь переключается атрибутом, а величина сдвига приезжает
переменной — её ставит скрипт инлайном, и это единственное инлайновое значение,
которое transform терпит, потому что само свойство остаётся в правиле.
Где transform вообще нельзя брать
Есть класс элементов, у которых сдвиг не сработает никаким способом. Если у
элемента (или у его обёртки в двух шагах вверх) задан backdrop-filter, Zero
Block переносит transform с .tn-atom на обёртку, а самому атому ставит
transform: none — инлайном. Инлайн перебьёт ваше правило, и элемент застынет
посреди сдвига: он выехал на 24 пикселя и остался там.
Проверить это до того, как что-то ставить, можно прямо из скрипта:
function canTransform(el) {
var node = el;
for (var depth = 0; node && depth < 3; depth++) {
var s = getComputedStyle(node);
var bf = s.backdropFilter || s.webkitBackdropFilter;
if (bf && bf !== 'none') return false;
node = node.parentElement;
}
return true;
}
Три узла — не магическое число, а ровно та вложенность, которая есть. Проверять
надо .t396__elem: именно на нём Zero Block смотрит backdrop-filter
(t396__processElementsTransform в tilda-zero-1.1.min.js). А в функцию вы
передаёте .tn-atom, потому что двигать надо его. Атом лежит либо прямым ребёнком
элемента, либо под одной обёрткой — .tn-atom__sbs-anim-wrapper, -prx-wrapper
или -sticky-wrapper. Атом → обёртка → элемент: три узла, ни одного лишнего.
И ещё одно, из-за чего эту проверку нельзя пропустить «потому что у меня всё
работает». t396__processElementsTransform вызывается не один раз: она же
отрабатывает при смене ширины окна и при повороте экрана. К этому моменту
вычисленный трансформ атома — это уже ваш трансформ. Тильда прочитает его как
дизайнерский, выпишет атому transform: none и приколотит ваше текущее значение к
обёртке. Элемент замрёт в той позе, в которой его застал поворот телефона.
Для таких элементов остаётся проявление по прозрачности. Оно работает всегда:
инлайновой opacity Тильда не пишет нигде.
Не считайте opacity: 1 целью
Самая тихая ошибка из всех. Стандартная анимация появления выглядит как «от 0 до 1», и почти во всех примерах в интернете написано именно так.
Но opacity: 0.8 в правиле Zero Block означает, что дизайнер задал этому
элементу восемьдесят процентов прозрачности осознанно. Анимация «до единицы»
сделает текст ярче, чем его задумали, — и оставит его таким. Никто не напишет
вам об этом в поддержку: страница выглядит нормально, просто не так, как в
макете.
Цель нужно прочитать у браузера до того, как прятать элемент:
function ownOpacity(el) {
var v = parseFloat(getComputedStyle(el).opacity);
return isNaN(v) ? 1 : v;
}
И из той же проверки следует ещё одно правило: если у элемента прозрачность близка к нулю, его спрятал сам дизайнер. Проявлять такой элемент — не ваше дело; его надо пропустить.
В обычных блоках этой проблемы нет
Всё описанное — про Zero Block, и только про него. Обычные блоки Тильды (T030,
T015, T060 и остальные) правил с id записи для отдельных элементов не пишут:
внутри них заголовок и текст размечены классами .t-title и .t-text, и вес
таких правил — те же (0,2,0), что у вашего. При равном весе решает порядок в
документе, а <style> из блока T123 стоит в документе позже подключённых стилей
Тильды. Ваше правило выигрывает.
Отсюда две практические вещи. Первая: если эффект работает в одной секции и не работает в другой — посмотрите, какая из них Zero Block; чаще всего этим различием всё и объясняется. Вторая: приёмы из этой статьи не нужно тащить в обычные блоки. Прозрачность инлайном там тоже сработает, но снимать её потом придётся руками, а выигрыша не будет никакого.
Как проверить, что анимация есть, а не «скрипт сработал»
Проверка вида «класс на месте, атрибут поставился, ошибок нет» этот класс поломок не видит вообще. Она проверяет ваш код, а сломалось не в нём, а в каскаде.
Спрашивать надо у браузера — есть ли на элементе настоящая анимация:
document.getAnimations().filter((a) => a.effect.target.matches('[data-mk-reveal]'));
Пустой массив в момент, когда секция вошла в экран, — это и есть диагноз: перехода не было, элемент просто нарисовался в конечном состоянии. Непустой — анимация играет, и можно смотреть уже на её длительность и задержки.
Второй способ, без консоли: откройте вкладку «Animations» в инструментах разработчика и прокрутите до секции. Если полоса не появилась — анимации нет.
Чек-лист диагностики
Пройдите сверху вниз — почти всегда останавливается на первых трёх пунктах.
- Страница опубликована, а не открыта в редакторе. В редакторе Тильда не выполняет пользовательский JS.
- Кеш сброшен — Ctrl+Shift+R. Тильда отдаёт закешированный HTML до пяти минут.
- В инспекторе ваше правило не перечёркнуто. Перечёркнуто — вы попали именно в эту статью: перепишите прозрачность инлайном.
- Класс стоит на секции, а не на элементе Zero Block. Настройки блока → CSS класс. Не у элемента внутри артборда.
opacityвы ставите инлайном,transform— правилом. Наоборот — не работает ни то, ни другое, но по разным причинам.- Целевая прозрачность прочитана у элемента, а не взята за единицу.
- У элемента нет
backdrop-filter— иначе сдвига не будет, только проявление. - Инлайновые стили снимаются после анимации. Иначе ховер дизайнера мёртв.
document.getAnimations()непуст в момент входа секции в экран.- На секции нет второй анимации — ни вашей, ни встроенной в Тильду. Если у
элемента есть любой атрибут, начинающийся с
data-animate-, его анимацией уже владеет Тильда, и в него лучше не лезть.
Если же document.getAnimations() пуст всегда и ни у одного элемента анимации нет
вовсе, дело может быть не в каскаде: секция могла просто ни разу не быть признана
вошедшей в экран. Это отдельная поломка со своей арифметикой — порог наблюдателя
и высота секции.