Как закрепить шапку сайта при скролле страницы

Привет, друзья. Сегодня поговорим о том, как закрепить шапку сайта при прокрутке страницы. Наверняка вы все видели такой эффект, когда шапка сначала выглядит статичной, но когда вы начинаете изучать сайт и скролить, то она фиксируется в верхней части экрана и не покидает поле зрения.

При этом она может немного видоизменяться, меняя размер, цвет и содержимое. Давайте реализуем этот эффект, за который меня уже много лет «костерят» в комментариях из-за того, что тема раскрыта неполностью и исправим это недоразумение.

В свое время было недостаточно знаний, чтобы подробно проработать все нюансы, но теперь сделаю, практически, все популярные эффекты, которые могут понадобится при реализации этого блока.

Давайте начнем с того, что напишем какую-то стандартную разметку шапки, подключим jQuery, чтобы легче было манипулировать javascript и добавим скрипт, в котором и будем управлять состоянием и положением шапки.

Вот структура моего проекта.

HTML разметка шапки

Для примера я придумал такую структуру.

<header class="header">
	<div class="header__inner">
		<div class="header__logo-wrapper">
			<img class="header__logo" width="60" src="./img/vsedovo.svg" alt="Отдых в Седово">
			<div class="header__logo-text">
				<p class="header__logo-title">vsedovo.ru</p>
				<p class="header__logo-description">Отдых в седово</p>
			</div>
		</div>
		<div class="header__contents">
			<div class="header__contacts">
				<div class="header__tel">
					<p><a href="tel:+380951267333">+38(095) 126-73-33</a></p>
					<span>Мобильный</span>
				</div>
				<div class="header__tel">
					<p><a href="tel:+380951267232">+38(095) 126-72-32</a></p>
					<span>Многоканальный</span>
				</div>
			</div>
			<button class="header__callback-button">Обратный звонок</button>
			<button class="header__nav-button"><img width="20" src="./img/menu.svg" alt="Кнопка меню"></button>
		</div>
	</div>
</header>

Слева логотип, название сайта и его описание, а справа контактные телефоны, кнопка обратного звонка и кнопка меню. Типичная разметка для многих сайтов.

Дабавим немного стилей и получим такой внешний вид.

<link rel="stylesheet" href="./css/style.css">

Пока, тут нет никаких особенностей. Это обычная шапка без дополнительных эффектов.

Исходник для изучения разметки, стилей и кода, как обычно, в конце статьи.

Теперь давайте подключим перед закрывающим тегом "body" jQuery и скрипт, в котором и будем писать js-код для управления состоянием и положением шапки.

		<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
		<script src="./js/scripts.js"></script>

Итак, давайте начнем с простейшего, добьемся того, чтобы шапка принимала статическое положение и перекрывала контент, который должен находится под ней.

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

.header {
  width: 100%;
  background: #fff;
  padding: 15px 0;
  z-index: 100;
  -webkit-box-shadow: 0 5px 25px rgba(0, 0, 0, 0.15);
          box-shadow: 0 5px 25px rgba(0, 0, 0, 0.15);
}

.header__inner {
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -ms-flex-wrap: wrap;
      flex-wrap: wrap;
  -webkit-box-pack: justify;
      -ms-flex-pack: justify;
          justify-content: space-between;
  padding: 0 15px;
}

Так выглядят стили для обертки шапки и блок с ее содержимым. За счет такой структуры мы легко сделаем шапку фиксированной, а ее содержимое продолжит оставаться в центре на любом устройстве.

Как я уже говорил, для того чтобы "header" стал фиксированным при прокрутке, ему нужно поменять позиционирование на "fixed". Для этого, при помощи метода "scrollTop()" мы проверим значение прокрутки в окне браузера и в нужный момент добавим шапке класс, в котором и изменим позиционирование.

Звучит страшнее чем кажется. На самом деле все достаточно просто. Давайте в таблицу стилей добавим класс, при помощи которого шапка будет получать position: fixed.

.header_fixed {
  position: fixed;
  left: 0;
  top: 0;
}

