Текст · Появлениеfx/03

AW-Flow — Mask Reveal

Строки текста выезжают из-под невидимой маски одна за другой — классика редакционных сайтов.

Запуск
при появлении в экране
Параметров
9
Телефоны
свои настройки
Код
HTML-блок
.awf-text-mask

Готовый код

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

класс: awf-text-mask4,3 КБ · HTML + CSS + JS
<!-- AW-Flow — Mask Reveal · класс элемента: awf-text-mask -->
<style>
.awf-text-mask {
  --awf-rotate: 4deg;
  --awf-duration: 950ms;
  --awf-stagger: 120ms;
  --awf-delay: 0ms;
  --awf-ease: cubic-bezier(0.16, 1, 0.3, 1);
}
.awf-text-mask:not(.awf-ready) { opacity: 0; }
.awf-text-mask .awf-w {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
  padding-bottom: 0.14em;
  margin-bottom: -0.14em;
}
.awf-text-mask .awf-p {
  display: inline-block;
  transform: translate3d(0, 110%, 0) rotate(var(--awf-rotate));
  transform-origin: 0 100%;
  transition: transform var(--awf-duration) var(--awf-ease) calc(var(--awf-delay) + var(--i, 0) * var(--awf-stagger));
}
.awf-text-mask.awf-in .awf-p { transform: none; }
.awf-text-mask.awf-off,
.awf-text-mask.awf-off * { transition: none !important; }
/* уважение к настройке «уменьшить движение» */
@media (prefers-reduced-motion: reduce) {
  .awf-text-mask, .awf-text-mask .awf-p { opacity: 1 !important; transform: none !important; transition: none !important; }
}
</style>
<script>
(function () {
  var CLS = 'awf-text-mask';
  var reduce = window.matchMedia && matchMedia('(prefers-reduced-motion: reduce)').matches;
  function split(el, mode) {
    var root = el.querySelector('.tn-atom') || el;
    var parts = [];
    (function walk(node) {
      [].slice.call(node.childNodes).forEach(function (n) {
        if (n.nodeType === 1) { if (n.tagName !== 'BR') walk(n); return; }
        if (n.nodeType !== 3 || !n.textContent.trim()) return;
        var frag = document.createDocumentFragment();
        n.textContent.split(/(\s+)/).forEach(function (chunk) {
          if (!chunk) return;
          if (/^\s+$/.test(chunk)) { frag.appendChild(document.createTextNode(chunk)); return; }
          var w = document.createElement('span');
          w.className = 'awf-w';
          if (mode === 'chars') {
            Array.from(chunk).forEach(function (ch) {
              var c = document.createElement('span');
              c.className = 'awf-p'; c.textContent = ch; c._ch = ch;
              w.appendChild(c); parts.push(c);
            });
          } else if (mode === 'mask') {
            var inner = document.createElement('span');
            inner.className = 'awf-p'; inner.textContent = chunk;
            w.appendChild(inner); parts.push(inner);
          } else {
            w.className += ' awf-p'; w.textContent = chunk; parts.push(w);
          }
          frag.appendChild(w);
        });
        node.replaceChild(frag, n);
      });
    })(root);
    parts.forEach(function (p, i) { p.style.setProperty('--i', i); });
    return parts;
  }
  // номер строки для каждого слова — строки появляются по очереди
  function lines(el) {
    var top = null, line = -1;
    [].forEach.call(el.querySelectorAll('.awf-w'), function (w) {
      var t = w.offsetTop;
      if (top === null || Math.abs(t - top) > 3) { line++; top = t; }
      w.firstChild.style.setProperty('--i', line);
    });
  }
  function prepare(el) {
    split(el, 'mask');
    lines(el);
    var t;
    window.addEventListener('resize', function () { clearTimeout(t); t = setTimeout(function () { lines(el); }, 150); });
  }
  function play(el) {
    el.classList.add('awf-in');
  }
  function stop(el) {
    // мгновенный сброс в начальное состояние, без обратной анимации
    el.classList.add('awf-off');
    el.classList.remove('awf-in');
    void el.offsetWidth;
    el.classList.remove('awf-off');
  }
  function init() {
    var els = [].slice.call(document.querySelectorAll('.' + CLS)).filter(function (el) {
      if (el.getAttribute('data-awf')) return false;
      el.setAttribute('data-awf', '1');
      prepare(el);
      el.classList.add('awf-ready');
      return true;
    });
    if (reduce) { els.forEach(play); return; }
    if (!('IntersectionObserver' in window)) { els.forEach(play); return; }
    var io = new IntersectionObserver(function (entries) {
      entries.forEach(function (e) {
        if (e.isIntersecting) { play(e.target); io.unobserve(e.target); }
      });
    }, { threshold: 0.2 });
    els.forEach(function (el) { io.observe(el); });
  }
  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
  else init();
})();
</script>

Вставляется в HTML-блок на той же странице, где элемент с классом.

Как добавить в Tilda

Эффект работает на опубликованной странице и в режиме предпросмотра — в самом редакторе Tilda скрипты не выполняются.

  1. Назначьте класс элементу. В Zero Block кликните правой кнопкой по нужному элементу — текстовому и выберите пункт добавления CSS-класса (Add CSS class name). Впишите awf-text-mask — без точки. Класс ставится на сам элемент, не на весь артборд.
  2. Добавьте HTML-блок. На этой же странице добавьте блок T123 «HTML-код» (проще всего найти поиском в библиотеке блоков) или элемент HTML внутри Zero Block.
  3. Вставьте код. Скопируйте код целиком и вставьте в этот HTML-блок, сохраните и опубликуйте страницу.
  4. Меняете настройки? Сначала удалите старый код этого эффекта, затем вставьте новый и снова опубликуйте страницу.
  5. Разные настройки — разные классы. Для второго варианта на той же странице задайте в конструкторе другой класс, например awf-text-mask-2, и вставьте его код отдельно.