web-dev-qa-db-fra.com

Faire en sorte que le lien d'ancrage atteigne quelques pixels au-dessus de l'endroit où il est lié

Je ne suis pas sûr de la meilleure façon de poser/chercher cette question:

Lorsque vous cliquez sur un lien d'ancrage, cela vous amène à cette section de la page avec la zone liée à maintenant en haut de la page. J'aimerais que le lien d'ancre m'envoie à cette partie de la page, mais j'aimerais un peu d'espace en haut. En tant que, je ne veux pas qu’il m’envoie à la partie liée au TRES TOP, je voudrais y avoir environ 100 pixels d’espace.

Est-ce que ça a du sens? Est-ce possible? 

Edité pour afficher le code - c'est juste une balise d'ancrage:

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

<p id="anchor">I should be 100px below where I currently am!</p>
90
damon
window.addEventListener("hashchange", function () {
    window.scrollTo(window.scrollX, window.scrollY - 100);
});

Cela permettra au navigateur de faire le travail de saut à l'ancre pour nous et nous utiliserons ensuite cette position pour compenser.

EDIT 1:

Comme l'a souligné @erb, cela ne fonctionne que si vous êtes sur la page alors que le hachage est modifié. Entrer la page avec un #something déjà dans l'URL ne fonctionne pas avec le code ci-dessus. Voici une autre version pour gérer cela:

// 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).

REMARQUE: Pour utiliser jQuery, vous pouvez simplement remplacer window.addEventListener par $(window).on dans les exemples. Merci @Neon.

EDIT 2:

Comme indiqué par quelques-uns, ce qui précède échouera si vous cliquez sur le même lien d'ancrage deux fois ou plus à la suite, car aucun événement hashchange ne force le décalage.

Cette solution est une version très légèrement modifiée de la suggestion de @Mave et utilise les sélecteurs jQuery pour plus de simplicité.

// 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 pour cet exemple est ici

113
Eric Olson

En travaillant uniquement avec css, vous pouvez ajouter un remplissage à l'élément ancré (comme dans une solution ci-dessus).

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

Je ne suis pas sûr que ce soit la meilleure solution dans tous les cas, mais cela fonctionne très bien pour moi. 

69
user3364768

Encore meilleure solution:

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

Positionnez simplement la balise <a> avec le positionnement absolu à l'intérieur d'un objet relativement positionné.

Fonctionne en entrant dans la page ou par un changement de hachage dans la page.

49
Thomas

Meilleure solution

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

Cela fonctionnera sans jQuery et lors du chargement de la page.

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

Pour créer un lien vers un élément, puis positionner cet élément à une distance arbitraire du haut de la page, en utilisant du CSS pur, vous devez utiliser padding-top, de cette manière, l'élément est toujours positionné en haut de la fenêtre, mais il semble, visiblement, être positionné à une certaine distance du haut du port, par exemple:

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

Démo de JS Fiddle .

Pour utiliser une approche JavaScript simple:

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

window.addEventListener('hashchange', addMargin);

Démo de JS Fiddle .

4
David Thomas

La réponse d'Eric est excellente, mais vous n'avez vraiment pas besoin de ce délai. Si vous utilisez jQuery, vous pouvez simplement attendre le chargement de la page. Donc, je suggère de changer le code pour:

// 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();
});

Cela nous débarrasse également de ce facteur arbitraire.

3
rppc

Cela devrait fonctionner:

    $(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;
    });
});

Il suffit de changer le .top-49 pour ce qui correspond à votre lien d'ancrage.

3
dMehta

Si vous utilisez des noms d'ancres explicites tels que,

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

alors en css vous pouvez simplement définir

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

Cela fonctionnera tant que vos balises d'ancrage HREF ne spécifient pas également un attribut NAME.

3
Mespr

essayez ce code, il a déjà une animation lisse lorsque vous cliquez sur le lien.

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

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

Je viens de trouver une solution facile pour moi-même .

HTML

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

CSS

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

La solution la plus simple:

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
Edalat Mojaveri

Une variante de la solution de Thomas: CSS élément> élément sélecteurs peut être pratique ici:

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 sur le lien déplacera la position de défilement à 100px au-dessus de l'endroit où l'élément avec une classe de paddedAnchor est positionné.

Pris en charge dans les navigateurs non-IE et dans IE à partir de la version 9. Pour la prise en charge sur IE 7 et 8, un <!DOCTYPE> doit être déclaré.

0
HondaGuy

J'ai juste le même problème. J'ai un profil de navigation pixed et je veux que l'angkor commence sous le nav. La solution de window.addEventListener... ne fonctionne pas pour moi car je règle ma page sur scroll-behavior:smooth, de sorte qu'elle règle l'offset à la place scroll jusqu'à l'angkor. setTimeout() fonctionne si le temps est écoulé pour faire défiler l'écran à la fin, mais que l'apparence ne soit pas satisfaisante ma solution a donc été d’ajouter un div absolu dans l’angkor, avec height:[the height of the nav] et bottom:100%. dans ce cas, cette division se termine dans la partie supérieure de l'élément angkor et commence à la position où vous souhaitez faire défiler l'angkor. Maintenant, tout ce que je fais est de définir le lien angkor vers ce div absolu et le travail accompli :)

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

Je sais que c'est un peu tard, mais j'ai trouvé quelque chose de très important à mettre dans votre code si vous utilisez Scrollspy de Bootstrap. ( http://getbootstrap.com/javascript/#scrollspy )

Cela me rendait fou pendant des heures.

Le décalage de l'espion de défilement DOIT correspondre à window.scrollY, sinon vous courez le risque de:

  1. Obtenir un effet de scintillement étrange lors du défilement
  2. Vous constaterez que lorsque vous cliquez sur les ancres, vous arrivez dans cette section, mais Scroll Spy suppose que vous êtes une section au-dessus. 

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

0
beefsupreme

Basé sur @Eric Olson solution modifiez simplement un peu pour inclure l'élément d'ancrage que je veux spécifiquement

// 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
Carlos A. Ortiz

Utiliser uniquement css et n'avoir aucun problème avec le contenu couvert et non cliquable auparavant (le point essentiel est le pointeur-événements: aucun):

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>
0
dantefff

je faisais face au même problème et j'ai résolu en utilisant le code suivant 

$(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();
    });
0
Umair Mehmood