Fai in modo che il collegamento di ancoraggio vada alcuni pixel sopra il punto a cui è collegato


124

Non sono sicuro del modo migliore per chiedere / cercare questa domanda:

Quando fai clic su un collegamento di ancoraggio, ti porta a quella sezione della pagina con l'area collegata ora nella MOLTO INIZIO della pagina. Vorrei che il collegamento di ancoraggio mi indirizzasse a quella parte della pagina, ma vorrei uno spazio in alto. Come in, non voglio che mi mandi alla parte collegata con esso al MOLTO SUPERIORE, vorrei circa 100 pixel di spazio lì.

Questo ha senso? È possibile?

Modificato per mostrare il codice - è solo un tag di ancoraggio:

<a href="#anchor">Click me!</a>

<p id="anchor">I should be 100px below where I currently am!</p>


Risposte:


157
window.addEventListener("hashchange", function () {
    window.scrollTo(window.scrollX, window.scrollY - 100);
});

Ciò consentirà al browser di eseguire il lavoro di saltare all'ancora per noi e quindi useremo quella posizione per spostarci.

MODIFICA 1:

Come è stato sottolineato da @erb, funziona solo se sei sulla pagina mentre l'hash è cambiato. L'accesso alla pagina con un #somethinggià nell'URL non funziona con il codice sopra. Ecco un'altra versione per gestirlo:

// The function actually applying the offset
function offsetAnchor() {
    if(location.hash.length !== 0) {
        window.scrollTo(window.scrollX, window.scrollY - 100);
    }
}

// This will capture hash changes while on the page
window.addEventListener("hashchange", offsetAnchor);

// This is here so that when you enter the page with a hash,
// it can provide the offset in that case too. Having a timeout
// seems necessary to allow the browser to jump to the anchor first.
window.setTimeout(offsetAnchor, 1); // The delay of 1 is arbitrary and may not always work right (although it did in my testing).

NOTA: per usare jQuery, puoi semplicemente sostituire window.addEventListenercon $(window).onnegli esempi. Grazie @Neon.

MODIFICA 2:

Come sottolineato da alcuni, quanto sopra fallirà se si fa clic sullo stesso collegamento di ancoraggio due o più volte di seguito perché non vi è alcun hashchangeevento per forzare l'offset.

Questa soluzione è una versione leggermente modificata del suggerimento di @Mave e utilizza i selettori jQuery per semplicità

// The function actually applying the offset
function offsetAnchor() {
  if (location.hash.length !== 0) {
    window.scrollTo(window.scrollX, window.scrollY - 100);
  }
}

// Captures click events of all <a> elements with href starting with #
$(document).on('click', 'a[href^="#"]', function(event) {
  // Click events are captured before hashchanges. Timeout
  // causes offsetAnchor to be called after the page jump.
  window.setTimeout(function() {
    offsetAnchor();
  }, 0);
});

// Set the offset when entering page with hash present in the url
window.setTimeout(offsetAnchor, 0);

JSFiddle per questo esempio è qui


1
Funziona solo quando l'utente è già sulla pagina, non ad esempio quando l'utente visita example.com/#anchorda example.com/about/.
erb

7
Grazie @erb. La domanda dell'OP non richiedeva quel caso, ma per aiutare gli altri ho aggiunto un'altra versione dell'implementazione.
Eric Olson

2
Manca ancora un piccolo dettaglio. Se fai clic su un'ancora, quindi scorri verso l'alto e fai nuovamente clic sulla stessa ancora, non vi è alcuna modifica hash, quindi non utilizzerà l'offset. Idee?
Teo Maragakis

Potresti andare per $('a[href^="#"]').on('click', function() { offsetAnchor(); });. In questo modo, se l' elemento hrefdi un aelemento inizia con a #, si chiama la stessa funzione.
Mave

2
Non c'è bisogno di jQuery - basta sostituire $(window).on("hashchange",conwindow.addEventListener("hashchange",
Neon

90

Lavorando solo con css puoi aggiungere un padding all'elemento ancorato (come in una soluzione sopra) Per evitare spazi bianchi non necessari puoi aggiungere un margine negativo della stessa altezza:

#anchor {
    padding-top: 50px;
    margin-top: -50px;
}

