Каждый кто решил будет круто использовать виджет Off-Canvas Elementor в качестве мобильного меню или полноэкранного меню в десктопной версии (и такое случается). Да использовать вне холста лучше для SEO, в отличие от Popup навигация доступна для индексирования. Наталкивался на проблему якорных ссылок, при переходе на которые холст остается на месте. Раньше я пользовался костылями, которые дергали кнопку закрытия, что иногда приводило к конфликтам, или работало не так я хотел. Так вот совместно с цифровыми помощниками написал вот такой универсальный код, который работает даже если ан странице несколько Off-Canvas.

Проблема
Когда в Elementor используется Off-Canvas (всплывающая боковая панель, часто применяемая для меню), клики по якорным ссылкам (#section) часто ведут себя некорректно:
- страница не прокручивается к нужному блоку;
- окно Off-Canvas остаётся открытым, перекрывая контент;
- плавный скролл не работает, или срабатывает до того, как панель закроется.
Эта проблема особенно заметна на мобильных устройствах, где UX сильно зависит от плавности перехода.
Решение: скрипт для корректной работы якорей
Ниже приведён код, который устраняет эти проблемы и делает работу Off-Canvas более «умной» и удобной:
<style>
.e-off-canvas-hidden { display: none; }
.e-off-canvas-overlay-hidden {
opacity: 0;
visibility: hidden;
transition: opacity .3s ease;
}
.e-off-canvas__overlay {
opacity: 1;
visibility: visible;
transition: opacity .3s ease;
}
</style>
<script>
jQuery(function($){
const CLOSE_DELAY = 1000; // задержка, пока Off Canvas закрывается
const initializedCanvases = new Set();
function initOffCanvas($offCanvas) {
const id = $offCanvas.attr('data-id') || $offCanvas.index();
if (initializedCanvases.has(id)) return;
initializedCanvases.add(id);
const $overlay = $offCanvas.find('.e-off-canvas__overlay');
const $body = $('body');
function hideOffCanvas() {
$overlay.addClass('e-off-canvas-overlay-hidden');
$body.removeClass('e-off-canvas__no-scroll');
}
function showOffCanvas() {
$overlay.removeClass('e-off-canvas-overlay-hidden');
$body.addClass('e-off-canvas__no-scroll');
}
function triggerOffCanvasClose() {
const $btn = $offCanvas.find(
'a[href*="elementor-action%3Aaction%3Doff_canvas%3Aclose"], [data-dismiss="dialog"], .eicon-close, .dialog-widget-close-button'
).first();
if ($btn.length) { $btn.trigger('click'); return true; }
hideOffCanvas(); return false;
}
$offCanvas.on('click', 'a:not([href*="elementor-action%3Aaction%3Doff_canvas%3Aclose"]):not([data-dismiss="dialog"]):not(.eicon-close):not(.dialog-widget-close-button)', function(e){
const href = $(this).attr('href') || '';
const [path, hash] = href.split('#');
const samePage = !path || path === window.location.pathname;
if (hash && samePage) {
e.preventDefault();
const anchor = document.getElementById(hash);
if (triggerOffCanvasClose()) {
setTimeout(() => {
if (anchor) anchor.scrollIntoView({ behavior: 'smooth' });
}, CLOSE_DELAY);
} else if (anchor) {
anchor.scrollIntoView({ behavior: 'smooth' });
}
} else {
triggerOffCanvasClose();
}
});
$(document).on('click', `[data-target="#${$offCanvas.attr('id')}"], .off-canvas-toggle-button`, showOffCanvas);
console.info(`[OffCanvas] initialized →`, id);
}
function initAll() {
$('[class^="e-off-canvas"]').each(function(){
initOffCanvas($(this));
});
}
initAll();
const observer = new MutationObserver((mutations) => {
for (const m of mutations) {
for (const node of m.addedNodes) {
if (node.nodeType === 1 && node.matches('[class^="e-off-canvas"]')) {
initOffCanvas($(node));
} else if (node.nodeType === 1) {
$(node).find('[class^="e-off-canvas"]').each(function() {
initOffCanvas($(this));
});
}
}
}
});
observer.observe(document.body, { childList: true, subtree: true });
});
</script>
Как использовать
Вставьте код в виджет «HTML» на странице, где используется Off-Canvas (первым блоком в контейнере, в подвал сайта или с помощью плагина сниппетов кода).
→ В Elementor: HTML → Вставить код → Обновить страницу.
Как это работает
jQuery находит все Off-Canvas элементы Elementor (.e-off-canvas...).
Для каждого:
Отслеживаются клики по ссылкам.
- Если ссылка ведёт к якорю на текущей странице — окно Off-Canvas плавно закрывается.
- После закрытия (через
setTimeout) страница прокручивается к нужному элементу (scrollIntoViewсbehavior: 'smooth').
Для новых Off-Canvas, созданных динамически (например, через AJAX или Elementor Popups), работает MutationObserver — автоматическая инициализация без перезагрузки страницы.
Улучшение UX
Можно добавить лёгкую анимацию иконки “крестика” при закрытии меню:
.eicon-close {
transition: transform 0.3s ease;
}
.eicon-close:hover {
transform: rotate(90deg);
}
Если используется SVG-иконка, можно применить тот же эффект к контейнеру SVG:
.off-canvas-close svg {
transition: transform 0.3s ease;
}
.off-canvas-close svg:hover {
transform: rotate(90deg);
}
Это мой стандартный метод, я заменил все старые костыли и использую его на всех сайтах. Проблеме уже пару лет, вряд ли Elementor починит это в ближайшее время, так что актуально.