Как установить смещение для ScrollSpy в Bootstrap?

98

У меня есть сайт с фиксированной навигационной панелью сверху и тремя блоками внизу в области основного содержимого.

Я пытаюсь использовать scrollspy из фреймворка начальной загрузки.

У меня он успешно выделяет разные заголовки в меню, когда вы прокручиваете мимо div.

У меня также есть, поэтому, когда вы нажимаете на меню, оно прокручивается до нужной части страницы. Однако смещение неверно (оно не учитывает навигационную панель, поэтому мне нужно смещение примерно на 40 пикселей)

Я вижу, что на странице Bootstrap упоминается параметр смещения, но я не уверен, как его использовать.

Я также не то, что означает, когда говорится, что вы можете использовать scrollspy $('#navbar').scrollspy(), я не уверен, где его включить, поэтому я этого не сделал, и все, похоже, работает (кроме смещения).

Я подумал, что смещение может быть data-offset='10'тегом body, но для меня это ничего не значит.

У меня такое чувство, что это что-то действительно очевидное, и я просто скучаю по нему. Любая помощь?

Мой код

...
<!-- note: the data-offset doesn't do anything for me -->
<body data-spy="scroll" data-offset="20">
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
    <div class="container">
    <a class="brand" href="#">VIPS</a>
    <ul class="nav">
        <li class="active">
             <a href="#trafficContainer">Traffic</a>
        </li>
        <li class="">
        <a href="#responseContainer">Response Times</a>
        </li>
        <li class="">
        <a href="#cpuContainer">CPU</a>
        </li>
      </ul>
    </div>
</div>
</div>
<div class="container">
<div class="row">
    <div class="span12">
    <div id="trafficContainer" class="graph" style="position: relative;">
    <!-- graph goes here -->
    </div>
    </div>
</div>
<div class="row">
    <div class="span12">
    <div id="responseContainer" class="graph" style="position: relative;">
    <!-- graph goes here -->
    </div>
    </div>
</div>
<div class="row">
    <div class="span12">
    <div id="cpuContainer" class="graph" style="position: relative;">
    <!-- graph goes here -->
    </div>
    </div>
</div>
</div>

...
<script src="assets/js/jquery-1.7.1.min.js"></script>
<script src="assets/js/bootstrap-scrollspy.js"></script>
</body>
</html>
Ланго
источник
Почему вы указываете позицию: относительно ваших div? Возможно, это причина этого. Можете ли вы создать jsfiddle со своим кодом, чтобы мы могли видеть в действии?
periklis

Ответы:

113

Bootstrap использует смещение только для разрешения шпионажа, а не прокрутки. Это означает, что прокрутка до нужного места зависит от вас.

Попробуйте, у меня это работает: добавьте обработчик событий для щелчков навигации.

var offset = 80;

$('.navbar li a').click(function(event) {
    event.preventDefault();
    $($(this).attr('href'))[0].scrollIntoView();
    scrollBy(0, -offset);
});

Я нашел его здесь: https://github.com/twitter/bootstrap/issues/3316

Курт UXD
источник
3
Спасибо за ответ. Мне потребовалось некоторое время, чтобы понять, что смещение не влияет на прокрутку. Это означает, что любой, кто использует фиксированный верх, должен вручную отрегулировать его таким образом.
Брайан Смит,
8
Чтобы обновить хэш-раздел URL-адреса соответствующим образом, добавьте window.location.hash = $(this).attr('href')эту функцию.
Стивен М. Харрис,
2
Спасибо! FWIW, размещение смещения данных в теле также важно, поскольку спрашивающий говорит, что он ничего не делает, но он нужен для правильного шпионажа. Было бы полезно получить исчерпывающий ответ.
mrooney
4
Динамичная победа: var navOffset = $('#navbar').height();иscrollBy(0, -navOffset);
ahnbizcad
79

Уловка, как намекал Тим, состоит в том, чтобы воспользоваться дополнением. Итак, проблема в том, что ваш браузер всегда хочет прокрутить ваш якорь точно до верхней части окна. если вы установите привязку там, где на самом деле начинается текст, он будет перекрыт строкой меню. Вместо этого вы устанавливаете привязку к контейнеру <section>или <div>идентификатору тега, который будет автоматически использоваться навигационной панелью / навигационной панелью. Затем вы должны установить ваш padding-topдля контейнера на сумму смещение вы хотите, и margin-topдля контейнера в противоположном из padding-top. Теперь блок вашего контейнера и якорь начинаются точно в верхней части страницы, но содержимое внутри начинается только под строкой меню.

Если вы используете обычные якоря, вы можете сделать то же самое, используя отрицательный маржинальный верх в вашем контейнере, как указано выше, но без заполнения. Затем вы помещаете обычный <a target="...">якорь в качестве первого дочернего элемента контейнера. Затем вы стилизуете второй дочерний элемент с противоположным, но равным margin-top, но с использованием селектора .container:first-child +.

Все это предполагает, что для вашего <body>тега уже установлено поле, начинающееся под вашим заголовком, что является нормой (в противном случае страница сразу же отобразилась бы с закрытым текстом).