Non sono sicuro che questa sia la soluzione migliore in ogni caso, ma per me funziona bene.


3
se c'è un collegamento entro 50 px sopra di esso, potrebbe essere nascosto e reso non cliccabile credo
Andrew

@Andrew Questo non sembra essere un problema su IE10 o Chrome.
Barba

11
puoi fare lo stesso usando la position: relativeproprietà css. Quindi, sarebbe comeposition: relative; top: -50px;
Aleks Dorohovich

@AleksDorohovich - Puoi pubblicarla come risposta separata poiché è unica rispetto a quelle esistenti.
BSMP

La mia pagina è

64

Soluzione ancora migliore:

<p style="position:relative;">
    <a name="anchor" style="position:absolute; top:-100px;"></a>
    I should be 100px below where I currently am!
</p>

Basta posizionare il <a>tag con posizionamento assoluto all'interno di un oggetto posizionato relativamente.

Funziona quando si accede alla pagina o tramite una modifica hash all'interno della pagina.


4
Preferisco la tua soluzione perché non utilizza javascript. Grazie!
Rosario Russo

1
Non capisco questa risposta. Stai riferendo questo link all'oggetto o all'oggetto stesso?
CZorio

3
Molto utile con le barre di
navigazione

1
@CZorio Se ho capito bene, è (ingegnosamente) creare un elemento di ancoraggio (potrebbe essere qualcos'altro, come "span" invece di "a") e posizionarlo relativamente al di sotto, in modo che l'ancora con href="#anchor"dentro punti lì, invece di puntare <p>direttamente all'elemento. Ma un avvertimento: l'uso idinvece di namein HTML5, vedi: stackoverflow.com/questions/484719/html-anchors-with-name-or-id
Flen

1
Veramente una soluzione migliore :)
Bobby Axe

23

Ecco la risposta del 2020 per questo:

#anchor {
  scroll-margin-top: 100px;
}

Perché è ampiamente supportato !


1
Downvoted perché anche se questo sarebbe bello, NON è ampiamente supportato. Né opera mobile / mini, né browser safari / ios, nemmeno il primo Edge lo supporta completamente.
Beda Schmid,

1
Un po 'meno del 90% di tutti i browser (incluso iOS con scroll-snap-margin-top) dovrebbe essere sufficiente per rinunciare a una soluzione javascript, soprattutto se l'impatto dell'utente è solo lo scorrimento. Ma hey, downvote questo approccio prima che danneggi qualcuno.
user127091

Una risposta così semplice e funzionante. Raggiungerà il 100% del supporto (per i browser moderni) abbastanza presto.
Leonel Becerra,

17

Soluzione migliore

<span class="anchor" id="section1"></span>
<div class="section"></div>

<span class="anchor" id="section2"></span>
<div class="section"></div>

<span class="anchor" id="section3"></span>
<div class="section"></div>

<style>
.anchor{
  display: block;
  height: 115px; /*same height as header*/
  margin-top: -115px; /*same height as header*/
  visibility: hidden;
}
</style>

8
Perché questa è la soluzione migliore? Inoltre, è molto più utile fornire un certo livello di spiegazione / ragionamento con una risposta.
Phill Healey

Dato che stai comunque aggiungendo HTML per creare un'ancora, l'aggiunta di uno span non è molto diversa. Quindi aggiungendo solo un po 'di CSS riesci a risolvere questo problema senza guadagnare alcun bug; come potrebbero fare altre soluzioni.
Sondre

11

Funzionerà senza jQuery e al caricamento della pagina.

(function() {
    if (document.location.hash) {
        setTimeout(function() {
            window.scrollTo(window.scrollX, window.scrollY - 100);
        }, 10);
    }
})();

1
Funziona per me e ha il vantaggio rispetto al metodo css che si applica a tutte le posizioni hash su una pagina, in modo da non dover scrivere uno stile con ogni hash incluso e ricordarsi di modificare lo stile quando aggiungi un altro para con un nuovo hash. Consente inoltre di modellare l'obiettivo con un colore di sfondo senza che questo si estenda di 100 px (o qualsiasi altra cosa) sopra come nella risposta da @ user3364768, sebbene ci sia un modo per aggirare questo.
David

4

