1289 votes

décalage d'une ancre html pour s'adapter à un en-tête fixe

J'essaie de nettoyer la façon dont mes ancres fonctionnent. J'ai un en-tête qui est fixé en haut de la page. Ainsi, lorsqu'on crée un lien vers une ancre ailleurs dans la page, la page saute pour que l'ancre se trouve en haut de la page, laissant le contenu derrière l'en-tête fixe (j'espère que cela a un sens). J'ai besoin d'un moyen de décaler l'ancre de 25px par rapport à la hauteur de l'en-tête. Je préférerais du HTML ou du CSS, mais du Javascript serait également acceptable.

1 votes

Le div wrapper présenté dans stackoverflow.com/questions/1431639/ est bien, je pense, pas trop agressif.

37 votes

Il existe un bel article sur ce sujet : css-tricks.com/hash-tag-links-padding

1 votes

1338voto

Jan Points 2409

Vous pourriez simplement utiliser le CSS sans aucun javascript.

Donnez une classe à votre ancre :

<a class="anchor" id="top"></a>

Vous pouvez ensuite positionner l'ancre un peu plus haut ou plus bas que là où elle apparaît réellement sur la page, en en faisant un élément de bloc et en la positionnant de manière relative. -250px positionnera l'ancre plus haut de 250px

a.anchor {
    display: block;
    position: relative;
    top: -250px;
    visibility: hidden;
}

13 votes

Cette réponse est la meilleure, car elle ne dépend pas d'un élément parent dont la position est définie comme relative. Merci d'avoir publié cet article.

2 votes

Je conseillerais aux autres d'utiliser cette balise plutôt que la balise span. Si vous devez ajouter des balises, autant en faire une balise d'ancrage traditionnelle.

85 votes

J'adore votre solution ! Elle semble ne pas fonctionner avec IE7. De toute façon, je prévois d'ignorer les utilisateurs d'IE7 à partir de maintenant...

394voto

Alexander Savin Points 1435

J'ai trouvé cette solution :

<a name="myanchor">
    <h1 style="padding-top: 40px; margin-top: -40px;">My anchor</h1>
</a>

Cela ne crée aucun vide dans le contenu et les liens d'ancrage fonctionnent très bien.

6 votes

Ça a bien marché. J'ai créé une classe d'ancrage CSS spéciale et je l'ai simplement attachée à mes ancres : <a class="anchor" name="foo"></a>. Merci.

2 votes

Il y a toujours un problème avec l'indicateur dans le nav. ainsi, si vous faites défiler la page vers le bas, l'élément actif du nav ne change pas tant que vous n'avez pas dépassé la cible de l'ancre.

38 votes

L'élément situé juste au-dessus de <h1> ne sera pas cliquable, en raison de la marge cachée. J'ai fini par utiliser la solution jQuery de Ian Clack, qui fonctionne très bien.

211voto

Hrvoje Miljak Points 729

Je cherchais également une solution à ce problème. Dans mon cas, c'était assez facile.

J'ai un menu de liste avec tous les liens :

<ul>
<li><a href="#one">one</a></li>
<li><a href="#two">two</a></li>
<li><a href="#three">three</a></li>
<li><a href="#four">four</a></li>
</ul>

Et en dessous, les rubriques où il faut aller.

<h3>one</h3>
<p>text here</p>

<h3>two</h3>
<p>text here</p>

<h3>three</h3>
<p>text here</p>

<h3>four</h3>
<p>text here</p>

Maintenant, parce que j'ai un menu fixe en haut de ma page, je ne peux pas le faire aller vers ma balise car elle serait derrière le menu.

Au lieu de cela, j'ai mis une balise span à l'intérieur de ma balise avec l'id approprié.

<h3><span id="one"></span>one</h3>

Utilisez maintenant 2 lignes de CSS pour les positionner correctement.

h3{ position:relative; }
h3 span{ position:absolute; top:-200px;}

Modifiez la valeur du haut pour qu'elle corresponde à la hauteur de votre en-tête fixe (ou plus). Je suppose que cela fonctionnerait également avec d'autres éléments.

7 votes

Cela devrait être coché à coup sûr.

4 votes

J'aime cette solution

3 votes

span pourrait être remplacé par un a

181voto

Ian Clark Points 4060

