L'en-tête de page fixe chevauche les points d'ancrage de la page

si j'ai un en-tête non-défilant dans une page HTML, fixe au haut, ayant une hauteur définie:

y a-t-il un moyen d'utiliser L'ancre URL (la partie #fragment ) pour faire défiler le navigateur vers un certain point de la page, tout en respectant la hauteur de l'élément fixe sans L'aide de JavaScript ?

http://foo.com/#bar
WRONG (but the common behavior):         CORRECT:
+---------------------------------+      +---------------------------------+
| BAR///////////////////// header |      | //////////////////////// header |
+---------------------------------+      +---------------------------------+
| Here is the rest of the Text    |      | BAR                             |
| ...                             |      |                                 |
| ...                             |      | Here is the rest of the Text    |
| ...                             |      | ...                             |
+---------------------------------+      +---------------------------------+
234
demandé sur Marco Bonelli 2010-11-03 13:31:11

26 réponses

j'ai eu le même problème. Je l'ai résolu en ajoutant une classe à l'élément d'ancrage avec la hauteur de la barre supérieure comme valeur supérieure de rembourrage.

<h1><a class="anchor" name="barlink">Bar</a></h1>

et puis simplement le css:

.anchor { padding-top: 90px; }
112
répondu MutttenXd 2015-08-15 18:13:55

si vous ne pouvez pas ou ne voulez pas définir une nouvelle classe, ajouter une hauteur fixe ::before pseudo-élément à la :target pseudo-classe dans CSS:

:target::before {
  content: "";
  display: block;
  height: 60px; /* fixed header height*/
  margin: -60px 0 0; /* negative fixed header height */
}

ou faites défiler la page relative à :target avec jQuery:

var offset = $(':target').offset();
var scrollto = offset.top - 60; // minus fixed header height
$('html, body').animate({scrollTop:scrollto}, 0);
154
répondu Adrian Garner 2018-07-31 16:50:43

j'utilise cette approche:

/* add class="jumptarget" to all targets. */

.jumptarget::before {
  content:"";
  display:block;
  height:50px; /* fixed header height*/
  margin:-50px 0 0; /* negative fixed header height */
}

ajoute un élément invisible devant chaque cible. Il fonctionne IE8+.

voici plus de solutions: http://nicolasgallagher.com/jump-links-and-viewport-positioning /

111
répondu Jerry 2016-01-06 03:54:30

Réponse Officielle De Bootstrap:

*[id]:before { 
  display: block; 
  content: " "; 
  margin-top: -75px; // Set the Appropriate Height
  height: 75px; // Set the Appropriate Height
  visibility: hidden; 
}

crédits

Fusion

29
répondu blnc 2016-06-29 18:01:20

le meilleur moyen que j'ai trouvé pour traiter ce problème est (Remplacer 65px avec votre hauteur d'élément fixe):

div:target {
  padding-top: 65px; 
  margin-top: -65px;
}

Si vous n'aimez pas utiliser le cible sélecteur vous pouvez aussi le faire de cette façon:

.my-target {
    padding-top: 65px;
    margin-top: -65px;
}

Note: Cet exemple ne fonctionnera pas si l'élément cible a une couleur de fond qui diffère de son parent. par exemple:

<div style="background-color:red;height:100px;"></div>
<div class="my-target" style="background-color:green;height:100px;"></div>

dans ce cas la couleur verte de l'élément my-target écrasera l'élément rouge parent en 65px. Je n'ai pas trouvé de solution CSS pure pour traiter cette question, mais si vous n'avez pas une autre couleur de fond, cette solution est la meilleure.

23
répondu Roy Shoa 2015-12-07 11:11:12

alors que certaines des solutions proposées fonctionnent pour des liens de fragment (= liens de hachage) dans la même page (comme un lien de menu qui défile vers le bas), j'ai constaté qu'aucun d'eux ne fonctionne dans le Chrome actuel quand vous voulez utiliser des liens de fragment venant dans d'autres pages .

So calling www.mydomain.com/page.html#foo à partir de zéro sera pas offset votre cible dans Chrome actuel avec l'un des CSS donnés solutions ou JS solutions.

il y a aussi un rapport de bogue de jQuery qui décrit certains détails du problème.

SOLUTION

la seule option que j'ai trouvée jusqu'à présent qui fonctionne vraiment dans Chrome est JavaScript qui n'est pas appelé onDomReady mais avec un retard.

// set timeout onDomReady
$(function() {
    setTimeout(delayedFragmentTargetOffset, 500);
});

// add scroll offset to fragment target (if there is one)
function delayedFragmentTargetOffset(){
    var offset = $(':target').offset();
    if(offset){
        var scrollto = offset.top - 95; // minus fixed header height
        $('html, body').animate({scrollTop:scrollto}, 0);
    }
}