Per creare un collegamento a un elemento, quindi "posizionare" quell'elemento a una distanza arbitraria dalla parte superiore della pagina, utilizzando CSS puro, dovresti usare padding-top, in questo modo l'elemento è ancora posizionato nella parte superiore della finestra, ma sembra , visibilmente, essere posizionato a una certa distanza dalla sommità del view-port, ad esempio:

<a href="#link1">Link one</a>
<a href="#link2">Link two</a>

<div id="link1">
    The first.
</div>

<div id="link2">
    The second.
</div>

CSS:

div {
    /* just to force height, and window-scrolling to get to the elements.
       Irrelevant to the demo, really */
    margin-top: 1000px;
    height: 1000px;
}

#link2 {
    /* places the contents of the element 100px from the top of the view-port */
    padding-top: 100px;
}

Demo di JS Fiddle .

Per utilizzare un semplice approccio JavaScript:

function addMargin() {
    window.scrollTo(0, window.pageYOffset - 100);
}

window.addEventListener('hashchange', addMargin);

Demo di JS Fiddle .


1
L'unico problema è che ora spinge quel div effettivo più in basso nella pagina. Idealmente, il collegamento di ancoraggio dovrebbe scendere di 100 px in meno rispetto al normale. Sono disposto a utilizzare JS o jQuery se necessario per ottenere questo risultato.
damon

3
Questo non risolve il problema, aggiunge semplicemente uno spazio bianco prima dell'elemento.
XCS

user1925805: vedi la risposta aggiornata per una soluzione JavaScript. @Cristy: lo so , l'ho detto esplicitamente nella risposta stessa: l'elemento è ancora posizionato nella parte superiore della finestra, ma sembra, visibilmente, essere posizionato a una certa distanza dall'alto .
David dice di reintegrare Monica l'

La soluzione migliore e pulita con il tuo JS. Grazie per me funziona molto bene!
DanielaB67

Funziona solo con i cambi hash avvenuti all'interno della pagina. Ma l'uso è stato reindirizzato con ID, quindi non funziona
Rohan Khude

4

Questo dovrebbe funzionare:

    $(document).ready(function () {
    $('a').on('click', function (e) {
        // e.preventDefault();

        var target = this.hash,
            $target = $(target);

       $('html, body').stop().animate({
        'scrollTop': $target.offset().top-49
    }, 900, 'swing', function () {
    });

        console.log(window.location);

        return false;
    });
});

Basta cambiare il .top-49 in quello che si adatta al tuo link di ancoraggio.


3

Se utilizzi nomi di ancoraggio espliciti come,

<a name="sectionLink"></a>
<h1>Section<h1>

quindi in css puoi semplicemente impostare

A[name] {
    padding-top:100px;
}

Questo funzionerà finché i tag di ancoraggio HREF non specificano anche un attributo NAME


Grazie. Questa è l'unica soluzione da questo elenco che ha funzionato per me.
MikeyBunny,

3

La risposta di Eric è ottima, ma davvero non hai bisogno di quel timeout. Se stai usando jQuery, puoi semplicemente aspettare che la pagina venga caricata. Quindi suggerirei di cambiare il codice in:

// The function actually applying the offset
function offsetAnchor() {
    if (location.hash.length !== 0) {
        window.scrollTo(window.scrollX, window.scrollY - 100);
    }
}

// This will capture hash changes while on the page
$(window).on("hashchange", function () {
    offsetAnchor();
});

// Let the page finish loading.
$(document).ready(function() {
    offsetAnchor();
});

Questo ci fa anche sbarazzare di quel fattore arbitrario.


3

prova questo codice, ha già un'animazione fluida quando si fa clic sul collegamento.

$(document).on('click', 'a[href^="#"]', function (event) {
    event.preventDefault();

    $('html, body').animate({
        scrollTop: $($.attr(this, 'href')).offset().top - 100
    }, 500);
});

1

La soluzione più semplice:

CSS

#link {
    top:-120px; /* -(some pixels above) */
    position:relative;
    z-index:5;
}

HTML

<body>
    <a href="#link">Link</a>
    <div>
        <div id="link"></div> /*this div should placed inside a target div in the page*/
        text
        text
        text
    <div>
</body>

1

Una variante della soluzione di Thomas: i selettori CSS element> element possono essere utili qui:

CSS

