¿Cómo configuro el desplazamiento para ScrollSpy en Bootstrap?


98

Tengo un sitio con la barra de navegación fija en la parte superior y 3 divs debajo en el área de contenido principal.

Estoy tratando de usar scrollspy desde el marco de arranque.

Lo tengo resaltando con éxito los diferentes encabezados en el menú cuando se desplaza más allá de los divs.

También lo tengo, así que cuando haces clic en el menú, se desplazará a la parte correcta de la página. Sin embargo, el desplazamiento es incorrecto (no tiene en cuenta la barra de navegación, por lo que necesito un desplazamiento de unos 40 píxeles)

Veo en la página de Bootstrap que menciona una opción de compensación, pero no estoy seguro de cómo usarla.

Tampoco soy lo que significa cuando dice que puedes usar scrollspy con $('#navbar').scrollspy(), no estoy seguro de dónde incluirlo, así que no lo hice y todo parece estar funcionando (excepto el desplazamiento).

Pensé que el desplazamiento podría ser el data-offset='10'de la etiqueta del cuerpo, pero no hace nada por mí.

Tengo la sensación de que esto es algo realmente obvio y me lo estoy perdiendo. ¿Alguna ayuda?

Mi codigo es

...
<!-- 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>

¿Por qué estás dando una posición: relativa a tus divs? Quizás eso es lo que está causando esto. ¿Puedes crear un jsfiddle con tu código para que podamos verlo en acción?
periklis

Respuestas:


113

Bootstrap usa el desplazamiento para resolver solo el espionaje, no el desplazamiento. Esto significa que el desplazamiento al lugar adecuado depende de usted.

Prueba esto, me funciona: agrega un controlador de eventos para los clics de navegación.

var offset = 80;

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

Lo encontré aquí: https://github.com/twitter/bootstrap/issues/3316


3
Gracias por la respuesta. Me tomó bastante tiempo darme cuenta de que el desplazamiento no afecta el desplazamiento. Esto significa que cualquiera que use una capota fija debe ajustar manualmente de esta manera.
Brian Smith

8
Para actualizar la sección hash de la URL de manera adecuada, agregue window.location.hash = $(this).attr('href')a esta función.
Stephen M. Harris

2
¡Gracias! FWIW, poner la compensación de datos en el cuerpo también es importante, ya que el autor de la pregunta dice que no hace nada, pero es necesario para un espionaje adecuado. Podría ser útil tener una respuesta completa.
mrooney

4
var navOffset = $('#navbar').height();scrollBy(0, -navOffset);
Ganancia

78

El truco, como aludió Tim, es aprovechar el relleno. Entonces, el problema es que su navegador siempre quiere desplazar su ancla hasta la parte superior exacta de la ventana. si establece su ancla donde realmente comienza su texto, será ocluido por su barra de menú. En cambio, lo que hace es establecer su ancla en el contenedor <section>o <div>la identificación de la etiqueta, que la barra de navegación / navegación utilizará automáticamente. Luego, debe establecer su padding-toppara el contenedor en la cantidad de compensación que desea, y margin-toppara el contenedor en el opuesto de padding-top. Ahora el bloque de su contenedor y el ancla comienzan en la parte superior exacta de la página, pero el contenido del interior no comienza hasta debajo de la barra de menú.

Si está usando anclas regulares, puede lograr lo mismo usando un margen superior negativo en su contenedor como se indicó anteriormente, pero sin relleno. Luego pones un <a target="...">ancla regular como primer hijo del contenedor. Luego, diseña el segundo elemento hijo con un opuesto pero igual margin-top, pero usando el selector .container:first-child +.

Todo esto supone que su <body>etiqueta ya tiene su margen establecido para comenzar debajo de su encabezado, que es la norma (de lo contrario, la página se mostraría con texto ocluido desde el principio).