Вот пример этого в действии. Все на вашей странице с идентификатором можно связать, добавив # the-elements-id в конец URL-адреса. Если вы сделаете все свои h-теги ad dt-тегами с возможностью связывания идентификаторов ( как это делает github ), с помощью какого-то скрипта, который вставляет небольшую ссылку слева от них ; добавление следующего в ваш CSS позаботится о смещении навигационной панели за вас:

body {
    margin-top: 40px;/* make room for the nav bar */
}

/* make room for the nav bar */
h1[id],
h2[id],
h3[id],
h4[id],
h5[id],
h6[id],
dt[id]{
    padding-top: 60px;
    margin-top: -40px;
}
Acjay
источник
9
Любите комбинацию padding-top и отрицательного margin-bottom (на том же элементе). Проще возиться с js.
Эйстейн
Похоже, лучший ответ, но я немного заблудился. Есть шанс привести пример.
eddyparkinson
@eddyparkinson, думаю, вы поняли это прямо сейчас: Пример, когда ваш идентификатор указан в строках начальной загрузки: .row [id] {padding-top: 60px; маржа сверху: -40 пикселей; } Поместите это в свой файл less: .row [id] {padding-top: 60px; маржа сверху: -40 пикселей; }
Klaaz 05
Разве для этого не предназначен параметр смещения начальной загрузки по умолчанию? Это изобилует такой очевидной вещью, которую нужно включить, и не нужно прибегать к подобным обходным путям.
ahnbizcad
Действительно ли это добавляет дополнительное пространство в div, на который вы нацеливаетесь? Что делать, если вы этого не хотите? Невидимый лишний интервал был бы идеальным.
ahnbizcad
10

Вы можете изменить смещение scrollspy на лету с помощью этого (при условии, что вы следите за телом):

offsetValue = 40;
$('body').data().scrollspy.options.offset = offsetValue;
// force scrollspy to recalculate the offsets to your targets
$('body').data().scrollspy.process();

Это также работает, если вам нужно динамически изменять значение смещения. (Мне нравится, когда scrollspy переключается, когда следующий раздел находится примерно на полпути к окну, поэтому мне нужно изменить смещение во время изменения размера окна.)

Cogell
источник
2
Спасибо за это - отлично работает с небольшой настройкой для Bootstrap 3.0 $ ('body'). Data () ['bs.scrollspy']. Options.offset = newOffset; // Устанавливаем новое смещение $ ('body'). Data () ['bs.scrollspy']. Process (); // Заставить scrollspy пересчитать смещения к вашим целям $ ('body'). Scrollspy ('refresh'); // Обновляем scrollspy.
Sam
Я обнаружил, что этот метод хорош, но если я хочу использовать его для установки смещения с самого начала из-за разной высоты меню, $ ('body'). Data (). Scrollspy.options.offset (или вариант для версии 3.0) еще не установлен. Есть ли что-то асинхронное в scrollspy, которое мне не хватает?
ness-EE
Начиная с Bootstrap 3.1.1 это должно быть $('body').data()['bs.scrollspy'].options.offset. Полезно для запуска scrollspy при загрузке страницы с помощьюwindow.scrollBy(X,Y)
Мередит
8

Если вам нужно смещение 10, вы должны вставить это в свою голову:

<script>
  $('#navbar').scrollspy({
    offset: 10
  });
</script>

Тег вашего тела будет выглядеть так:

<body data-spy="scroll">
Дэвид Наффис
источник
6
Это не смещает контент, а смещает навигацию.
markus 05
Это будет работать для выделения правильного элемента навигации, а не места, куда ведет щелчок (что является исходным вопросом плаката). С учетом сказанного, это было то, что я искал! Спасибо!
valin077
6

Из проблемы начальной загрузки № 3316 :

[Это] предназначено только для изменения вычислений прокрутки - мы не смещаем фактический щелчок по привязке

Таким образом, установка смещения влияет только на то, где scrollspy думает, что страница прокручивается . Это не влияет на прокрутку при нажатии тега привязки.

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

var navOffset = $('.navbar').height();

$('.navbar li a').click(function(event) {
    var href = $(this).attr('href');

    // Don't let the browser scroll, but still update the current address
    // in the browser.
    event.preventDefault();
    window.location.hash = href;

    // Explicitly scroll to where the browser thinks the element
    // is, but apply the offset.
    $(href)[0].scrollIntoView();
    window.scrollBy(0, -navOffset);
});

Однако, чтобы убедиться, что scrollspy подсвечивает правильный текущий элемент, вам все равно нужно установить смещение:

<body class="container" data-spy="scroll" data-target=".navbar" data-offset="70">

Вот полная демонстрация JSFiddle .


В качестве альтернативы вы можете дополнить свои теги привязки, как это предлагается трюками CSS .

a[id]:before { 
  display: block; 
  content: " ";
  // Use the browser inspector to find out the correct value here.
  margin-top: -285px; 
  height: 285px; 
  visibility: hidden; 
}
Уилфред Хьюз
источник
1

Я думаю, что это смещение может что-то сделать с нижним положением раздела.

Я исправил свою проблему - такую ​​же, как и вашу, - добавив

  padding-top: 60px;