résumé

sans solution de retard JS va probablement travailler dans Firefox, IE, Safari, mais pas dans le Chrome.

12
répondu Jpsy 2016-02-17 16:22:14

pour Chrome / Safari / Firefox vous pouvez ajouter un display: block et utiliser une marge négative pour compenser l'offset, comme:

a[name] {
    display: block;
    padding-top: 90px;
    margin-top: -90px;
}

Voir exemple http://codepen.io/swed/pen/RrZBJo

8
répondu MrSwed 2016-05-21 12:11:11

vous pouvez le faire avec jQuery:

var offset = $('.target').offset();
var scrollto = offset.top - 50; // fixed_top_bar_height = 50px
$('html, body').animate({scrollTop:scrollto}, 0);
6
répondu webvitaly 2012-05-29 10:25:19

Ça marche pour moi:

Lien HTML vers Anchor:

<a href="#security">SECURITY</a>

ancre HTML:

<a name="security" class="anchor"></a>

CSS:

.anchor::before {
    content: "";
    display: block;
    margin-top: -50px;
    position: absolute;
}
5
répondu avila 2017-05-28 21:49:46

vous pourriez essayer ceci:

<style>
h1:target { padding-top: 50px; }
</style>

<a href="#bar">Go to bar</a>

<h1 id="bar">Bar</h1>

définissez la valeur de remplissage supérieure à la hauteur réelle de votre en-tête. Cela va introduire un léger supplément d'avance au sommet de votre tête, mais il ne sera visible que lorsque l'utilisateur passe à l'ancre, puis défiler vers le haut. J'ai composé cette solution pour mon site dès maintenant, mais il n'affiche une petite barre fixe en haut de la page, rien de trop haut.

4
répondu ygoe 2012-02-29 21:06:02

Je l'ai fait fonctionner facilement avec CSS et HTML, en utilisant la méthode" anchor:before " mentionnée ci-dessus. Je pense que ça marche le mieux, parce que ça ne crée pas de rembourrage massif entre vos divs.

.anchor:before {
  content:"";
  display:block;
  height:60px; /* fixed header height*/
  margin:-60px 0 0; /* negative fixed header height */
}

il ne semble pas fonctionner pour la première div sur la page, mais vous pouvez contrer cela en ajoutant du rembourrage à cette première div.

#anchor-one{padding-top: 60px;}

voici un violon de travail: http://jsfiddle.net/FRpHE/24/

4
répondu Eric Wood 2013-09-25 20:46:54

cela me semble un peu ringard pour mon esprit puriste, mais comme solution uniquement css vous pouvez ajouter du rembourrage à l'élément actif ancré en utilisant le sélecteur :target :

html, body {height:100%; min-height:100%; margin:0;}
body {min-height:200%;}
header {display:inline-block; position:fixed; font-size:1.5em; height:100px; top:0; left:0; right:0; line-height:100px; background:black; text-align:center;}
header a {color:#fff;}
section {padding:30px; margin:20px;}
section:first-of-type, section:target {padding-top:130px;}
<header><a href="#one">#One</a> <a href="#two">#two</a> <a href="#three">#three</a></header>
<section id="one"><h1>One</h1>Aenean lacinia bibendum nulla sed consectetur. Nullam id dolor id nibh ultricies vehicula ut id elit. Integer posuere erat a ante venenatis dapibus posuere velit aliquet.</section>
<section id="two"><h1>Two</h1>Aenean lacinia bibendum nulla sed consectetur. Nullam id dolor id nibh ultricies vehicula ut id elit. Integer posuere erat a ante venenatis dapibus posuere velit aliquet.</section>
<section id="three"><h1>Three</h1>Aenean lacinia bibendum nulla sed consectetur. Nullam id dolor id nibh ultricies vehicula ut id elit. Integer posuere erat a ante venenatis dapibus posuere velit aliquet.</section>
3
répondu Moob 2016-04-26 16:02:00

la façon dont je trouve être le plus propre est la suivante:

  #bar::before {
    display: block;
    content: " ";
    margin-top: -150px;
    height: 150px;
    visibility: hidden;
    pointer-events: none;
  }
3
répondu Guillaume Le Mière 2018-04-29 00:17:45

j'ai eu beaucoup de mal avec beaucoup de réponses ici et ailleurs car mes ancres avec un signet étaient des en-têtes de section dans une page FAQ, donc compenser l'en-tête n'a pas aidé car le reste du contenu serait simplement rester où il était. Donc je pensais que je poste.

ce que j'ai fini par faire était un composite de quelques solutions:

  1. Le CSS:

    .bookmark { margin-top:-120px; padding-bottom:120px; display:block; }

