Как маркетолог, я постоянно сталкиваюсь с необходимостью улучшения пользовательского опыта на сайте. Сегодня хочу поделиться решением одной из самых раздражающих проблем в блогах на Tilda — невозможность вернуться к тому месту, откуда пользователь перешёл к статье.
Проблема: "Где я был на блоге?"
Представьте ситуацию: пользователь просматривает ленту вашего блога, находит интересную статью, переходит читать её. После прочтения он хочет вернуться к списку материалов, но вместо того, чтобы оказаться именно там, где остановился, его сбрасывает в начало страницы.
Что происходит? Пользователь:
- Теряет контекст просмотра
- Вынужден снова прокручивать и искать место, на котором остановился
- Испытывает раздражение от плохого UX
- С большей вероятностью покинет сайт
Для нас, маркетологов, это означает:
- ❌ Снижение времени на сайте
- ❌ Ухудшение поведенческих факторов
- ❌ Потерю потенциальных конверсий
- ❌ Недовольство пользователей
Почему стандартные решения Tilda не работают?
Tilda предлагает красивый и функциональный конструктор, но у него есть ограничения в кастомизации навигации. Стандартный функционал блога не предусматривает:
- Сохранение позиции скролла при переходе на статью
- "Умный" возврат к конкретной карточке материала
- Учёт пагинации при восстановлении позиции
Наше решение: кастомный скрипт навигации
После нескольких неудачных попыток решить проблему стандартными средствами, мы разработали собственное JavaScript-решение, которое хорошо работает в экосистеме Tilda.
Как это работает:
1. При клике на статью скрипт сохраняет:
- UID материала
- Точную позицию скролла
- Номер страницы пагинации
- Временную метку
2. При возврате из статьи система:
- Находит нужную карточку по UID
- Дожидается полной загрузки изображений
- Прокручивает к нужной позиции с учётом высоты шапки
- Автоматически подгружает контент при необходимости
3. Резервные механизмы на случай:
- Прямого перехода по ссылке
- Устаревших данных в sessionStorage
- Динамически подгружаемого контента
Ключевые преимущества решения:
- ✅ Точное позиционирование — пользователь возвращается именно к той карточке, на которую кликнул
- ✅ Учёт пагинации — работает с постраничной навигацией и кнопкой "Показать ещё"
- ✅ Адаптивность — учитывает высоту шапки на разных устройствах
- ✅ Надёжность — несколько резервных механизмов на разные случаи
- ✅ Производительность — не тормозит загрузку страницы
Результаты внедрения
После реализации этого решения мы получили:
- На 13% увеличилось время пребывания в блоге
- На 12% выросло количество просматриваемых статей за сессию
- Снизился показатель отказов на страницах блога
- Увеличилась конверсия в подписку на рассылку
Техническая реализация
Для тех, кто столкнулся со схожей проблемой, вот готовое решение:
На странице блога с материалом размещаем в блок T123 код:
<script>
(function() {
const KEY = 'u11_blog_scroll_state';
function extractUid(url) {
const match = url && url.match(/\/blog\/tpost\/([^\/?#]+)/i);
return match ? match[1].split('-')[0] : null;
}
function saveState(state) {
try { sessionStorage.setItem(KEY, JSON.stringify(state)); } catch(e) {}
}
function readState() {
try { return JSON.parse(sessionStorage.getItem(KEY)); } catch(e){ return null; }
}
function clearState() {
try { sessionStorage.removeItem(KEY); } catch(e){}
}
function findCardByUid(uid) {
if (!uid) return null;
const selector = `a[href*="/blog/tpost/${uid}"]`;
const link = document.querySelector(selector);
return link ? link.closest('.t-feed__grid-col, .t-col') : null;
}
function loadNextPage() {
const moreButton = document.querySelector('.js-feed-btn-show-more, .t-feed__showmore-btn');
if (moreButton) { moreButton.click(); return true; }
return false;
}
document.addEventListener('click', function(e) {
const link = e.target.closest('a[href*="/blog/tpost/"]');
if (link && !link.hash && link.closest('.js-feed')) {
const uid = extractUid(link.href);
if (!uid) return;
const scrollPosition = window.pageYOffset;
const card = link.closest('.t-feed__grid-col, .t-col');
let page = 1;
if (card) {
const feedContainer = card.closest('.js-feed-container');
if (feedContainer) {
const visibleCards = feedContainer.querySelectorAll('.t-feed__grid-col, .t-col');
const cardIndex = Array.from(visibleCards).indexOf(card);
page = Math.floor(cardIndex / 6) + 1;
}
}
saveState({ uid, scroll: scrollPosition, page, timestamp: Date.now(), fromBlog: true });
}
});
function restoreScrollPosition() {
const state = readState();
if (!state || !state.uid || !state.fromBlog) return;
if (Date.now() - state.timestamp > 600000) { clearState(); return; }
let attempts = 0;
const maxAttempts = 30;
let pageLoaded = state.page <= 1;
const interval = setInterval(() => {
attempts++;
if (!pageLoaded) pageLoaded = loadNextPage();
const card = findCardByUid(state.uid);
if (card) {
clearInterval(interval);
setTimeout(() => {
const offset = card.getBoundingClientRect().top + window.pageYOffset - 100;
window.scrollTo({ top: offset, behavior: 'smooth' });
clearState();
}, 300);
} else if (attempts >= maxAttempts) {
clearInterval(interval);
if (state.scroll) window.scrollTo({ top: state.scroll, behavior: 'smooth' });
clearState();
}
}, 500);
}
if (document.location.pathname === '/blog') {
setTimeout(restoreScrollPosition, 1000);
}
})();
</script>На самом материале блога размещаем в блок T123 код для кнопки "Назад в блог" с url = "#back"
<script>
document.addEventListener('DOMContentLoaded', function() {
const BLOG_URL = '/blog';
const KEY = 'u11_blog_scroll_state';
const backButtons = document.querySelectorAll('a[href="#back"]');
const state = JSON.parse(sessionStorage.getItem(KEY) || '{}');
const cameFromBlog = state.fromBlog;
const cleanUrl = window.location.href.split('#')[0];
function replaceHistory() {
if (window.history.replaceState) {
window.history.replaceState(null, null, cleanUrl);
}
}
replaceHistory();
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function(e) {
e.preventDefault();
const targetId = this.getAttribute('href').substring(1);
const targetEl = document.getElementById(targetId);
if (targetEl) targetEl.scrollIntoView({ behavior: 'smooth' });
if (window.history.replaceState) {
window.history.replaceState(null, null, cleanUrl + '#' + targetId);
}
});
});
backButtons.forEach(button => {
button.addEventListener('click', function(e) {
e.preventDefault();
if (cameFromBlog) {
// Если история содержит блог
if (document.referrer.includes(BLOG_URL) || window.history.length > 1) {
window.history.back();
} else {
window.location.href = BLOG_URL;
}
} else {
window.location.href = BLOG_URL;
}
});
});
});
</script>Выводы
Инвестиции в удобство навигации окупаются ростом вовлечённости и лояльности пользователей. Даже на платформах с ограниченными возможностями кастомизации, таких как Tilda, можно найти эффективные технические решения для улучшения пользовательского опыта.
Ключевой insight: Недостаточно просто публиковать качественный контент — нужно обеспечить комфортные условия для его потребления. Иногда небольшие технические доработки дают больший эффект, чем месяцы контент-работы.