+7 (4012) 20-10-86

Как сделать кнопку «Развернуть» (unfold) для секций в Elementor без плагинов

В практике веб-разработки мы часто сталкиваемся с дилеммой: SEO-специалистам нужны объемные тексты на посадочных страницах, а UX-дизайнеры хотят сохранить интерфейс чистым и не перегружать пользователя «простынями» текста.

Идеальное решение — блок Unfold (развернуть/свернуть).

Конечно, для WordPress существуют десятки плагинов, решающих эту задачу. Но зачем устанавливать тяжелый плагин ради одной функции, нагружая сайт лишними скриптами и стилями? В этой статье мы поделимся нашим фирменным решением: легковесным, SEO-friendly кодом для создания эффекта Unfold, который идеально интегрируется с Elementor.

Почему наше решение лучше стандартных плагинов?

Мы написали этот скрипт с учетом современных требований к производительности и доступности:

  1. Никаких зависимостей. Основная логика написана на чистом JavaScript.
  2. Полная совместимость с Elementor. Скрипт учитывает динамическую подгрузку контента (например, в попапах или табах) благодаря хукам elementor/frontend/init.
  3. Плавная анимация. Мы используем вычисление scrollHeight для создания красивой CSS-анимации раскрытия, что работает гораздо плавнее, чем стандартный jQuery slideDown.
  4. Умный градиент. Скрипт автоматически определяет цвет фона секции и создает бесшовный градиент для эффекта «затухания» текста.
  5. Доступность (A11y). Кнопка содержит атрибуты aria-expanded и aria-controls, что критически важно для скринридеров и SEO.

Шаг 1. Подключаем скрипты и стили в functions.php

Для начала нам нужно правильно подключить наши файлы в дочерней теме. Мы используем стандартный хук wp_enqueue_scripts.

				
					function enqueue_unfold_scripts() {
    // Подключаем стили
    wp_enqueue_style(
        'unfold-style',
        get_stylesheet_directory_uri() . '/css/unfold.css',
        array(),
        '1.0.0'
    );

    // Подключаем скрипт в футере
    wp_enqueue_script(
        'unfold-script',
        get_stylesheet_directory_uri() . '/js/unfold.js',
        array('jquery'), // Зависимость от jQuery (если используется в теме)
        '1.0.0',
        true // Загрузка перед закрывающим тегом </body>
    );
}
add_action('wp_enqueue_scripts', 'enqueue_unfold_scripts');
				
			

Шаг 2. Пишем логику на JavaScript (/js/unfold.js)

Это сердце нашего функционала. Мы обернули код в IIFE (Immediately Invoked Function Expression), чтобы не засорять глобальную область видимости.

В начале файла вынесен объект CONFIG — вы можете легко изменить высоту свернутого блока, тексты кнопок и другие параметры без необходимости копаться в самом коде.

				
					// js/unfold.js

