Come imposto l'offset per ScrollSpy in Bootstrap?


98

Ho un sito con la barra di navigazione fissata in alto e 3 div sotto nell'area del contenuto principale.

Sto cercando di usare scrollspy dal framework bootstrap.

Ho evidenziato con successo le diverse intestazioni nel menu quando scorri oltre i div.

Ce l'ho anche così quando fai clic sul menu, scorrerà fino alla parte corretta della pagina. Tuttavia, l'offset non è corretto (non tiene conto della barra di navigazione, quindi devo compensare di circa 40 pixel)

Vedo nella pagina Bootstrap che menziona un'opzione di offset ma non sono sicuro di come usarla.

Non sono nemmeno quello che significa quando dice che puoi usare scrollspy con $('#navbar').scrollspy(), non sono sicuro di dove includerlo, quindi non l'ho fatto e tutto sembra funzionare (tranne l'offset).

Ho pensato che l'offset potrebbe essere l' data-offset='10'etichetta sul corpo, ma non fa nulla per me.

Ho la sensazione che questo sia qualcosa di veramente ovvio e mi manca solo. Qualsiasi aiuto?

Il mio codice è

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

Perché stai dando una posizione: relativa ai tuoi div? Forse è questo che sta causando questo. Puoi creare un jsfiddle con il tuo codice in modo che possiamo vedere in azione?
periklis

Risposte:


113

Bootstrap utilizza l'offset per risolvere solo lo spionaggio, non lo scorrimento. Ciò significa che lo scorrimento nella posizione corretta dipende da te.

Prova questo, per me funziona: aggiungi un gestore di eventi per i clic di navigazione.

var offset = 80;

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

L'ho trovato qui: https://github.com/twitter/bootstrap/issues/3316


3
Grazie per la risposta. Mi ci è voluto un po 'per rendermi conto che l'offset non influisce sullo scorrimento. Ciò significa che chiunque utilizzi un piano fisso deve regolare manualmente in questo modo.
Brian Smith

8
Per aggiornare in modo appropriato la sezione hash dell'URL, aggiungere window.location.hash = $(this).attr('href')a questa funzione.
Stephen M. Harris

2
Grazie! FWIW, anche l'inserimento dell'offset dei dati nel corpo è importante, poiché il richiedente dice che non fa nulla, ma è necessario per una corretta spionaggio. Potrebbe essere utile avere una risposta esauriente.
mrooney

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

78

Il trucco, come alludeva Tim, è sfruttare l'imbottitura. Quindi il problema è che il tuo browser vuole sempre far scorrere l'ancora fino alla parte superiore esatta della finestra. se imposti l'ancora dove inizia effettivamente il testo, verrà occluso dalla barra dei menu. Invece, quello che fai è impostare il tuo ancoraggio sull'ID del contenitore <section>o del <div>tag, che nav / navbar utilizzerà automaticamente. Quindi devi impostare il tuo padding-topper il contenitore sull'offset dell'importo che desideri e il margin-topper il contenitore al contrario di padding-top. Ora il blocco del contenitore e l'ancora iniziano nella parte superiore esatta della pagina, ma il contenuto all'interno non inizia fino a sotto la barra dei menu.

Se stai usando ancore regolari, puoi ottenere la stessa cosa usando il margine superiore negativo nel tuo contenitore come sopra, ma senza imbottitura. Quindi metti <a target="...">un'ancora regolare come primo figlio del contenitore. Quindi modifichi il secondo elemento figlio con un opposto ma uguale margin-top, ma usando il selettore .container:first-child +.

Tutto ciò presume che il tuo <body>tag abbia già il margine impostato per iniziare sotto l'intestazione, che è la norma (altrimenti la pagina verrebbe visualizzata con testo occluso immediatamente).