où "120px" est votre hauteur d'en-tête fixe (peut-être plus une marge).

  1. Le lien de signet HTML:

    <a href="#01">What is your FAQ question again?</a>

  2. référencé le contenu HTML:

    <span class="bookmark" id="01"></span> <h3>What is your FAQ question again?</h3> <p>Some FAQ text, followed by ...</p> <p>... some more FAQ text, etc ...</p>

la bonne chose à propos de cette solution est que l'élément span n'est pas seulement caché, il est essentiellement effondré et n'encombrez pas votre contenu.

Je ne peux pas prendre beaucoup de crédit pour cette solution car il vient d'un mélange de différentes ressources, mais il a fonctionné le mieux pour moi dans ma situation.

Vous pouvez voir le résultat réel ici .

3
répondu SteveCinq 2018-07-23 05:43:01

j'ai trouvé que je devais utiliser à la fois MutttenXd 's et Badabam 's solutions CSS ensemble, comme le premier ne fonctionne pas dans le Chrome et le second ne fonctionne pas dans Firefox:

a.anchor { 
  padding-top: 90px;
}

a.anchor:before { 
  display: block;
  content: "";
  height: 90px;
  margin-top: -90px;
}

<a class="anchor" name="shipping"></a><h2>Shipping (United States)</h2>
...
2
répondu tshalif 2016-05-24 00:12:14

j'utilise la réponse de @Jpsy, mais pour des raisons de performance Je ne règle le minuteur que si le hachage est présent dans l'URL.

$(function() {
      // Only set the timer if you have a hash
      if(window.location.hash) {
        setTimeout(delayedFragmentTargetOffset, 500);
      }
  });

function delayedFragmentTargetOffset(){
      var offset = $(':target').offset();
      if(offset){
          var scrollto = offset.top - 80; // minus fixed header height
          $('html, body').animate({scrollTop:scrollto}, 0);
          $(':target').highlight();
      }
  };
2
répondu sandre89 2016-07-20 02:46:33

Un peu intrusif approche à l'aide de jQuery:

Link:

<a href="#my-anchor-1" class="anchor-link">Go To Anchor 1</a>

Contenu:

<h3 id="my-anchor-1">Here is Anchor 1</a>

Script:

$(".anchor-link").click(function() {
    var headerHeight = 120;
    $('html, body').stop(true, true).animate({
        scrollTop: $(this.hash).offset().top - headerHeight
    }, 750);
    return false;
});

en assignant la classe anchor-link aux links, le comportement des autres links (comme les commandes accordéon ou tab) n'est pas affecté.

la question ne veut pas javascript mais l'autre question plus populaire est fermé à cause de cela, et je ne pouvais pas répondre.

2
répondu Hüseyin Yağlı 2018-04-18 12:35:29
<div style="position:relative; top:-45px;">
    <a name="fragment"> </a>
</div>

Ce code devrait faire l'affaire. Échanger 45px pour la hauteur de votre barre d'en-tête.

EDIT: si utiliser jQuery est une option, j'ai aussi réussi à utiliser jQuery.localScroll avec un jeu de valeurs offset. L'option offset fait partie de jQuery.scrollTo, qui jQuery.localScroll est construite. Une démo est disponible ici: http://demos.flesler.com/jquery/scrollTo / (deuxième fenêtre, sous "offset")

1
répondu fourk 2011-09-23 22:07:09

Voici une solution complète de jquery qui fonctionnera dans IE:

supposons que les éléments de la barre de navigation sont quelque chose comme ceci:

<ul>
    <li><a class="navigation" href="/#contact-us">Contact us</a></li>
    <li><a class="navigation" href="/#about-us">About us</a></li>
</ul>

vous pouvez utiliser l'extrait de jQuery suivant pour offenser le rouleau:

$(function() {
    $("a.navigation").click(function(event) {
        event.preventDefault();
        offSetScroll($(this));
    });
    offSetScrollFromLocation(window.location.href.toLowerCase());
});

function offSetScroll(anchor) {
    var href = anchor.attr("href");
    offSetScrollFromLocation(href);
}

function offSetScrollFromLocation(href) {
    //Change this according to the height of the navigation bar
    var fromTop = 250;
    if(href.indexOf("#")<=0)
        return;
    var hash=href.substring(href.indexOf("#"));
    var targetOffset = $(hash).offset().top-fromTop;
    $('html, body').animate({scrollTop: targetOffset}, 400, function(e) {

    });
}
1
répondu Thunder 2015-09-03 19:09:08

implémenté en utilisant :before fonctionnait très bien jusqu'à ce que nous réalisions que le pseudo-élément couvrait et bloquait en fait les événements pointeurs qui sat dans la zone du pseudo-élément. L'utilisation de quelque chose comme pointer-events: none sur le :before ou même directement sur l'ancre n'a eu aucun effet.