(function () {

  "use strict";

  // ----------------------------------------
  // НАСТРОЙКИ - Изменяйте эти значения свободно
  // ----------------------------------------
  const CONFIG = {
    targetClass:    "unfold-section",   // CSS-класс на вашей секции Elementor
    expandedClass:  "is-expanded",      // Класс, добавляемый при раскрытии
    collapsedHeight: "300px",           // Высота в свёрнутом состоянии
    btnTextMore:    "Развернуть ▼",     // Текст кнопки в свёрнутом состоянии
    btnTextLess:    "Свернуть ▲",       // Текст кнопки в развёрнутом состоянии
    showOverlay:    true,               // Показывать градиентное затухание
    scrollToTop:    true,               // Прокручивать вверх при сворачивании
  };
  // ----------------------------------------


  /**
   * Инициализация всех сворачиваемых секций на странице
   */
  function initUnfold() {

    // Находим все секции с целевым классом
    const sections = document.querySelectorAll("." + CONFIG.targetClass);

    if (sections.length === 0) {
      console.warn("Unfold: Секции с классом ." + CONFIG.targetClass + " не найдены");
      return;
    }

    sections.forEach(function (section, index) {
        // ✅ ЗАЩИТА: Пропускаем, если секция уже инициализирована
        if (section.dataset.unfoldInit === "true") {
            return; // Останавливаемся, уже выполнено
        }

    section.dataset.unfoldInit = "true";

      // Устанавливаем высоту свёрнутого состояния из настроек
      const customHeight = section.dataset.collapseHeight || CONFIG.collapsedHeight;
      section.style.maxHeight = customHeight;
      section.style.overflow  = "hidden";
      section.style.position  = "relative";
      section.style.transition = "max-height 0.6s ease-in-out";

      // Добавляем градиентное затухание
      if (CONFIG.showOverlay) {
        addOverlay(section);
      }

      // Создаём кнопку «Развернуть»
      const btnWrapper = createButton(section, index);

      // Вставляем кнопку ПОСЛЕ секции
      if (btnWrapper !== null) {
            section.parentNode.insertBefore(btnWrapper, section.nextSibling);
        }

    });

  }


  /**
   * Добавляем градиентный оверлей внутрь секции
   */
  function addOverlay(section) {

    const overlay = document.createElement("div");
    overlay.classList.add("unfold-overlay");

    // По возможности подбираем цвет фона секции
    const bgColor = getComputedStyle(section).backgroundColor;
    if (bgColor && bgColor !== "rgba(0, 0, 0, 0)") {
      overlay.style.background =
        "linear-gradient(to bottom, rgba(255,255,255,0), " + bgColor + ")";
    }

    section.appendChild(overlay);
  }


  /**
   * Создаём кнопку «Развернуть» / «Свернуть»
   */
function createButton(section, index) {

    // ✅ ПРОВЕРКА: Если кнопка рядом с секцией уже существует — пропускаем
    const nextEl = section.nextElementSibling;
    if (nextEl && nextEl.classList.contains("unfold-btn-wrapper")) {
        return null; // Кнопка уже есть, повторно не создаём
    }

    const wrapper = document.createElement("div");
    wrapper.classList.add("unfold-btn-wrapper");

    const btn = document.createElement("button");
    btn.classList.add("unfold-btn");
    btn.setAttribute("aria-expanded", "false");
    btn.setAttribute("aria-controls", "unfold-section-" + index);
    btn.textContent = CONFIG.btnTextMore;

    section.setAttribute("id", "unfold-section-" + index);

    btn.addEventListener("click", function () {
        toggleSection(section, btn);
    });

    wrapper.appendChild(btn);
    return wrapper;
}


  /**
   * Переключаем состояние: развернуть / свернуть
   */
  function toggleSection(section, btn) {

    const isExpanded = section.classList.contains(CONFIG.expandedClass);

    if (!isExpanded) {
      // --- РАЗВОРАЧИВАЕМ ---
      expandSection(section, btn);

    } else {
      // --- СВОРАЧИВАЕМ ---
      collapseSection(section, btn);
    }
  }


  /**
   * Разворачиваем секцию
   */
  function expandSection(section, btn) {

    // Получаем реальную полную высоту
    const fullHeight = section.scrollHeight + "px";

    section.style.maxHeight  = fullHeight;
    section.style.transition = "max-height 0.8s ease-in-out";
    section.classList.add(CONFIG.expandedClass);

    btn.textContent = CONFIG.btnTextLess;
    btn.setAttribute("aria-expanded", "true");

    // После завершения анимации снимаем ограничение для динамического контента
    section.addEventListener("transitionend", function handler() {
      if (section.classList.contains(CONFIG.expandedClass)) {
        section.style.maxHeight = "none";
      }
      section.removeEventListener("transitionend", handler);
    });
  }


  /**
   * Сворачиваем секцию
   */
  function collapseSection(section, btn) {

    // Перед анимацией необходимо задать явную высоту
    section.style.maxHeight  = section.scrollHeight + "px";

    // Принудительный пересчёт макета браузером
    section.offsetHeight;

    // Запускаем анимацию до свёрнутой высоты
    section.style.transition = "max-height 0.6s ease-in-out";
    section.style.maxHeight  = CONFIG.collapsedHeight;
    section.classList.remove(CONFIG.expandedClass);

    btn.textContent = CONFIG.btnTextMore;
    btn.setAttribute("aria-expanded", "false");

    // Прокручиваем страницу к началу секции
    if (CONFIG.scrollToTop) {
      setTimeout(function () {
        section.scrollIntoView({ behavior: "smooth", block: "start" });
      }, 300);
    }
  }


  // ----------------------------------------
  // Запуск после загрузки DOM и готовности Elementor
  // ----------------------------------------

  // Стандартное событие готовности DOM
  document.addEventListener("DOMContentLoaded", function () {
    initUnfold();
  });

  // Событие готовности Elementor Frontend (для динамических виджетов)
  window.addEventListener("elementor/frontend/init", function () {
    if (window.elementorFrontend) {
      elementorFrontend.hooks.addAction(
        "frontend/element_ready/global",
        function () {
          initUnfold(); // Повторная инициализация при добавлении новых виджетов
        }
      );
    }
  });

})();
				
			