в объявлении раздела в bootstrap.css

Надеюсь, это поможет!

Тим
источник
что такое "объявление для раздела" Где вы помещаете этот код?
ahnbizcad
1

Я добавил элемент высотой 40 пикселей .vspaceс привязкой перед каждым из моих h1элементов.

<div class="vspace" id="gherkin"></div>
<div class="page-header">
  <h1>Gherkin</h1>
</div>

В CSS:

.vspace { height: 40px;}

Он отлично работает, и места не забивает.

Квентин
источник
1

Bootstrap 4 (обновление 2019)

Реализация: фиксированная навигация, прокрутка и плавная прокрутка

Это решение от @ wilfred-hughes выше, оно точно устраняет проблему перекрытия с фиксированной навигационной панелью Bootstrap, используя CSS ':: before' для добавления неотображаемого блока перед каждым тегом раздела. Преимущество: вы не получаете ненужных отступов между разделами. Например, раздел 3 можно расположить вертикально вплотную к разделу 2, и он все равно будет прокручиваться до точного правильного положения вверху раздела 3.

Боковое примечание: установка смещения scrollspy в теге скрипта не привела к тому, что ничего не произошло ($ ('# navbar'). Scrollspy ({offset: 105});), и попытки отрегулировать смещение в блоке анимации по-прежнему приводили к рассогласованию пост- анимация.

index.html

<section id="section1" class="my-5">
...
<section id="section2" class="my-5">
...
<section id="section3" class="my-5">
...

позже в index.html ...

 <script>
      // Init Scrollspy
      $('body').scrollspy({ target: '#main-nav' });

      // Smooth Scrolling
      $('#main-nav a').on('click', function(event) {
        if (this.hash !== '') {
          event.preventDefault();

          const hash = this.hash;

          $('html, body').animate(
            {
              scrollTop: $(hash).offset().top
            },
            800,
            function() {
              window.location.hash = hash;
            }
          );
        }
      });
    </script>

style.css:

// Solution to Fixed NavBar overlapping content of the section.  Apply to each navigable section.
// adjust the px values to your navbar height
// Source: https://github.com/twbs/bootstrap/issues/1768
#section1::before,
#section2::before,
#section3::before {
  display: block;
  content: ' ';
  margin-top: -105px;
  height: 105px;
  visibility: hidden;
}

body {
  padding-top: 105px;
}

Предоставлено: @ wilfred-hughes выше и исходный источник от пользователя @mnot на https://github.com/twbs/bootstrap/issues/1768.

ObjectiveTC
источник
1
Спасибо! тьфу, я уже час борюсь с этим, LOL!
Nexus,
0

У меня были проблемы с решениями acjohnson55 и Kurt UXD. Оба работали для нажатия ссылки на хеш, но смещение scrollspy по-прежнему было неправильным.

Я пришел к следующему решению:

<div class="anchor-outer">
  <div id="anchor">
    <div class="anchor-inner">
      <!-- your content -->
    </div>
  </div>
</div>

И соответствующий CSS:

body {
  padding-top:40px;
}

.anchor-outer {
  margin-top:-40px;
}

.anchor-inner {
  padding-top:40px;
}

@media (max-width: 979px) {
  body {
    padding-top:0px;
  }

  .anchor-outer {
    margin-top:0px;
  }

  .anchor-inner {
    padding-top:0px;
  }
}

@media (max-width: 767px) {
  body {
    padding-top:0px;
  }

  .anchor-outer {
    margin-top:0px;
  }

  .anchor-inner {
    padding-top:0px;
  }
}

Вам нужно будет заменить отступ / поле 40 пикселей на высоту вашей панели навигации и идентификатор вашего якоря.

В этой настройке я даже могу наблюдать эффект установки значения для атрибута data-offset. Если найти большие значения для data-offset около 100-200, это приведет к более ожидаемому поведению (scrollspy- "switch" произойдет, если заголовок будет примерно посередине экрана).

Я также обнаружил, что scrollspy очень чувствителен к ошибкам, таким как незакрытые теги div (что вполне очевидно), поэтому http://validator.w3.org/check был моим другом.

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

Schreon
источник
0

Если вы наткнулись на этот вопрос (как и я) через Google и все еще ищете способ динамического изменения смещения scrollspy. Сейчас я прикрепляю ссылку на решение, которое сработало для меня.

Взгляните на этот пост, который я сделал в другой ветке . Он содержит отрывок о том, как вы можете программно изменить значение смещения и динамически реагировать на изменения (например, если панель навигации изменяется в размере).

Вам не нужно возиться с исправлениями CSS, а лучше установить необходимое смещение в зависимости от определенных событий.

thex
источник
-1

Вы также можете открывать bootstap-offset.jsи изменять

$.fn.scrollspy.defaults = {
  offset: 10
}

там.

Adobe
источник
1
Смещение scrollspy не смещает контент, а смещает навигацию.
markus 05
-1

Просто установите:

data-offset="200"

data-offsetпо умолчанию "50", что эквивалентно 10px, так что просто увеличьте, data-offsetи ваша проблема будет решена.

Живанич
источник