ce que nous avons fini par faire était de rendre le positionnement de l'ancre absolu et ensuite ajuster sa position pour être le décalage/hauteur de la zone fixe.

ancre Offset sans Événements D'aiguille de blocage

.section-marker {

    position: absolute;
    top: -300px;
}

la valeur avec ceci est que nous ne bloquons aucun élément qui pourrait tomber à l'intérieur de ces 300px. L'inconvénient est que saisir la position de cet élément à partir de Javascript doit tenir compte de ce décalage, donc toute logique là-bas a dû être ajustée.

1
répondu skabob11 2017-02-16 23:03:48

C'est comme ça que je l'ai eu pour finalement aller au bon endroit quand tu cliques sur la navigation. J'ai ajouté un gestionnaire d'événements pour les clics de navigation. Ensuite, vous pouvez simplement utiliser "scrollBy" pour monter sur le décalage.

var offset = 90;

 $('.navbar li a').click(function(event) {
    event.preventDefault();
    $($(this).attr('href'))[0].scrollIntoView();
    scrollBy(0, -offset);
 });
1
répondu Mile Mijatovic 2017-08-21 20:45:07
// handle hashes when page loads
// <http://stackoverflow.com/a/29853395>
function adjustAnchor() {
  const $anchor = $(':target');
  const fixedElementHeight = $('.navbar-fixed-top').outerHeight();
  if ($anchor.length > 0)
    window.scrollTo(0, $anchor.offset().top - fixedElementHeight);
}
$(window).on('hashchange load', adjustAnchor);
$('body').on('click', "a[href^='#']", function (ev) {
  if (window.location.hash === $(this).attr('href')) {
    ev.preventDefault();
    adjustAnchor();
  }
});
0
répondu niftylettuce 2016-09-05 06:51:40

j'utilise cette méthode parce que pour une raison quelconque, aucune des autres solutions proposées n'a vraiment fonctionné pour moi. Je vous promets que j'ai essayé.

section {
   position: relative;
   border-top: 52px solid transparent; /* navbar height +2 */
   margin: -30px 0 0;
   -webkit-background-clip: padding-box;
   -moz-background-clip: padding;
   background-clip: padding-box;
}

section:before {
   content: "";
   position: absolute;
   top: -2px;
   left: 0;
   right: 0;
   border-top: 2px solid transparent;
}

remplacer section par une classe si vous préférez.

source: Sauter des liens et fenêtre de positionnement

  • testé sur Firefox 45 et Chrome 52.
  • version bootstrap: 3.3.7

pour ceux qui ne me croient pas j'ai gentiment préparé un jsfiddle avec la solution en elle: SOLUTION

0
répondu scavenger 2016-10-22 20:10:35

CSS trick sera une solution. Une solution appropriée qui fonctionnera dans tous les scénarios peut être implémentée en utilisant jQuery.

se référer à https://codepen.io/pikeshmn/pen/mMxEdZ

: Nous avons à la hauteur de fixe de la valeur liquidative à l'aide de document.getElementById ('header').offsetHeight Et décaler le rouleau à cette valeur.

var jump=function(e){  

e.preventDefault();                        //prevent "hard" jump
  var target = $(this).attr("href");       //get the target

      //perform animated scrolling
      $('html,body').animate(
        {
          scrollTop: $(target).offset().top - document.getElementById('header').offsetHeight - 5  //get top-position of target-element and set it as scroll target
        },1000,function()                  //scrolldelay: 1 seconds
        {
          location.hash = target;          //attach the hash (#jumptarget) to the pageurl
        });
      }

  $(document).ready(function()
  {
    $('a[href*="#"]').bind("click", jump); //get all hrefs
    return false;
  });

P. S:

  • il comprend une belle différence de 5 pixels entre l'en-tête et la cible
  • Défilement effet n'est pas dur, plutôt lisse, Lisse Défilement
0
répondu Pikesh Prasoon 2017-08-20 09:42:23

Ajouter une classe avec un "paddingtop", de sorte qu'il fonctionne ;)

<h1><a class="paddingtop">Bar</a></h1>

et pour css vous avez:

    .paddingtop{ 
       padding-top: 90px; 
     }
0
répondu Marcel1997 2017-11-10 21:01:37

une réponse CSS très simple est de mettre cela au sommet de votre feuille de style:

a{padding-top: 90px;}
a:link{padding-top: unset;}

le premier style régule toutes les marques d'ancrage où les marques d'ancrage second styles avec un hyperlien.

Note: cela fonctionne actuellement en Firefox et Edge mais pas en Chrome.

0
répondu D. Stewart 2018-03-08 02:13:36