Как добавить плавающий блок на страницу

Что дела­ем: пла­ва­ю­щий блок на стра­ни­це, что­бы его содер­жи­мое все­гда было на экране даже при скрол­ле. При этом что­бы у него было «исход­ное» место на стра­ни­це: напри­мер, кноп­ка сто­ит в нача­ле стра­ни­цы, а потом мы скрол­лим стра­ни­цу вниз, а кноп­ка зали­па­ет. А когда мы скрол­лим обрат­но, в нуж­ном месте кноп­ка при­ли­па­ет обрат­но на нуж­ное место. 

Зачем: если вы хоти­те, что­бы поль­зо­ва­тель всё вре­мя видел какую-то инфор­ма­цию — кноп­ку с реги­стра­ци­ей, меню или содер­жи­мое кор­зи­ны. Но при этом что­бы это выгля­де­ло логич­но и акку­рат­но. 

Вре­мя: 5 минут.

С чем рабо­та­ем: JavaScript, jQuery и CSS.

Что пона­до­бит­ся: bootstrap для раз­мет­ки стра­ни­цы.

👉 Бла­го­да­ря раз­ви­тию тех­но­ло­гий такую шту­ку мож­но сде­лать бук­валь­но за одну коман­ду: 

  • С помо­щью css-свойства position:sticky. Тогда всё будет рабо­тать имен­но так, как нам надо, но будет под­дер­жи­вать­ся не во всех бра­у­зе­рах.
  • С помо­щью position:fixed. Тогда блок будет про­сто всё вре­мя в одном месте на экране, без «домаш­не­го» поло­же­ния. Напри­мер, кноп­ка будет все­гда висеть в пра­вом верх­нем углу экра­на, как бы мы ни кру­ти­ли стра­ни­цу. 

В прин­ци­пе, под­держ­ка position:sticky ста­но­вит­ся всё луч­ше, поэто­му мож­но было бы оста­но­вить­ся на ней. Но ради люб­ви к исто­рии и из сооб­ра­же­ний пара­нойи вос­поль­зу­ем­ся косты­ля­ми, кото­ры­ми поль­зо­ва­лись раз­ра­бот­чи­ки послед­ние 10 лет: исполь­зу­ем jQuery.

1. Размечаем страницу

Смысл такой: мы делим стра­ни­цу на две части: с основ­ным содер­жи­мым и пла­ва­ю­щий блок. Основ­ной части дадим 10 вир­ту­аль­ных коло­нок, а пла­ва­ю­ще­му бло­ку — 2 остав­ши­е­ся. Для это­го мы исполь­зу­ем фрейм­ворк Bootstrap, но мож­но и про­сто свер­стать что-то вруч­ную.

Если нуж­но, что­бы блок был сле­ва — поме­няй­те места­ми их в коде с основ­ным бло­ком.

<section>
  <div class="row">

    <!-- основной блок шириной 10 колонок -->
    <div class="col-md-10">
      <!-- сюда кладём то, что будет вести себя как обычная страница -->
      <div class="content-block">
        <h3>Заголовок</h3>
        <p>Тут — любой текст, картинки или что-то ещё. Это же бутстрап, здесь можно всё.</p>
      </div>
    </div>

    <!-- А здесь — наш плавающий блок -->
    <div class="col-md-2">
      <div class="float-block">
        <!-- здесь тоже можно прописать что угодно -->
      </div>
    </div>
    
  </div>
</section>

2. Добавляем стили

Сти­ли помо­гут настро­ить нам внеш­ний вид каж­до­го бло­ка так, как нам нуж­но. Их нуж­но доба­вить в раз­дел <style> или под­клю­чить отдель­ным .css-файлом.

/* отвечает за оба блока в целом */
section{
  max-width: 600px;
  margin:0 auto;
}

/* настройки основного блока */
.col-md-10{
  min-height: 900px;
} 
.content-block{
  padding: 15px;
}

/* настройки плавающего блока */
/* для наглядности это будет пока красный квадрат */
.float-block{
  background-color: red;
  height: 50px;
  width: 50px;
  position:absolute;
  top: 150px;
}

