Bootstrap 3 - Affix

На этом уроке мы познакомимся с плагином Twitter Bootstrap affix и научимся его добавлять к элементам веб-страницы.

Плагин Twitter Bootstrap Affix предназначен для "прикрепления" элемента веб-страницы к краям окна браузера. "Прикреплённый" элемент при прокрутке веб-страницы будет оставаться в определённом месте и находиться в поле зрения пользователя. Плагин affix позволяет также выключать это "прикрепление", т.е. работать в режиме переключателя (т.е. выключать или включать прикрепление элемента к краям окна браузера). Реализуется этот принцип посредством изменения значения CSS свойства position элемента веб-страницы из static в fixed.

Плагин affix очень часто применяют к социальным иконкам на сайте, которые при прокрутке веб-страницы всегда располагаются в определённом месте и доступны для просмотра пользователю.

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

Плагин affix может переключаться между тремя классами, каждый из которых представляет определенное состояние: .affix, .affix-top, и .affix-bottom.

Принцип работы плагина Affix:

  • Изначально плагин добавляет класс .affix-top или .affix-bottom, чтобы определить самое верхнее или самое нижнее положение элемента. На этом шаге CSS позиционирование элемента не требуется.
  • При прокрутке страницы элемент смещается вместе с текстом, но его смещение ограничено значением атрибута data-offset-top-* или data-offset-bottom-*. После достижения этого ограничения плагин заменяет класс .affix-top или .affix-bottom на .affix и устанавливает элементу CSS свойство position со значением fixed (т.е. фиксированное позиционирование), которое "прикрепляет" элемент.
  • В этой точке необходимо соответствующее свойство CSS top или bottom, чтобы определить позицию элемента, к которому добавлен плагин Affix, в области просмотра веб-страницы.

Плагин Affix можно добавить к любому элементу веб-страницы с помощью атрибута data-spy="affix". После этого с помощью атрибута data-offset- установите величину смещения, которая определяет момент прикрепления элемента к верхнему или нижнему краю окна браузера.

<!-- Добавление Affix к элементу div с помощью атрибута data-spy="affix", и смещения с помощью атрибута data-offset-top -->
<div data-spy="affix" data-offset-top="20">
  ...
</div>

Вы также можете добавить плагин Affix к элементам, используя сценарий на языке JavaScript. Для этого Вам необходимо вызвать для элемента веб-страницы, используя её идентификатор или имя класса, метод Bootstrap affix().

<!-- Сценарий на языке JavaScript -->
<script>
// #myAffix - идентификатор элемента к которому необходимо
// добавить Affix
$('#myAffix').affix({
  // установка смещений с помощью параметра offset
  offset: {
    top: 100,
    bottom: function () {
      // возвращает значение высоты 
      // элемента веб-страницы с классом .footer
      return (this.bottom = $('.footer').outerHeight(true))
    }
  }
})
</script>
...
<!-- Добавление Affix к элементу div с помощью JavaScript -->
<div id="myAffix">
...
</div>

Параметры могут быть установлены с помощью атрибутов Data или JavaScript. Для атрибутов Data добавьте имя параметра к data- (например: data-offset-top=100).

Параметр Описание
offset Тип: number | function | object. Значение по умолчанию: 10. Задаёт величину смещения элемента в пикселях от краёв экрана. Данное значение является контрольной точкой, при которой плагин переключает элемент веб-страницы из одного состояния в другое и наоборот, т.е. включает или выключает "прикрепление" элемента. Величина смещения вычисляется на основании позиции прокрутки. Если Вы зададите в качестве смещения одно значение, то оно будет применяться в обоих направлениях (верх и вниз).
Например: offset:{top: 20} или offset:{top:20,bottom:10}
Если Вам необходимо динамически вычислить значение смещения, то используйте функцию.
target Тип: селектор | узел | элемент jQuery. Значение по умолчанию: объект window. Этот параметр предназначен для указания элемента, к которому необходимо добавить плагин Affix.

События для плагина Affix представлены в следующей таблице.