Разбор интересных моментов в коде:

  • Трюк сscrollHeight. Анимировать свойство height: auto в CSS невозможно. Поэтому при раскрытии мы вычисляем реальную высоту контента (section.scrollHeight) и задаем её в пикселях. А после завершения анимации (transitionend) меняем на none, чтобы блок мог адаптироваться при ресайзе окна.
  • Принудительный reflow (section.offsetHeight). При сворачивании нам нужно вернуть точную высоту в пикселях перед тем, как запустить анимацию сжатия. Вызов offsetHeight заставляет браузер перерисовать кадр, гарантируя плавность.
  • Elementor Hooks. Строки с elementorFrontend.hooks.addAction гарантируют, что если вы используете виджеты с AJAX-подгрузкой, скрипт заново найдет новые секции и применит к ним логику.

Шаг 3. Добавляем базовый CSS (unfold.css)

Чтобы градиент и кнопка выглядели аккуратно, добавьте этот минимальный CSS. Вы можете стилизовать кнопку под дизайн вашего сайта.

				
					/* css/unfold.css */

/* ---- Свёрнутое состояние ---- */
.unfold-section {
  max-height: 300px;        /* Желаемая высота в свёрнутом виде */
  overflow: hidden;
  position: relative;
  transition: max-height 0.6s ease-in-out;
}

/* ---- Развёрнутое состояние ---- */
.unfold-section.is-expanded {
  max-height: 9999px;       /* Достаточно большое значение для любого контента */
  transition: max-height 0.8s ease-in-out;
}

/* ---- Градиентное затухание (оверлей) ---- */
.unfold-overlay {
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 100px;
  background: linear-gradient(
    to bottom,
    rgba(255, 255, 255, 0),
    rgba(255, 255, 255, 1)
  );
  transition: opacity 0.4s ease;
  pointer-events: none;     /* Оверлей не блокирует клики */
}

/* ---- Скрыть оверлей в развёрнутом состоянии ---- */
.unfold-section.is-expanded .unfold-overlay {
  opacity: 0;
}

/* ---- Кнопка «Показать больше» ---- */
.unfold-btn {
  display: block;
  margin: 15px auto;
  padding: 10px 25px;
  background-color: #6EC1E4;  /* Замените на свой цвет */
  color: #ffffff;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  font-size: 15px;
  font-weight: 600;
  transition: background-color 0.3s ease;
}

.unfold-btn:hover {
  background-color: #4a9fc4;
}

/* ---- Обёртка кнопки ---- */
.unfold-btn-wrapper {
  text-align: center;
  margin-top: 10px;
}
				
			

Шаг 4. Как использовать это в Elementor?

Использовать созданный функционал проще простого:

  1. Откройте нужную страницу в редакторе Elementor.
  2. Выделите секцию (или внутреннюю секцию / контейнер), которую нужно скрыть.
  3. Перейдите во вкладку «Расширенные».
  4. В поле «CSS классы» впишите: unfold-section.
  5. Сохраните страницу.

Готово! Скрипт сам обрежет секцию до 300px (настраивается в JS), добавит градиент и выведет кнопку «Развернуть».

Если для конкретной секции вам нужна другая высота (например, 150px), вы можете добавить атрибут data-collapse-height="150px" к секции через вкладку «Атрибуты» в Elementor (доступно в Elementor Pro). Наш скрипт автоматически считает это значение!

Итоги

С помощью небольшого фрагмента кода мы создали мощный, SEO-оптимизированный и доступный инструмент для управления контентом. Отказ от тяжелых плагинов в пользу таких кастомных решений — это именно то, что отличает профессиональную разработку от любительской сборки сайтов.

Нужна помощь с оптимизацией вашего WordPress-сайта или разработка сложного функционала? Обращайтесь в наше агентство! Мы создаем быстрые и надежные веб-проекты, которые любят и пользователи, и поисковые системы.

Заказать звонок

Мы перезвоним вам в рабочее время в течение часа

Наш сайт использует файлы cookies, которые делают его более удобным для каждого пользователя. Оставаясь на нашем сайте, вы соглашаетесь с использованием файлов cookies.