Aquí tienes un ejemplo de esto en acción. Se puede vincular cualquier elemento de su página con una identificación al agregar # the-elements-id al final de su URL. Si hace que todas sus etiquetas h y etiquetas dt con ID se puedan vincular ( como hace github ) con algún tipo de secuencia de comandos que inserte un pequeño vínculo a la izquierda de ellas ; agregar lo siguiente a su CSS se encargará del desplazamiento de la barra de navegación por usted:

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;
}

9
Me encanta la combinación de relleno superior, margen negativo inferior (en el mismo elemento). Más fácil que jugar con el js.
Eystein

Parece la mejor respuesta, pero estoy un poco perdido. Cualquier posibilidad de un ejemplo.
eddyparkinson

@eddyparkinson, supongo que lo descubrió ahora mismo: Por ejemplo, cuando tiene su identificación en las filas de bootstrap: .row [id] {padding-top: 60px; margen superior: -40px; } Pon esto en tu archivo menos: .row [id] {padding-top: 60px; margen superior: -40px; }
Klaaz

¿No se supone que el parámetro de compensación predeterminado del bootstrap es para esto? Parece una cosa tan obvia para incluir, y no tener que recurrir a soluciones como esta.
ahnbizcad

¿Esto agrega efectivamente espacio adicional en el div al que se dirige? ¿Y si no quieres eso? Un espacio adicional invisible sería ideal.
ahnbizcad

10

Puede cambiar el desplazamiento de scrollspy sobre la marcha con esto (suponiendo que esté espiando el cuerpo):

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

Esto también funciona si necesita cambiar el valor de compensación de forma dinámica. (Me gusta que el scrollspy cambie cuando la siguiente sección esté a la mitad de la ventana, por lo que necesito cambiar el desplazamiento durante el cambio de tamaño de la ventana).


2
Gracias por esto - funciona muy bien con un pequeño ajuste para Bootstrap 3.0 $ ('body'). Data () ['bs.scrollspy']. Options.offset = newOffset; // Establecer el nuevo desplazamiento $ ('cuerpo'). Data () ['bs.scrollspy']. Process (); // Obliga a scrollspy a recalcular las compensaciones a tus objetivos $ ('body'). Scrollspy ('refresh'); // Actualiza el scrollspy.
Sam

Descubrí que este método es bueno, pero que si quiero usarlo para establecer el desplazamiento desde el principio debido a que tengo diferentes alturas de menú, el $ ('body'). Data (). Scrollspy.options.offset (o la variante para la versión 3.0) aún no está configurada. ¿Hay algo asincrónico sobre scrollspy que me falta?
ness-EE

A partir de Bootstrap 3.1.1 esto debería ser $('body').data()['bs.scrollspy'].options.offset. Útil para activar scrollspy en la carga de la página usandowindow.scrollBy(X,Y)
Meredith

8

Si desea un desplazamiento de 10, debe poner esto en su cabeza:

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

Su etiqueta corporal se vería así:

<body data-spy="scroll">

6
Eso no compensa el contenido, compensa la navegación.
Markus

Esto funcionará para resaltar el elemento de navegación correcto y no la ubicación a la que conduce el clic (que es la pregunta de los carteles originales). Dicho esto, ¡esto era lo que estaba buscando! ¡Gracias!
valin077

6

Desde el problema de arranque # 3316 :

[Esto] solo está destinado a modificar los cálculos de desplazamiento; no cambiamos el clic de ancla real

Por lo tanto, establecer el desplazamiento solo afecta a donde scrollspy cree que se desplaza la página . No afecta el desplazamiento cuando hace clic en una etiqueta de anclaje.

Usar una barra de navegación fija significa que el navegador se desplaza al lugar equivocado. Puede solucionar esto con 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);
});

Sin embargo, para asegurarse de que scrollspy resalte el elemento actual correcto, aún necesita establecer el desplazamiento:

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

Aquí hay una demostración completa de JSFiddle .


Alternativamente, puede rellenar sus etiquetas de anclaje, como lo sugieren los trucos de 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

Creo que el desplazamiento podría hacer algo con la posición inferior de la sección.