Событие Описание
affix.bs.affix Это событие срабатывает перед "прикреплением" элемента к верхнему или нижнему краю окна браузера.
affixed.bs.affix Это событие срабатывает после "прикрепления" элемента к верхнему или нижнему краю окна браузера.
affix-top.bs.affix Это событие срабатывает перед выключением "прикрепления" элемента, т.е когда класс .affix заменяется на .affix-top.
affixed-top.bs.affix Это событие срабатывает после выключения "прикрепления" элемента к , т.е когда класс .affix заменяется на .affix-top.
affix-bottom.bs.affix Это событие срабатывает перед выключением "прикрепления" элемента, т.е когда класс .affix заменяется на .affix-bottom.
affixed-bottom.bs.affix Это событие срабатывает после выключения "прикрепления" элемента к , т.е когда класс .affix заменяется на .affix-bottom.
<script type="text/javascript">
$(document).ready(function(){
  $("#myNav").affix({
    offset: { 
      top: 200 
    }
  });
  $("#myNav").on('affixed.bs.affix', function(){
    alert("Меню навигации была прикреплена. Теперь она не прокручивается вместе со страницей.");
  });
});
</script>

<div class="container">
  <div class="row">
    <div class="col-xs-3">
      <div id="myNav" class="list-group">
        <a href="#section1" class="list-group-item">Раздел1</a>
        <a href="#section2" class="list-group-item">Раздел2</a>
        <a href="#section3" class="list-group-item">Раздел3</a>
      </div>
    </div>
    <div class="col-xs-9">
      <section id="section1">
        <h2>Раздел 1</h2>
        <p>Содержание раздела 1...</p>
      </section>
      <section id="section2">
        <h2>Раздел 2</h2>
        <p>Содержание раздела 2...</p>
      </section>
      <section id="section3">
        <h2>Раздел 3</h2>
        <p>Содержание раздела 3...</p>
      </section>
    </div> 
  </div>
</div>

Изображение, на котором изображен результат выполнения события affixed.bs.affix

Скачать пример

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

Пример совместного использования плагинов Affix и ScrollSpy

Открыть пример


   Bootstrap 0    17616 0