.paddedAnchor{
  position: relative;
}
.paddedAnchor > a{
  position: absolute;
  top: -100px;
}

HTML

<a href="#myAnchor">Click Me!</a>

<span class="paddedAnchor"><a name="myAnchor"></a></span>

Un clic sul collegamento sposterà la posizione di scorrimento a 100 px sopra ogni punto in cui l'elemento con una classe di paddedAnchor .

Supportato nei browser non IE e in IE dalla versione 9. Per il supporto su IE 7 e 8, è <!DOCTYPE>necessario dichiarare a.


1

Ho appena trovato una soluzione facile per me stesso. Aveva un margine superiore di 15 px

HTML

<h2 id="Anchor">Anchor</h2>

CSS

h2{margin-top:-60px; padding-top:75px;}

1

Usando solo css e non avendo problemi con contenuti coperti e non cliccabili prima (il punto di questo è il pointer-events: nessuno):

CSS

.anchored::before {
    content: '';
    display: block;
    position: relative;
    width: 0;
    height: 100px;
    margin-top: -100px;
}

HTML

<a href="#anchor">Click me!</a>
<div style="pointer-events:none;">
<p id="anchor" class="anchored">I should be 100px below where I currently am!</p>
</div>

1

Metti questo con stile:

.hash_link_tag{margin-top: -50px; position: absolute;}

e usa questa classe in un divtag separato prima dei link, esempio:

<div class="hash_link_tag" id="link1"></div> 
<a href="#link1">Link1</a>

o usa questo codice php per il tag echo link:

function HashLinkTag($id)
{
    echo "<div id='$id' class='hash_link_tag'></div>";
}

0

So che è un po 'tardi, ma ho trovato qualcosa di molto importante da inserire nel tuo codice se stai usando Scrollspy di Bootstrap. ( http://getbootstrap.com/javascript/#scrollspy )

Questo mi stava facendo impazzire per ore.

L'offset per la spia di scorrimento DEVE corrispondere a window.scrollY altrimenti correrai il rischio di:

  1. Ottenere uno strano effetto di sfarfallio durante lo scorrimento
  2. Scoprirai che quando fai clic sulle ancore, atterrerai in quella sezione, ma la spia di scorrimento presumerà che tu sia una sezione sopra di essa.

 var body = $('body');
    body.scrollspy({
        'target': '#nav',
        'offset': 100 //this must match the window.scrollY below or you'll have a bad time mmkay
});

$(window).on("hashchange", function () {
        window.scrollTo(window.scrollX, window.scrollY - 100);
});


Solo js nello snippet? Non funzionerà in ogni caso

0

Basato sulla soluzione di @Eric Olson , modifica solo un po 'per includere l'elemento di ancoraggio che voglio specificamente

// Function that actually set offset
function offsetAnchor(e) {
    // location.hash.length different to 0 to ignore empty anchor (domain.me/page#)
    if (location.hash.length !== 0) {
        // Get the Y position of the element you want to go and place an offset
        window.scrollTo(0, $(e.target.hash).position().top - 150);
    }
}

// Catch the event with a time out to perform the offset function properly
$(document).on('click', 'a[href^="#"]', function (e) {
    window.setTimeout(function () {
        // Send event to get the target id later
        offsetAnchor(e);
    }, 10);
});

0

Ho solo lo stesso problema. Ho un pixel di navigazione postato e voglio che Angkor inizi sotto il navigatore. La soluzione window.addEventListener...per me non funziona perché ho impostato la mia pagina in scroll-behavior:smoothmodo tale da impostare l'offset invece di scorrere fino all'angkor. il setTimeout()lavoro se il tempo è a portata di mano per scorrere fino alla fine, ma non sembra ancora buono. quindi la mia soluzione è stata quella di aggiungere un div assoluto postulato in angkor, con height:[the height of the nav]e bottom:100%. in questo caso questo div terminava nella parte superiore dell'elemento angkor, e inizia nella posizione in cui devi scorrere l'angkor. ora tutto quello che faccio è impostare il collegamento angkor a questo div assoluto e il lavoro fatto :)

html,body{
    margin:0;
    padding:0;
    scroll-behavior:smooth;
}

nav {
    height:30px;
    width:100%;
    font-size:20pt;
    text-align:center;
    color:white;
    background-color:black;
    position:relative;
}