3. Включаем «липкость»

Логи­ка такая: нуж­ный нам блок (напри­мер, кноп­ка) живёт в стра­ни­це как обыч­ный объ­ект. Но когда мы доскрол­ли­ва­ем до опре­де­лён­но­го места, этот блок «выры­ва­ет­ся» из обще­го пото­ка стра­ни­цы и при­креп­ля­ет­ся к экра­ну спра­ва навер­ху. 

Это пове­де­ние в совре­мен­ных бра­у­зе­рах реа­ли­зо­вы­ва­ет­ся в css так:

.float-block{position:sticky}

Но мы ори­ен­ти­ру­ем­ся не толь­ко на совре­мен­ные бра­у­зе­ры. Поэто­му исполь­зу­ем тяжё­лую артил­ле­рию.

Под­клю­ча­ем jQuery к стра­ни­це в раз­де­ле <head>:

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

Теперь добав­ля­ем скрипт, кото­рый даст нам нуж­ное пове­де­ние для бло­ков. Его мож­но доба­вить тегом <script> или выне­сти в отдель­ный файл.

// «Липкий» код
$(function(){
  $.fn.followTo = function (pos) {
    var $this = this,
        $window = $(window);

    $window.scroll(function (e) {
        if ($window.scrollTop() > pos) {
            $this.css({
                position: 'fixed',
                top: 10
            });
        } else {
            $this.css({
                position: 'absolute',
                top: 150
            });
        }
    });
};

$('.float-block').followTo(140);
});

По сути, этот скрипт гово­рит: «Если мы доскрол­ли­ли ниже это­го эле­мен­та, ска­жи ему position:fixed. А если выше, ска­жи ему position:absolute». 

Вопрос из зала: «Почему вы используете jQuery, чтобы тупо обратиться к объекту на странице? Нельзя было просто написать обращение вручную, раз уж вы делаете всё на костылях»?

Отве­ча­ет Миша Поля­нин: 

При­чи­ны две: 

  1. Sticky рабо­та­ет не все­гда пра­виль­но во всех бра­у­зе­рах. Быва­ют ситу­а­ции, когда даже в зави­си­мо­сти от вер­сии одно­го и того же бра­у­зе­ра резуль­тат на экране и пове­де­ние отли­ча­ют­ся от ожи­да­е­мо­го. 
  2. Есть эле­мен­ты, с кото­ры­ми sticky вооб­ще не рабо­та­ет или рабо­та­ет через раз, напри­мер, если у кон­тей­не­ра есть свой­ство overflow: hidden. А вот jQuery вооб­ще всё рав­но, какие у кого свой­ства, глав­ное — полу­чить доступ к нуж­но­му эле­мен­ту, и мож­но делать с ним что угод­но. 

Но если под­хо­дить к объ­ек­там на стра­ни­це гло­баль­но, то полу­ча­ет­ся, что на прак­ти­ке рабо­тать с эле­мен­та­ми через jQuery полу­ча­ет­ся удоб­нее:

  • удоб­нее нахо­дить нуж­ные эле­мен­ты по любым свой­ствам и харак­те­ри­сти­кам;
  • когда таких эле­мен­тов мно­го, орга­ни­зо­вать их поточ­ную обра­бот­ку через jQuery тоже часто полу­ча­ет­ся быст­рее;
  • не нуж­но думать о сов­ме­сти­мо­сти в бра­у­зе­рах — jQuery-код будет рабо­тать оди­на­ко­во хоро­шо в любом бра­у­зе­ре.

Посмот­реть, как рабо­та­ет, и поиг­рать с кодом на CodePen.

Текст и код:
Миша Поля­нин

Редак­тор:
Мак­сим Илья­хов

Кор­рек­тор:
Ира Михе­е­ва

Иллю­стра­тор:
Даня Бер­ков­ский

Вёрст­ка:
Маша Дро­но­ва

Достав­ка:
Олег Веш­кур­цев