Умная шапка сайта как на Medium (почти)

· JavaScript · 6 мин чтения
AnyComment - Современный виджет комментариев для WordPress

Когда я разрабатывал вторую версию шаблона для своего блога я хотел дать ему какую-то изюминку. Еще в то время я активно читал Medium. Я заметил, что у них интересным образом сделана шапка. Когда вы скроллите вниз, она прячется, продолжая скроллить вниз она все еще скрыта и как только начинаете двигаться вверх, она снова показывается. Я решил сделать такую же шапку (ну, почти) у себя в блоге.

Мне понравился подход Medium и я примерно понимал почему они выбрали именно такой способ относительно обычного фиксированной шапки сверху.

Вот несколько причин:

Первая — когда пользователь захочет вернуться к меню, оно у него сразу же появится как только он двинется чуть вверх.

Вторая — вы не загораживаете контент сайта — это самое дорогое и важное что у вас есть.

Третья — это придает изюминку сайту и выглядит интересно.

Демо

21516

Немного поразмыслив

Немного посмотреть на их концепцию, я решил ее чуть изменить.

У меня в заголовке был логотип и поиск в одну строчку и потом ними меню с 4-5 пунктами (пункты могут расти, в зависимости от того, что я добавляю).

Шапка Bologer И далее я понял, что я не хочу скрывать всю шапку, а лишь логотип и поиск, то есть меню всегда будет доступно сверху, если оно понадобиться зашедшему.

План

Абстрактно, шапка выглядит следующим образом:

Bologer - план шапки

Кратко: зона «Лого и Поиск» будет скрыта, меню останется.

Далее я обдумал как это сделать и решил, что:

  • шапка будет фиксированной, чтобы она по умолчанию двигалась за пользователем
  • как только она доходит до определенной точки от верха страницы — зона «Лого и Поиск» должна скрываться, «Меню» оставаться
  • если пользователь продолжает скроллить ниже, то «Лого и Поиск»  остается скрытой, «Меню» показывается
  • если в определенный момент пользователь решил подняться вверх, вся шапка должна вернуться в изначальное положение
  • все должно быть анимированным, не дергаться, чтобы не пугать пользователя

Код

HTML & CSS здесь особой роли не играет. Самое важное выполняет jQuery.

Для простоты работы я выбрал jQuery.

Полный скрипт:

$(document).ready(function() {
  var body = $(".container");
  var header = $("header");
  var nav = header.find("nav");
  var max = 400;

  var headerHeight = header.outerHeight();
  var navHeight = nav.outerHeight();

  header.addClass('shown');
  body.css("margin-top", headerHeight + 30);

  var lastActive = 0;
  
  $(window).on("scroll", function() {
    var top = $(document).scrollTop();
    if (top >= max) {
      
      if(lastActive > мне нужно top) {
        header.removeClass('hidden');
        header.addClass("shown");
        header.stop().animate({ marginTop: 0 }, 200);
      } else {
        header.removeClass('hidden');
        header.addClass("shown");
        header.stop().animate({ marginTop: -(headerHeight - navHeight) }, 200);
      }
      
      lastActive = top;
    } else {
      if (header.hasClass('shown')) {
        header.removeClass('shown');
        header.addClass("hidden");
        header.stop().animate({ marginTop: 0 }, 200);
      }
    }
  });
});

Не пугайтесь, сейчас все объясню.

Изначально ожидаем загрузки DOM страницы, чтобы начать с ним работать с $(document).ready.

Далее нужно обозначить часто используемые переменные. Вот их значения:

  • body — это ваш контейнер, в моем случае — это где я отображаю текст страницы или статью (которую вы читаете сейчас). Требуется для того, чтобы сделать отступ от шапки
  • header — это главной элемент шапки — наш главной герой
  • nav — элемент внутри шапки, отвечающий за отображение меню (если оно у вас есть)
  • max — это максимальная высота сверху от страницы после которой будет скрыта шапка до меню. Допустим, вы проскроллили 400 пикселей вниз и какая-то логика после этого должна произойти.
  • headerHeight — это высота элемента header (шапки)
  • navHeight — это высота меню

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

Далее нужно поставить значения по умолчанию:

header.addClass('shown'); 
body.css("margin-top", headerHeight + 30); 

var lastActive = 0;

Для шапки добавим класс shown, чтобы означает показана, для bodyустановим верхний отступ, чтобы был отступ от шапки (размер шапки + 30 пикселей.

Далее немного магии:

$(window).on("scroll", function() {
    var top = $(document).scrollTop();
    if (top >= max) {
      
      if(lastActive > top) {
        header.removeClass('hidden');
        header.addClass("shown");
        header.stop().animate({ marginTop: 0 }, 200);
      } else {
        header.removeClass('hidden');
        header.addClass("shown");
        header.stop().animate({ marginTop: -(headerHeight - navHeight) }, 200);
      }
      
      lastActive = top;
    } else {
      if (header.hasClass('shown')) {
        header.removeClass('shown');
        header.addClass("hidden");
        header.stop().animate({ marginTop: 0 }, 200);
      }
    }
});

$(window).on("scroll") означает, что мы заинтересованы в событии скроллинга. И уже внутри, мы может выполнять нашу логику.

В самом верху, есть переменная top, которая будет записывать текущую высоту сверху страницы каждый раз когда пользователь скролл.

Далее у нас есть условие if, else.

Скрытие/отображение (if)

В if я проверяю не является ли текущая высота больше той, которую мы определили в max. Если является, то нужно спрятать шапку по меню.

Если обратить внимание, то внутри есть еще условие, которые проверяет не прокрутил ли пользователь вверх когда он уже ниже max. Если не ушел, то сработает else:

} else {
    header.removeClass('hidden');
    header.addClass("shown");
    header.stop().animate({ marginTop: -(headerHeight - navHeight) }, 200);
}

Я использовал метод animate(), которые позволяет анимировать действия. в данном случае, я менял CSS свойство margin-top. Я поставил минусовой маргин, который равен:

высота шапки — минус высота меню

Таким образом у нас получается высота по меню и не больше.

Если вы не ушли за max значит сработает это условие:

if(lastActive > top) {
    header.removeClass('hidden');
    header.addClass("shown");
    header.stop().animate({ marginTop: 0 }, 200);

Для проверки двигается пользователь вверх или вниз — используется переменная lastActive, которая записывается предыдущее значение высоты когда пользователь находится ниже max высоты.

Отображение (else)

В случае когда пользователь находится выше max, нужно показать шапку.

Для WordPress

Если вам нужно вставить данные код в WordPress, сделайте это следующим образом:

  • откройте functions.php
  • и укажите код ниже:
function smart_header() {
?>
<script>
{JS КОД}
</script>
<?php
}
add_action('wp_footer', 'smart_header');
  • Замените {JS КОД} на JavaScript код, на полный код, который я указывал выше в этом посте

Вывод

Как видите все не так сложно, главное немного поразмыслить над реализацией, а уже сам процесс дастся легко, если вам это интересно.

Если у вас возникнут какие-либо вопросы — пишите ниже, буду раз помочь.