#my_nav{
    position:fixed;
    z-index:3;
}
#fixer_nav{
    position:static;
}

#angkor{
    position:absolute;
    bottom:100%;
    height:30px;
}
<nav id="my_nav"><a href="#angkor">fixed position nav<a/></nav>
<nav id="fixer_nav"></nav>

<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque nec lacus vel eros rutrum volutpat. Cras ultrices enim sit amet odio dictum, eget consectetur mi pellentesque. Sed mollis gravida nulla, eu euismod turpis efficitur id. Integer pretium posuere fringilla. Aenean laoreet, augue non pharetra elementum, lectus massa congue orci, a imperdiet neque enim ut dui. Praesent commodo orci bibendum leo suscipit viverra. Nunc fermentum semper eleifend. Pellentesque suscipit nulla aliquet, egestas lectus sed, egestas dui. Vivamus scelerisque maximus nibh, ac dignissim nunc tempor a. Praesent facilisis non lacus et aliquam. Proin ultricies lacus vitae nibh ullamcorper gravida. Proin elit arcu, convallis eget posuere quis, placerat id augue. Fusce ex risus, tempus nec orci vitae, feugiat faucibus quam. Integer risus metus, ornare et rhoncus vitae, accumsan a urna.
</p>

<nav><div id="angkor"></div>The angkor</nav>

<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque nec lacus vel eros rutrum volutpat. Cras ultrices enim sit amet odio dictum, eget consectetur mi pellentesque. Sed mollis gravida nulla, eu euismod turpis efficitur id. Integer pretium posuere fringilla. Aenean laoreet, augue non pharetra elementum, lectus massa congue orci, a imperdiet neque enim ut dui. Praesent commodo orci bibendum leo suscipit viverra. Nunc fermentum semper eleifend. Pellentesque suscipit nulla aliquet, egestas lectus sed, egestas dui. Vivamus scelerisque maximus nibh, ac dignissim nunc tempor a. Praesent facilisis non lacus et aliquam. Proin ultricies lacus vitae nibh ullamcorper gravida. Proin elit arcu, convallis eget posuere quis, placerat id augue. Fusce ex risus, tempus nec orci vitae, feugiat faucibus quam. Integer risus metus, ornare et rhoncus vitae, accumsan a urna.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque nec lacus vel eros rutrum volutpat. Cras ultrices enim sit amet odio dictum, eget consectetur mi pellentesque. Sed mollis gravida nulla, eu euismod turpis efficitur id. Integer pretium posuere fringilla. Aenean laoreet, augue non pharetra elementum, lectus massa congue orci, a imperdiet neque enim ut dui. Praesent commodo orci bibendum leo suscipit viverra. Nunc fermentum semper eleifend. Pellentesque suscipit nulla aliquet, egestas lectus sed, egestas dui. Vivamus scelerisque maximus nibh, ac dignissim nunc tempor a. Praesent facilisis non lacus et aliquam. Proin ultricies lacus vitae nibh ullamcorper gravida. Proin elit arcu, convallis eget posuere quis, placerat id augue. Fusce ex risus, tempus nec orci vitae, feugiat faucibus quam. Integer risus metus, ornare et rhoncus vitae, accumsan a urna.

</p>


0

stavo affrontando il problema simile e l'ho risolto utilizzando il seguente codice

$(document).on('click', 'a.page-scroll', function(event) {
        var $anchor = $(this);
        var desiredHeight = $(window).height() - 577;
        $('html, body').stop().animate({
            scrollTop: $($anchor.attr('href')).offset().top - desiredHeight
        }, 1500, 'easeInOutExpo');
        event.preventDefault();
    });

-1
<a href="#anchor">Click me!</a>

<div style="margin-top: -100px; padding-top: 100px;" id="anchor"></div>
<p>I should be 100px below where I currently am!</p>

4
Questa è essenzialmente la stessa risposta di questa . Se pubblichi le risposte a una vecchia domanda, prova ad aggiungere qualcosa di nuovo. Ad esempio, potresti descrivere perché funziona.
Artjom B.

1
Direi che qualsiasi risposta dovrebbe avere una sorta di descrizione del motivo per cui funziona. ;-)
Phill Healey
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.