Ecco un esempio di questo in azione. Qualsiasi cosa sulla tua pagina con un ID può essere collegata inserendo # the-elements-id alla fine del tuo URL. Se crei tutti i tuoi tag h e tag dt con id collegabili ( come fa GitHub ) con una sorta di script che inietta un piccolo link alla loro sinistra ; aggiungendo quanto segue al tuo CSS si occuperà dell'offset della barra di navigazione per te:

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
Adoro la combinazione padding-top, margine negativo-bottom (sullo stesso elemento). Più facile quindi scherzare con js.
Eystein

Sembra la risposta migliore, ma sono un po 'perso. Ogni possibilità di un esempio.
eddyparkinson

@eddyparkinson, immagino tu l'abbia capito adesso: Esempio, quando hai i tuoi ID sulle righe di bootstrap: .row [id] {padding-top: 60px; margin-top: -40px; } Mettilo nel tuo file less: .row [id] {padding-top: 60px; margin-top: -40px; }
Klaaz

Il parametro di offset predefinito del bootstrap non dovrebbe essere per questo? È una cosa così ovvia da includere e non è necessario ricorrere a soluzioni alternative come questa.
ahnbizcad

Questo aggiunge effettivamente spazio extra sul div che stai prendendo di mira? E se non lo volessi? Una spaziatura extra invisibile sarebbe l'ideale.
ahnbizcad

10

Puoi cambiare l'offset di scrollspy al volo con questo (supponendo che tu stia spiando il corpo):

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

Funziona anche se è necessario modificare dinamicamente il valore di offset. (Mi piace che lo scrollspy cambi quando la sezione successiva è circa a metà della finestra, quindi ho bisogno di cambiare l'offset durante il ridimensionamento della finestra.)


2
Grazie per questo - funziona alla grande con un piccolo aggiustamento per Bootstrap 3.0 $ ('body'). Data () ['bs.scrollspy']. Options.offset = newOffset; // Imposta il nuovo offset $ ('body'). Data () ['bs.scrollspy']. Process (); // Forza scrollspy a ricalcolare gli offset per i tuoi obiettivi $ ('body'). Scrollspy ('refresh'); // Aggiorna lo scrollspy.
Sam

Ho scoperto che questo metodo è buono, ma che se voglio usarlo per impostare l'offset dall'inizio a causa di altezze di menu diverse, $ ('body'). Data (). Scrollspy.options.offset (o la variante per la versione 3.0) non è ancora impostata. C'è qualcosa di asincrono in scrollspy che mi manca?
ness-EE

A partire da Bootstrap 3.1.1 questo dovrebbe essere $('body').data()['bs.scrollspy'].options.offset. Utile per attivare lo scrollspy al caricamento della pagina utilizzandowindow.scrollBy(X,Y)
Meredith

8

Se vuoi un offset di 10, metteresti questo nella tua testa:

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

Il tuo tag body sarebbe simile a questo:

<body data-spy="scroll">

6
Ciò non compensa il contenuto, compensa la navigazione.
markus

Questo funzionerà per evidenziare l'elemento di navigazione corretto e non la posizione in cui conduce il clic (che è la domanda originale dei poster). Detto questo, questo era quello che stavo cercando! Grazie!
valin077

6

Dal numero di bootstrap n. 3316 :

[Questo] ha il solo scopo di modificare i calcoli di scorrimento - non spostiamo il clic di ancoraggio effettivo

Quindi l'impostazione dell'offset ha effetto solo dove scrollspy pensa che la pagina sia stata fatta scorrere . Non influisce sullo scorrimento quando fai clic su un tag di ancoraggio.

L'utilizzo di una barra di navigazione fissa significa che il browser sta scorrendo nella posizione sbagliata. Puoi risolvere questo problema 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);
});

Tuttavia, per garantire che scrollspy evidenzi l'elemento corrente corretto, è comunque necessario impostare l'offset:

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

Ecco una demo completa su JSFiddle .


In alternativa, puoi riempire i tuoi tag di ancoraggio, come suggerito dai trucchi 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

Penso che l'offset potrebbe fare qualcosa con la posizione inferiore della sezione.