Solucioné mi problema, el mismo que el suyo, agregando

  padding-top: 60px;

en la declaración para la sección en bootstrap.css

¡Espero que ayude!


¿Qué es una "declaración de sección" ¿Dónde pones este código?
ahnbizcad

1

Agregué un .vspaceelemento de 40px de altura sosteniendo el ancla antes de cada uno de mis h1elementos.

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

En el CSS:

.vspace { height: 40px;}

Está funcionando muy bien y el espacio no se está ahogando.


1

Bootstrap 4 (actualización de 2019)

Implementación: Navegación fija, Scrollspy y Desplazamiento suave

Esta es la solución de @ wilfred-hughes anterior, soluciona exactamente el problema de superposición con Bootstrap Fixed Navbar usando CSS ':: before' para anteponer un bloque no mostrado antes de cada etiqueta de sección. Ventaja: no terminas con un relleno innecesario entre tus secciones. Por ejemplo, la sección 3 se puede colocar verticalmente justo contra la sección 2 y aún se desplazará hasta la posición correcta exacta en la parte superior de la sección 3.

Nota al margen: establecer el desplazamiento de scrollspy en la etiqueta del script no provocó que sucediera nada ($ ('# navbar'). Scrollspy ({offset: 105});) y los intentos de ajustar el desplazamiento en el bloque de animación aún resultaron en una desalineación posterior. animación.

index.html

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

más adelante en 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;
}

Crédito: @ wilfred-hughes arriba y la fuente original del usuario @mnot en https://github.com/twbs/bootstrap/issues/1768


1
¡gracias! ugh, he estado luchando con esto durante una hora, ¡LOL!
Nexus

0

Tuve problemas con las soluciones de acjohnson55 y Kurt UXD. Ambos funcionaron para hacer clic en un enlace al hash, pero el desplazamiento de scrollspy aún no era correcto.

Se me ocurrió la siguiente solución:

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

Y el CSS correspondiente:

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;
  }
}

Deberá reemplazar el relleno / margen de 40px con la altura de su barra de navegación y la identificación de su ancla.

En esta configuración, incluso puedo observar un efecto de establecer un valor para el atributo de compensación de datos. Si encuentra valores grandes para el desplazamiento de datos alrededor de 100-200 conduce a un comportamiento más esperado (el scrollspy- "cambiar" sucederá si el encabezado está en el medio de la pantalla).

También encontré que scrollspy es muy sensible a errores como las etiquetas div sin cerrar (lo cual es bastante obvio), así que http://validator.w3.org/check era mi amigo aquí.

En mi opinión, scrollspy funciona mejor con secciones completas que llevan el ID de anclaje, ya que los elementos de ancla regulares no producen los efectos esperados cuando se desplaza hacia atrás (el scrollspy- "switch" eventualmente ocurre tan pronto como presiona el elemento de anclaje, por ejemplo, su encabezado, pero en ese momento ya se ha desplazado sobre el contenido que el usuario espera que pertenezca al título correspondiente).


0

Si tropezó con esta pregunta (como lo hice yo) a través de Google y aún está buscando una forma de cambiar dinámicamente el desplazamiento de scrollspy. Ahora adjunto un enlace a una solución que funcionó para mí.

Echa un vistazo a esta publicación que hice en otro hilo . Este contiene un fragmento de cómo puede cambiar mediante programación el valor de compensación y reaccionar dinámicamente a los cambios (por ejemplo, si la barra de navegación cambia de tamaño).

No necesita jugar con las correcciones de CSS, sino establecer el desplazamiento que necesita actualmente en función de ciertos eventos.


-1

También puede abrir bootstap-offset.jsy modificar

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

ahí.


1
El desplazamiento scrollspy no compensa el contenido, compensa la navegación.
markus

-1

Solo configure:

data-offset="200"

data-offsetes por defecto "50" y eso equivale a 10px, así que simplemente aumente data-offsety su problema estará resuelto.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.