Комментарии (21)

  1. Анатоилй # 0
    Здравствуйте!
    Прочитал вашу статью о прилипающем меню. Bootstrap только начал изучать и в java я пока не силен. Но никак не могу сделать это проклятое прилипающее меню на bootstrap с помощью плагинов scrollspy.js и affix.js. На странице их подключил, но при прокрутке (меню-которое надо закрепить) выскакивает и стоит слева по середине страницы.
    Прошу вас помочь. Вот код меню. Посмотрите пожалуйста что я делаю не так.

     <nav role="navigation" class="navbar navbar-default nav-fixed-top"  data-spy="affix" data-offset-top="185" id="affix">
                          <div class="navbar-header" >
                             <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#collapse"><span class="sr-only">Навигация</span>
                                <span class="icon-bar"></span>
                                <span class="icon-bar"></span>
                                <span class="icon-bar"></span>                         
                             </button>
                              <a class="navbar-brand" href="index.html">Logo</a>
                          </div>
                          <div class="collapse navbar-collapse" id="collapse" >  
                              <ul class="nav navbar-nav navbar-right">
                                   <li><a href="#">Начало</a></li>
                                   <li><a href="#">Портфолио</a></li>
                                   <li><a href="#">Сервис</a></li>
                                   <li><a href="#">Контакты</a></li>
                               </ul>
                           </div>
                   </nav>
    
    1. Александр Мальцев # 0
      Здравствуйте, Анатолий!
      Не очень понятно, про какое меню идёт речь.
      Если Вы хотите использовать стандартное меню bootstrap, то его можно прикрепить к верхнему краю с помощью добавления класса navbar-fixed-top к элементу nav. В этом случае affix не нужен. Кроме этого стандартного класса nav-fixed-top нет. Т.е. код меню будет такой:
      <nav role="navigation" class="navbar navbar-default navbar-fixed-top">
      <!-- ... -->
      </nav>
      
      1. Михаил # 0
        дабы Ваше меню с прокруткой и фиксацией в top работало исправно, уберите из кода nav-fixed-top (предназначено для изначальной фиксации в TOP)
      2. Евгений Ко # 0
        Здравствуйте,
        наблюдается следующая проблема: внизу экрана Affix начинает накрываться текстом, формами и т.д. Как решить эту проблему?
        И за одно вопрос Как установить
        <div id="Affix">
            <ul class="list-inline" >
        	<li><a .....
        по центру.
        text-align: center;- не работает?
        Спасибо за столь полезный сайт и за возможный ответ.
        1. Александр Мальцев # 0
          Здравствуйте, Евгений!
          Для этого Вам необходимо установить значение bottom. Можно использовать либо какую-то фиксированную величину (например 500px) или вычислять данное значение с помощью функции.
          $('#myAffix').affix({
            // установка смещений с помощью параметра offset
            offset: {
              top: 100,
              bottom: 500
            }
          })
          
          Кроме этого необходимо ещё прописать стили CSS для .affix-bottom (т.е. когда Ваш affix блок будет достигать bottom). Обычно для этого класса задают свойство position (как минимум) и другие:
          .affix-bottom {
            position: absolute;
          }
          
          Для выравнивания элемента по центру, попробуйте применить к нему класс .center-block.
        2. Михаил # 0
          Здравствуйте, у меня стандартное меню bootstrap расположено в 150пикс от верха страницы, как сделать чтобы при перелистывание когда до него дойдет верхний край страницы оно приклеивалось?
          <div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
            <div class="container">
              <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                  <span class="sr-only">Toggle navigation</span>
                  <span class="icon-bar"></span>
                  <span class="icon-bar"></span>
                  <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand" href="http://bootstrap-3.ru/examples/jumbotron/#">Project name</a>
              </div>
              <div class="navbar-collapse collapse">
                <form class="navbar-form navbar-right" role="form">
                  <div class="form-group">
                    <input type="text" placeholder="Email" class="form-control">
                  </div>
                  <div class="form-group">
                    <input type="password" placeholder="Password" class="form-control">
                  </div>
                  <button type="submit" class="btn btn-success">Sign in</button>
                </form>
              </div><!--/.navbar-collapse -->
            </div>
          </div>
          
          1. Александр Мальцев # 0
            Здравствуйте, Михаил.
            Для этого у меню необходимо убрать у навигационного меню класс .navbar-fixed-top.
            После этого добавить к меню data-атрибуты affix:
            <div class="navbar navbar-inverse" data-spy="affix" data-offset-top="150" role="navigation">
            
            Кроме этого надо ещё задать стили CSS для меню, когда оно будет находиться в режиме affix:
            .navbar.affix {
              position: fixed;
              top: 0;
              width: 100%;
              z-index:1000;
            }
            
          2. Антон # 0
            А можно посмотреть исходник последнего примера
            Пример совместного использования плагинов Affix и ScrollSpy
            Очень нужен сейчас для работы
            1. Александр Мальцев # 0
              Код HTML:
              <body data-spy="scroll" data-target="#myScrollspy">
              <div class="container">
                <div class="jumbotron">
                  <h1>Bootstrap ScrollSpy и Affix</h1>
                </div>
                <div class="row">
                  <div class="col-xs-3" id="myScrollspy">
                    <ul class="nav nav-tabs nav-stacked" data-spy="affix" data-offset-top="125">
                      <li class="active"><a href="#section-1">1 раздел</a></li>
                      <li><a href="#section-2">2 раздел</a></li>
                      <li><a href="#section-3">3 раздел</a></li>
                      <li><a href="#section-4">4 раздел</a></li>
                      <li><a href="#section-5">5 раздел</a></li>
                    </ul>
                  </div>
                  <div class="col-xs-9">
                    <h2 id="section-1">1 раздел</h2>
                    <p>Содержимое 1 раздела...</p>
                    <h2 id="section-2">2 раздел</h2>
                    <p>Содержимое 2 раздела...<p>
                    <h2 id="section-3">3 раздел</h2>
                    <p>Содержимое 3 раздела...</p>
                    <h2 id="section-4">4 раздел</h2>
                    <p>Содержимое 4 раздела...</p>
                    <h2 id="section-5">5 раздел</h2>
                    <p>Содержимое 5 раздела...</p>
                  </div>
                </div>
              </div>
              </body>
              

              Код CSS:
              ul.nav-tabs{
                width: 140px;
                margin-top: 20px;
                border-radius: 4px;
                border: 1px solid #ddd;
                box-shadow: 0 1px 4px rgba(0, 0, 0, 0.067);
              }
              ul.nav-tabs li{
                margin: 0;
                border-top: 1px solid #ddd;
              }
              ul.nav-tabs li:first-child{
                border-top: none;
              }
              ul.nav-tabs li a{
                margin: 0;
                padding: 8px 16px;
                border-radius: 0;
              }
              ul.nav-tabs li.active a, ul.nav-tabs li.active a:hover{
                color: #fff;
                background: #0088cc;
                border: 1px solid #0088cc;
              }
              ul.nav-tabs li:first-child a{
                border-radius: 4px 4px 0 0;
              }
              ul.nav-tabs li:last-child a{
                border-radius: 0 0 4px 4px;
              }
              ul.nav-tabs.affix{
                top: 30px;
              }
              
            2. Владимир # 0
              Здравствуйте.

              Изначально у меня используется для меню

              <div class="navbar navbar-inverse navbar-static-top" role="navigation" data-spy="affix" data-offset-top="50">
              affix работает, но дело в том, что меню прижимается к левому краю (а хочется, чтобы меню было на всю ширину, только прилипало), как это сделать?
              1. Александр Мальцев # 0
                Настроить класс affix. Т.е. описать как должен выглядеть блок когда он откреплён.
                Как минимум так:
                .affix {
                  top: 0;
                  width: 100%;
                }
                
              2. Иван # 0
                Добрый день в моем случае имеется страница 3000рх высотой, левый блок высотой 1500рх и экран монитора высотой 900px
                При прокручивании сверху вниз в какой-то момент левый блок фиксируется, но, поскольку он по высоте больше чем разрешение экрана, можно ли сделать чтобы при достижении скролла высоты в 50% экрана и продолжении скролла вниз левый блок прокрутился вниз до достижении нижней его границы нижнего угла монитора?
                1. Александр Мальцев # 0
                  Для начала необходимо определить высоту страницы. Если она больше, например, 5000px, то только после этого выполнять манипуляции с блоком affix. Сам принцип можно организовать посредством CSS-свойства top.
                  HTML-код:
                  <div class="container">
                    <div class="row">
                      <div class="col-xs-8">
                        <div style="height: 5000px; background-color: pink;"></div>
                      </div>
                      <div id="right-block" class="col-xs-4">
                        <div style="height: 100px; background-color: pink;"></div>
                        <div id="myAffix" style="height: 1500px; background-color: brown;" data-spy="affix" data-offset-top="100"></div>
                      </div>
                    </div>
                  </div>
                  
                  CSS-код:
                  $(function(){
                    if ($(document).height()>5000) {
                      $(window).on('scroll', function () {
                        if (($(window).scrollTop())>($(document).height()/2)) {
                          var top = Math.round(($(window).scrollTop())-($(document).height()/2));
                          if (top>0) {
                            $('#myAffix').css('top',-top);
                          }
                        } 
                        else {
                          $('#myAffix').css('top','0px');
                        }
                      });
                    }
                    $('#myAffix').on('affix.bs.affix', function () {
                      $(this).width($('#right-block').width());
                    });
                  });
                  </script>
                  
                2. ctac # 0
                  простите новичка, но есть вопрос
                  надо что бы меню закреплялось на верху страницы как только страница опускается, но при этом меню
                  1. прикрепляется, вроде так и надо
                  2. но становится прозрачным, нажать на кнопки нельзя
                  3. при опускании страницы во время прикрепления меню, страница прыгает, на размер самого меню, видимо идет вырезание

                  как решить эти проблемы. спасибо.
                  HTML-код
                  <style>
                    .logo {
                      background-color: #f2f3f8;
                    }
                    .affix {
                      top: 0;
                      width: 100%;
                    }
                  </style>
                  
                  <header>
                    <div class="logo">
                      <div class="container">
                        <div class="row">
                          <div class=" col-sm-12 col-lg-8 sitename"><img src=".." alt=".." height=100></div>
                        </div>
                      </div>
                    </div>
                  
                    <!-- Навигация (affix) -->
                    <nav id="custom-bootstrap-menu" class="navbar navbar-default" data-spy="affix" data-offset-top="100">
                      ...
                    </nav>
                  </header>
                  
                  <main class=clearfix>
                    <div class="container">
                      <div class="row">
                        <!--Адаптивный блок article-->
                        <article class1="col-sm-12 col-md-8">
                          ...
                        </article>
                        <!--Адаптивный блок aside-->
                        <aside class="col-sm-12 col-md-4">
                          ...
                        </aside>
                      </div>
                    </div>
                  </main>
                  <footer>
                    ...
                  </footer>
                  
                  1. Александр Мальцев # 0
                    Меню отображается нормально, кнопки нажимаются. Т.е. то, что Вы привели, отображается нормально.
                    Если хотите привести готовую страницу или много кода, то это лучше сделать на специальном сервисе, например jsfiddle.net. В комментариях этого делать не стоит.
                    Третья проблема существует из-за того, что блок navbar (affix) при прокручивании выпадает из основного потока и становится fixed. Это приводит к тому, что блоки основного потока перемещаются вверх на 70px (высота navbar 50px + margin navbar 20px). Т.е. как бы блок affix исчезает и появляется отдельно над ними.
                    Чтобы это убрать, необходимо написать скрипт:
                    <script>
                    $('#custom-bootstrap-menu').on('affix.bs.affix', function () {
                      $('body').css('padding-top','70px');
                    });
                    $('#custom-bootstrap-menu').on('affix-top.bs.affix', function () {
                      $('body').css('padding-top','0px');
                    });
                    </script>
                    
                    1. ctac # 0
                      спасибо за ответ.
                      кнопки пропадают (становятся прозрачными) когда меню прилепляется к верху.
                      1. ctac # 0
                        вот пример
                        jsfiddle.net/h8qfkuhm/2/
                        1. Александр Мальцев # 0
                          Меню у Вас распологается ниже других элементов страницы.
                          Необходимо добавить в CSS следующее:
                          #custom-bootstrap-menu {
                            z-index: 1000;
                          }
                          
                    2. Максим # 0
                      Привет.
                      Подскажите, как отключить аффикс при открытии подменю в навбаре — на очень мелких устройствах подменю полностью не влазит и нижние пункты нельзя выбрать из-за прибитого навбара
                      1. Максим # 0
                        Понял: при открытии подменю отключать аффикс глупо — нужно будет считать его текущее положение по высоте, а возможно вылезут другие сложности, иначе навбар будет скакать вверх -вниз, поэтому просто отключил аффикс для мелких экранов
                        Но если у кого есть несложный вариант подобной конструкции — поделитесь
                        1. Александр Мальцев # 0
                          Привет. Тут необходимо установить какую-то максимальную высоту блоку navbar. Т.к. когда он становится affix, он имеет position: fixed.
                          Например, так:
                          /* CSS */
                          .affix {
                            top: 0px;
                            width: 100%;
                          }
                          @media (max-width: 767px) {
                            .navbar .navbar-collapse.in { 
                              max-height: 300px !important; 
                              overflow-y: scroll !important;
                            }
                          }
                          </style>
                          
                          Либо вычислить максимальную высоту устройства и установить данный параметр (max-height) с помощью JavaScript.

                      Вы должны авторизоваться, чтобы оставлять комментарии.