Ho risolto il mio problema, lo stesso del tuo, aggiungendo

  padding-top: 60px;

nella dichiarazione per la sezione in bootstrap.css

Spero che aiuti!


che cos'è una "dichiarazione per sezione" Dove metti questo codice?
ahnbizcad

1

Ho aggiunto un .vspaceelemento di 40px di altezza che tiene l'ancora prima di ciascuno dei miei h1elementi.

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

Nel CSS:

.vspace { height: 40px;}

Funziona alla grande e lo spazio non è soffocante.


1

Bootstrap 4 (aggiornamento 2019)

Implementazione: Fixed Nav, Scrollspy e Smooth Scrolling

Questa è la soluzione di @ wilfred-hughes sopra, risolve esattamente il problema di sovrapposizione con Bootstrap Fixed Navbar utilizzando CSS ":: before" per anteporre un blocco non visualizzato prima di ogni tag di sezione. Vantaggio: non ti ritroverai con imbottiture inutili tra le sezioni. Ad esempio, la sezione 3 può essere posizionata verticalmente contro la sezione 2 e continuerà a scorrere fino alla posizione esatta esatta nella parte superiore della sezione 3.

Nota a margine: l'impostazione dell'offset dello scrollspy nel tag dello script non faceva accadere nulla ($ ('# navbar'). Scrollspy ({offset: 105});) e i tentativi di regolare l'offset nel blocco dell'animazione hanno comunque provocato un disallineamento post- animazione.

index.html

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

più avanti in 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;
}

Credito: @ wilfred-hughes sopra e la fonte originale dell'utente @mnot su https://github.com/twbs/bootstrap/issues/1768


1
grazie! ugh ho lottato con questo per un'ora, LOL!
Nexus

0

Ho avuto problemi con le soluzioni di acjohnson55 e Kurt UXD. Entrambi funzionavano per fare clic su un collegamento all'hash, ma l'offset scrollspy non era ancora corretto.

Ho trovato la seguente soluzione:

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

E il CSS corrispondente:

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

Dovrai sostituire il riempimento / margine di 40px con l'altezza della barra di navigazione e l'ID della tua ancora.

In questa configurazione posso anche osservare un effetto dell'impostazione di un valore per l'attributo data-offset. Se trovare valori grandi per il data-offset intorno a 100-200 porta ad un comportamento più atteso (lo scrollspy- "switch" avverrà se l'intestazione è circa al centro dello schermo).

Ho anche scoperto che scrollspy è molto sensibile agli errori come i tag div non chiusi (il che è abbastanza ovvio), quindi http://validator.w3.org/check era mio amico qui.

Secondo me scrollspy funziona meglio con intere sezioni che portano l'ID di ancoraggio, poiché i normali elementi di ancoraggio non portano agli effetti previsti quando si scorre all'indietro (lo scrollspy- "interruttore" alla fine si verifica non appena si preme l'elemento di ancoraggio, ad esempio la propria intestazione, ma in quel momento hai già fatto scorrere il contenuto che l'utente si aspetta appartenga alla relativa intestazione).


0

Se ti sei imbattuto in questa domanda (come ho fatto io) tramite Google e stai ancora cercando un modo per modificare dinamicamente l'offset di scrollspy. Ora sto allegando un collegamento a una soluzione che ha funzionato per me.

Dai un'occhiata a questo post che ho fatto in un altro thread . Contiene uno snippet su come modificare programmaticamente il valore di offset e reagire dinamicamente alle modifiche (ad esempio se la barra di navigazione cambia di dimensione).

Non è necessario armeggiare con le correzioni CSS, ma piuttosto impostare l'offset attualmente necessario in base a determinati eventi.


-1

Puoi anche aprire bootstap-offset.jse modificare

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

Là.


1
L'offset scrollspy non compensa il contenuto, compensa la navigazione.
markus

-1

Basta impostare:

data-offset="200"

data-offsetè di default "50" e questo è equivalente a 10px, quindi aumenta data-offsete il tuo problema è risolto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.