Обратите внимание, что z-index для того, чтобы при позиционировании шапка была над остальными элементами, я задал непосредственно классу header немного ранее.

Теперь давайте перейдем к написанию скрипта. Открывайте файл scripts.js и добавьте следующий код.

$(function() {
 let header = $('.header');
 
 $(window).scroll(function() {
   if($(this).scrollTop() > 1) {
    header.addClass('header_fixed');
   } else {
    header.removeClass('header_fixed');
   }
 });
});

Здесь мы создаем переменную header и присваиваем ей наш элемент, в котором расположена шапка, чтобы было легче и удобнее им манипулировать. Затем пишем функцию, которая следит за прокруткой, и если мы прокрутили больше чем на 1 пиксели от начала окна браузера, то элементу с классом header добавляем недавно созданный класс "header_fixed", который и фиксирует шапку в верхней области экрана.

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

Давайте исправим это. Происходи такое резкое смещение из-за того, что шапка занимала 90 пикселей и, соответственно, смещала контент вниз на 90 писклей, а когда мы прокрутили, мы вырвали из общего потока этот элемент и все сдвигается на его высоту. Чтобы этого избежать, предлагаю body, во время того, как шапка становиться фиксированной, дать отступ в 90 пикселей, которые мы теряем. Только я не буду топорно зашивать эту высоту в скрипт, а автоматический вычислю ее высоту и буду использовать это значение в вычислениях.

Опять же звучит страшно и заумно, но посмотрите, как все просто.

$(function() {
 let header = $('.header');
 let hederHeight = header.height(); // вычисляем высоту шапки
 
 $(window).scroll(function() {
   if($(this).scrollTop() > 1) {
    header.addClass('header_fixed');
    $('body').css({
       'paddingTop': hederHeight+'px' // делаем отступ у body, равный высоте шапки
    });
   } else {
    header.removeClass('header_fixed');
    $('body').css({
     'paddingTop': 0 // удаляю отступ у body, равный высоте шапки
    })
   }
 });
});

В 3 строке я получаю число с высотой шапки. На 8 строке, добавлю отступ тегу body, равный высоте шапки, чтобы скомпенсировать ее, в тот момент, когда мы вырываем из общего потока шапку и минеям ей позиционирование.

Когда прокручиваем страницу обратно, и скрипт удаляет класс header_fixed, я также удалю и, теперь, лишний отступ у тега body.

Надеюсь, понятно объяснил и теперь у вас нет никакого рывка, при скролле, а шапка плавно фиксируется и позиционируется в верхней области экрана.

Как закрепить шапку при прокрутке

Изменение высоты шапки и цвета

Теперь давайте разбираться, как при прокрутке изменить высоту шапки. Это достаточно популярный эффект, о котором вы меня часто спрашивали.

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

Но давайте на этот раз я не буду задавать отдельный класс, а покажу как изменить стили прямо в js. Итак, задача при прокрутке на 300 пикселей при помощи jQuery плавно изменить высоту шапки и ее цвет.

if($(this).scrollTop() > 300) {
    header.css({
      'padding': '5px 0',
      'background': '#f6ffdb',
      'transition': '.3s'
    });
} else {
    header.css({
      'padding': '15px 0',
      'background': '#ffffff',
      'transition': '.3s'
    });
}

Как видите, благодаря методу ".css" можно манипулировать стилями прямо из jQuery. Отступ был по 15 пикселей сверху и снизу, а я заменил его на 5, за счет чего шапка стала меньше на 20 пикселей. Цвет сделал бледно желтым, а при помощи свойства transition сделал эффект перехода из одного состояния в другое более плавным.

Как удалить/скрыть элемент из шапки при прокрутке страницы

Этот вопрос мне также периодически задавали в соцсетях, поэтому решил вынести его в отдельный пункт. Наверняка вы уже догадались, если дочитали статью до этого момента. Ничего нового, увы, тут не будет. Все также, как выше. Получим id или class элемента и добавим ему свойства для скрытия. Например "display: none" в простейшем случае.

