На некоторых сайтах, особенно контентных, есть базовый элемент страницы - сайдбар . Это колонка справа или слева от основного контента страницы, где может размещаться полезная информация - рекомендуемые статьи, опросы, ссылки на соцсети и подобное.

Владельцы сайтов, которые зарабатывают на размещении рекламы, в сайдбаре зачастую размещают баннеры контекстных сетей или партнерских программ. Эффективный способ повысить кликабельность баннера — зафиксировать его на экране при прокрутке. Пользователь будет видеть его постоянно, что может пробить «баннерную слепоту». Такие баннеры называют «липкий», «прилипший» или «плавающий».

Пример сайдбара на сайте

Я сделал такой баннер на своем сайте и хочу поделиться решением. Живой пример можно наблюдать на десктопах в сайдбаре справа. Реализация работает на чистом JavaScript и не требует подключения других библиотек.

Единственный минус - нужно немного разбираться в HTML, CSS и JS, так как это не готовый плагин, а просто блок кода. Но начинающих призываю не бояться и попробовать, так как я объясню все подробно, и для вас это будет отличный повод узнать что-то новое. Если что, для разных CMS есть готовые плагины — можно погуглить.

Основной принцип такой: размещаем в сайдбаре баннер в контейнере-обертке и добавляем скрипт, который срабатывает при скролле страницы. Если экран опускается ниже верхней точки обертки баннера - у обертки добавляется внутренний верхний отступ, чтобы баннер следовал за областью просмотра пользователя.

Схема работы липкого плавающего баннера в сайдбаре

Можно корректировать отступ баннера от начала экрана в переменной sidebar_banner_window_top. Давайте разберем сам код.

Структура страницы:

<html>
    <head>
        <title>Заголовок</title>
    </head>
    <body>
        <div class="main">
            <div class="content">
                <h1>Заголовок 1</h1>
                <p>Контент страницы</p>
            </div>
            <div class="sidebar">
                <div class="banner-sidebar">
                    <a href="#">
                        <img src="" width="100%"/>
                    </a>
                </div>
            </div>
        </div>
    </body>
</html>

Стили:

.main {
    width: 100%;
    display: flex;
}

.content {
    width: 66.6666%;
    height: 1200px; /* Чтобы появилась прокрутка */
    border: 1px #ddd solid;
    margin-right: 1%;
    padding: 1em 15px;
}

.sidebar {
    width: 32.3333%;
}

.banner-sidebar img {
    width: 100%;
    background: #000;
    height: 500px;
}

Скрипт:

document.addEventListener("scroll", function() {
    let sidebar_banner_window_top = 10; // Отступ баннера от верха экрана в px
    let sidebar = document.querySelector('.sidebar');
    let banner = document.querySelector('.banner-sidebar');
    let content = document.querySelector('.content');
    let banner_a = document.querySelector('.banner-sidebar a');

    // Определяем верхнюю точку обертки баннера
    let sidebar_banner_static_start = banner.offsetTop;

    // Определяем высоту блока сайдбара (должна быть 100%, как основной контент)
    let sidebar_height = sidebar.offsetHeight;

    // Определяем верхнюю точку всего сайдбара
    let sidebar_top = sidebar.offsetTop;

    // Определяем текущее положение верхней точки экрана
    let window_top_point = window.pageYOffset || document.documentElement.scrollTop;

    // Определяем высоту баннера
    let sidebar_banner_height = banner_a.offsetHeight;

    // Если экран опускается ниже верхней точки обертки баннера - опускаем баннер,
    // увеличивая padding-top, иначе поднимаем обратно
    if (window_top_point > sidebar_banner_static_start) {
        let content_bottom = content.offsetHeight + content.offsetTop;
        let banner_bottom = (window_top_point - sidebar_banner_static_start) + sidebar_banner_static_start + sidebar_banner_height + sidebar_banner_window_top;

        // Чтобы не было бесконечной прокрутки и увеличения высоты сайдбара за счет padding, то
        // если нижняя точка баннера по расчетам больше нижней точки основного контента -
        // ограничиваем ее, иначе меняем padding по стандартному сценарию
        if (banner_bottom > content_bottom) {
            let sidebar_banner_max_padding = sidebar_height - sidebar_banner_height - (sidebar_banner_static_start - sidebar_top) - sidebar_banner_window_top;
            banner.style.paddingTop = (sidebar_banner_max_padding + sidebar_banner_window_top) + 'px';
        } else {
            banner.style.paddingTop = (window_top_point - sidebar_banner_static_start + sidebar_banner_window_top) + 'px';
        }
    } else {
        banner.style.paddingTop = '0px';
    }
});

Теоретически, можно попробовать сделать подобное и с помощью position: fixed, однако в таком случае картинка не может корректно вписаться в ширину сайдбара, и ширину придется определять также скриптом, что делает вариант менее адаптивным. Вариант с изменением отступов меня вполне устроил и видимых минусов я в нем не нашел, а какие нашел — исправил, так что буду рад, если мое решение пригодится и Вам.

Спасибо за внимание!