Comme il s'agit d'un souci de présentation, une solution purement CSS serait idéale. Cependant, cette question a été posée en 2012, et bien que des solutions de positionnement relatif / marge négative aient été suggérées, ces approches semblent plutôt bricolées, créent des problèmes potentiels de flux, et ne peuvent pas répondre dynamiquement aux changements dans le DOM / viewport.

En gardant cela à l'esprit, je pense que l'utilisation de JavaScript est toujours (février 2017) la meilleure approche. Voici une solution vanilla-JS qui répondra à la fois aux clics des ancres et résoudra le hachage de la page au chargement. (Voir JSFiddle) . Modifiez le .getFixedOffset() si des calculs dynamiques sont nécessaires. Si vous utilisez jQuery, voici une solution modifiée avec une meilleure délégation des événements et un défilement fluide .

(function(document, history, location) {
  var HISTORY_SUPPORT = !!(history && history.pushState);

  var anchorScrolls = {
    ANCHOR_REGEX: /^#[^ ]+$/,
    OFFSET_HEIGHT_PX: 50,

    /**
     * Establish events, and fix initial scroll position if a hash is provided.
     */
    init: function() {
      this.scrollToCurrent();
      window.addEventListener('hashchange', this.scrollToCurrent.bind(this));
      document.body.addEventListener('click', this.delegateAnchors.bind(this));
    },

    /**
     * Return the offset amount to deduct from the normal scroll position.
     * Modify as appropriate to allow for dynamic calculations
     */
    getFixedOffset: function() {
      return this.OFFSET_HEIGHT_PX;
    },

    /**
     * If the provided href is an anchor which resolves to an element on the
     * page, scroll to it.
     * @param  {String} href
     * @return {Boolean} - Was the href an anchor.
     */
    scrollIfAnchor: function(href, pushToHistory) {
      var match, rect, anchorOffset;

      if(!this.ANCHOR_REGEX.test(href)) {
        return false;
      }

      match = document.getElementById(href.slice(1));

      if(match) {
        rect = match.getBoundingClientRect();
        anchorOffset = window.pageYOffset + rect.top - this.getFixedOffset();
        window.scrollTo(window.pageXOffset, anchorOffset);

        // Add the state to history as-per normal anchor links
        if(HISTORY_SUPPORT && pushToHistory) {
          history.pushState({}, document.title, location.pathname + href);
        }
      }

      return !!match;
    },

    /**
     * Attempt to scroll to the current location's hash.
     */
    scrollToCurrent: function() {
      this.scrollIfAnchor(window.location.hash);
    },

    /**
     * If the click event's target was an anchor, fix the scroll position.
     */
    delegateAnchors: function(e) {
      var elem = e.target;

      if(
        elem.nodeName === 'A' &&
        this.scrollIfAnchor(elem.getAttribute('href'), true)
      ) {
        e.preventDefault();
      }
    }
  };

  window.addEventListener(
    'DOMContentLoaded', anchorScrolls.init.bind(anchorScrolls)
  );
})(window.document, window.history, window.location);

3 votes

Fonctionne parfaitement, mais pour jquery 1.7+, utilisez $("a").on("click",... au lieu de $("a").live("click",...

4 votes

Bon commentaire, je vais mettre à jour :) - BTW il devrait aussi être $("body").on("click", "a"... car il peut avoir besoin de fonctionner pour les ancres qui sont ajoutées dans le document par des scripts (c'est pourquoi j'utilisais la fonction .live )

0 votes

+1 : dans une solution purement CSS, les éléments situés au-dessus ne sont pas cliquables (par exemple, lorsqu'une barre de navigation latérale se déplace vers le haut pour les petits écrans).

89voto

Ziav Points 836

Solution purement css inspirée par Alexander Savin :

a[name] {
  padding-top: 40px;
  margin-top: -40px;
  display: inline-block; /* required for webkit browsers */
}

En option, vous pouvez ajouter ce qui suit si la cible est toujours hors de l'écran :

  vertical-align: top;

6 votes

Je viens d'essayer sur Chrome et l'affichage inline-block n'était pas nécessaire.

2 votes

Asrail Pour moi, ça n'a pas marché sans lui.

1 votes

Pour moi, "display : inline-block ;" n'a pas du tout fonctionné dans Chrome (tous les liens sont devenus impossibles à cliquer).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X