Для примера давайте скроем один из номеров телефонов. Это будет сложнее, так как у обоих номеров одинаковый класс. Напомню, блок с контактами у меня выглядит так:

<div class="header__contacts">
	<div class="header__tel">
		<p><a href="tel:+380951267333">+38(095) 126-73-33</a></p>
		<span>Мобильный</span>
	</div>
	<div class="header__tel">
		<p><a href="tel:+380951267232">+38(095) 126-72-32</a></p>
		<span>Многоканальный</span>
	</div>
</div>

Теперь давайте в js напишем код, отвечающий за скрытие одного из номеров. Пусть это событие случается, когда мы прокрутили окно на 500 пикселей, но давайте, чтобы не повторятся, будем не просто стили менять или классом манипулировать, а воспользуемся методами fadeIn|fadeOut для плавного скрытия и появления элемента.

let mobileTel = $('.header__tel').first();  // сохранем в переменную первый элемент с классом header__tel

if($(this).scrollTop() > 500) {
  mobileTel.fadeOut();
} else {
  mobileTel.fadeIn();
}

Вот, что мы получили:

Вот такой, достаточно простой эфеект получился. Надеюсь, все основные нюансы по закреплению шапки учел. Если будут еще какие-то вопросы, задавайте в комментариях.

 

Фиксированная шапка

Размер: 0,08 мб

Похожие публикации

18 комментариев

  1. gow

    А есть еще что то похожее на эту тему?

  2. Виктор

    При этом, шапка должна еще и видоизменяться уменьшаться, чтобы не закрывать всю страницу для пользователя.

  3. Дмитрий

    Добрый день!
    Подскажите, а как сделать, что бы менялся размер при прокрутке страницы в зафиксированном хедере?

  4. Vivando

    Здравствуйте! А не подскажите, как сделать чтобы меню меняло цвет при фиксации сверху сайта. Чё то ни как не могу разобраться. Буду очень признателен Вам!

  5. Андрей

    а если в шапке два блока, стоящих последовательно (float:left), как тогда зафиксировать?
    (Для элемента с position: absolute или position: fixed нельзя одновременно устанавливать свойство float)

    1. dimadv7

      Андрей, добавить 2 элемента в общий div и уже его позиционировать.

  6. Тима

    а ты сам все знаешь?

  7. Sergey

    я тут не пойму только для чего манипуляции с вкл/выкл "фикса" в момент начала скроллинга? почему нельзя изначально задать его в стилях, а эффекты уже добавлять при прокрутке с помощью js..?

    1. Дмитрий Давыдов

      Sergey, дело вкуса и подхода.

  8. Станислав

    Как сделать чтобы она не дёргалась?

    1. Дмитрий Давыдов

      Станислав, что вы имеете ввиду?

    2. Дмитрий Давыдов

      Станислав, попробуйте изначально задать в стилях position:fixed, а остальные эффекты добавлять уже при скролле.

  9. Юрий

    Зравствуйте, Дмитрий. Столько полезного на сайте... Здорово!
    Вопрос такой появилась необходимость в фиксированной шапке. Сайт вам знаком https://podokonniki.hpltop.ru/
    Благодаря статье я добился скроллинга, но присутствует дергание. Не подскажите в чем может быть причина? Стили я взял со статьи,

    1. Дмитрий Давыдов

      Попробуйте сразу сделать фиксированной шапку, просто дайте отступ сверху (padding-top) контенту, который спрячется за ней. Тогда рыка не будет.

  10. Алекс

    а где исходники можно посмотреть? не вижу в конце статьи(

    1. Дмитрий Давыдов

      Добавил ссылку. Видимо, удалил случайно. Проверьте.

  11. Віктор

    Є дуже груба помилка в коді, діма! Сєдове - це українське місто і тому ні в якому разі не може бути з .RU!

  12. Дмитрий Давыдов

    Віктор, у вас також є дуже груба помилка в моєму імені. Написано з маленької. Ще декілька років тому нікого не піклувало .ru чи не .ru. Не хочу робити з блога політичний майданчик. Тут багато адекватних людей як з РФ, так і з України.

Добавить комментарий