L'en-tête de page fixe chevauche les ancrages sur la page

359

Si j'ai un en-tête sans défilement dans une page HTML, fixé en haut, ayant une hauteur définie:

Existe-t-il un moyen d'utiliser l'ancre URL (la #fragmentpartie) pour que le navigateur défile jusqu'à 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
FAUX (mais le comportement commun): CORRECT:
+ --------------------------------- + + -------------- ------------------- +
| BAR ///////////////////// en-tête | | //////////////////////// header |
+ --------------------------------- + + -------------- ------------------- +
| Voici le reste du texte | | BAR |
| ... | | |
| ... | | Voici le reste du texte |
| ... | | ... |
+ --------------------------------- + + -------------- ------------------- +
Tomalak
la source
3
@ax OUI, c'est la meilleure réponse. Vérifiez également nicolasgallagher.com/jump-links-and-viewport-positioning/demo à l' intérieur. Cela a fonctionné le mieux pour moi:.dislocate50px, #bar { padding: 50px 0 0; margin: -50px 0 0; -webkit-background-clip: content-box; background-clip: content-box; }
flen
je cherche une solution qui * fonctionne pour les ancres provenant de la même page ou d'une autre page, * et qui ajuste la pression sur la touche bas de page pour que le contenu ne soit pas écrêté par l'en-tête, * et qui permet au pied de page sib-div de faites défiler vers le haut avec content-div. Je n'ai pas encore trouvé de solution! Mais je dois dire que je pense que la bonne façon viserait la totalité du contenu, et non chaque ancre individuelle. stackoverflow.com/questions/51070758/…
johny why
@hache. CSS-tricks.com a un bien meilleur article plus récent scroll-padding-topici: css-tricks.com/… Réponse correspondante: stackoverflow.com/a/56467997/247696
Flimm

Réponses:

167

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 de remplissage supérieur.

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

Et puis simplement le CSS:

.anchor { padding-top: 90px; }
MutttenXd
la source
19
@Tomalak Soyez conscient que cette solution rend les liens à l'intérieur de la zone de remplissage non cliquables. Pour résoudre ce problème, vous devez utiliser z-index et définir une valeur de liens supérieure à celle de l'ancre. N'oubliez pas que la barre supérieure doit avoir la valeur d'index z la plus élevée, de sorte que le contenu de la page ne flotte pas sur la barre supérieure lorsque vous faites défiler.
MutttenXd
Ne fonctionnait pas dans Chrome v28 en raison d'un bogue de position fixe WebKit entraînant la disparition de l'en-tête. Cette réponse a fait l'affaire dans mon cas.
Knickedi
2
MuttenXd .. tu es mon héros. J'avais un problème de lien non fonctionnel étrange sur mon site (sans rapport avec les ancres) qui me rendait fou. Votre commentaire non cliquable a vraiment aidé. Je te dois grand!
zipzit
9
Comme suggéré dans la réponse de Roy Shoa, ajoutez margin-top: -90px;pour contrer l'écart créé par le rembourrage.
Skippy le Grand Gourou
37
J'ai utilisé de .anchor:target {padding-top: 90px;}sorte qu'il n'ait ajouté le rembourrage que lorsqu'ils ont utilisé la balise d'ancrage. De cette façon, il n'y a pas toujours un tas de rembourrage si la page se charge en haut. Seulement quand il charge un point spécifique plus bas sur la page.
jimmyplaysdrums
265

Si vous ne pouvez pas ou ne voulez pas définir une nouvelle classe, ajoutez un ::beforepseudo-élément à hauteur fixe au:target pseudo-classe en 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 par rapport à :targetavec jQuery:

var offset = $(':target').offset();
var scrollto = offset.top - 60; // minus fixed header height
$('html, body').animate({scrollTop:scrollto}, 0);
Adrian Garner
la source
30
J'aime vraiment ta solution. C'est la solution la plus propre que j'ai trouvée.
Itay Grudev
5
C'est la solution qui a parfaitement fonctionné pour moi sans bourrer quoi que ce soit d'autre dans ma mise en page.
Jamie Carl
2
La solution CSS a un problème lorsqu'elle est utilisée avec la liste dans WebKit. Regardez: stackoverflow.com/questions/39547773/…
Mert S. Kaplan
14
Cela ne fonctionnera pas si la cible a un rembourrage supérieur ou une bordure car elle repose sur la réduction de la marge.
krulik
9
:targetétait tout simplement génial!
sans fin
125

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 */
}

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

Voici d'autres solutions: http://nicolasgallagher.com/jump-links-and-viewport-positioning/

Jeremias Erbs
la source
regardez le lien fourni par Badabam, il y a une deuxième solution, que j'utilise et qui fonctionne dans Chrome et Firefox
scavenger
Testé sur le dernier Firefox (55.0.3 sur PC) et cela fonctionne maintenant. :-)
RachieVee
46

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

Fusionner

blnc
la source
1
Merci beaucoup de l'inclure, +1 pour l'exhaustivité.
amjoconn
2
Cette solution a un problème lorsqu'elle est utilisée avec la liste dans WebKit. Regardez: stackoverflow.com/questions/39547773/…
Mert S. Kaplan
Notez que cela ne fonctionnera pas si l'élément cible lui-même se trouve avoir display: flex;ou padding-top. Utilisez un élément d'ancrage dédié (comme <a name="my_link">{leave this empty}</a>) dans ces cas.
WoodrowShigeru
Cela ne fonctionnera pas si l'élément cible est <tr>
Ivan Gusev
42
html {
  scroll-padding-top: 70px; /* height of sticky header */
}

à partir de: https://css-tricks.com/fixed-headers-on-page-links-and-overlapping-content-oh-my/

François Romain
la source
Prise en charge du navigateur: caniuse.com/#feat=mdn-css_properties_scroll-padding-top
Flimm
Travaille pour moi. Je navigue vers l'ancre depuis une autre page. D'autres n'ont pas fonctionné. Merci!
davidloper
1
Cela ne fonctionne pas pour faire défiler la page entière dans Edge et Safari ( bugs.webkit.org/show_bug.cgi?id=179379 ).
Juliusz Gonera
1
Sauveur! Simple, précis. Aucune des autres solutions n'a fonctionné pour moi car j'utilise display: flex. Merci beaucoup, c'était tellement frustrant d'essayer toutes les solutions.
Priya Payyavula
Ceci est une belle solution, j'ai utilisé le comportement de défilement: lisse! Important; aussi pour jeter l'ancre, vraiment simple en deux lignes de code
yehanny
30

La meilleure façon que j'ai trouvée pour gérer ce problème est (remplacez 65 pixels par la hauteur de votre élément fixe):

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

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

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

Remarque: cet exemple ne fonctionnera pas si l'élément cible a une couleur d'arrière-plan différente 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 son élément parent rouge en 65 pixels. Je n'ai trouvé aucune solution CSS pure pour gérer ce problème, mais si vous n'avez pas une autre couleur d'arrière-plan, cette solution est la meilleure.

Roy Shoa
la source
2
De toutes les réponses, c'est la seule qui a fonctionné pour moi!
Javier Arias
18

Bien que certaines des solutions proposées fonctionnent pour les liens de fragments (= liens de hachage) au sein de la même page (comme un lien de menu qui défile vers le bas), j'ai constaté qu'aucune d'entre elles ne fonctionnait dans Chrome actuel lorsque vous souhaitez utiliser des liens de fragments provenant d'autres pages .

Donc, appeler www.mydomain.com/page.html#foo à partir de zéro ne compensera PAS votre cible dans Chrome actuel avec l'une des solutions CSS ou JS données.

Il y a aussi un rapport de bogue jQuery décrivant 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);
    }
}

SOMMAIRE

Sans délai JS, les solutions fonctionneront probablement dans Firefox, IE, Safari, mais pas dans Chrome.

Jpsy
la source
3
J'en suis arrivé à la même conclusion et à la même solution. Il semble que tout le monde oublie les liens externes qui utilisent les hashtags.
AJJ
J'ai ce problème aujourd'hui et j'ai utilisé votre solution. Bien qu'il semble que vous n'ayez pas besoin de délai d'attente. Cela fonctionne aussi comme IIFE.
kwiat1990
1
@ kwiat1990: Oui, cela peut être possible - mais seulement si votre JS est placé à la toute fin du code HTML. Sinon, votre cible de défilement pourrait ne pas être encore dans le DOM. En fait, c'est tout l'intérêt d'utiliser onDomReady. Je suppose donc que la version timeout est la voie stable à suivre.
Jpsy
Cette réponse était la seule qui fonctionnait pour les liens externes. Cependant, cela ne fonctionne pas pour moi lorsque le lien est appelé dans la même page :( Des idées?
Augusto Samamé Barrientos
@Augusto avez-vous trouvé une solution? Je rencontre le même problème.
Jesse
9

Comme la spécification CSS Scroll Snap entre en jeu, il est facilement possible avec la scroll-margin-toppropriété. Fonctionne actuellement sur Chrome et Opera (avril 2019). De plus, Safari 11+ devrait prendre en charge cela, mais je n'ai pas pu l'exécuter sur Safari 11. Nous devons probablement attendre que les gars le résolvent là-bas.

Exemple de Codepen

body {
  padding: 0;
  margin: 0;
}

h1,
p {
  max-width: 40rem;
  margin-left: auto;
  margin-right: auto;
}
h1 {
  scroll-margin-top: 6rem; /* One line solution. :-) */
}
.header {
  position: sticky;
  top: 0;
  background-color: red;
  text-align: center;
  padding: 1rem;
}
.header .scroll {
  display: block;
  color: white;
  margin-bottom: 0.5rem;
}
.header .browsers {
  color: black;
  font-size: 0.8em;
}
<header class="header">
  <a class="scroll" href="#heading">Scroll to heading</a>
  <span class="browsers" >Chrome 69+, Opera 56+ and Safari 11+ only</span>
</header>
<p>
  Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
</p>
<h1 id="heading">What is Lorem Ipsum?</h1>
<p>
  Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
</p>
<p>
  

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent pulvinar eleifend dolor, in cursus augue interdum quis. Morbi volutpat pulvinar nisl et condimentum. Quisque elit lacus, egestas non ante sit amet, hendrerit commodo dui. Nunc ac sagittis dolor. Proin iaculis ante non est pharetra, et ullamcorper nisl accumsan. Aenean quis leo vel sapien eleifend aliquam. Pellentesque finibus dui ex, blandit tristique risus vestibulum vitae. Nam a quam ac turpis porta eleifend. Sed at hendrerit risus, ac efficitur ante. Aenean pretium justo feugiat condimentum consectetur. Etiam mattis urna id porta hendrerit.
</p>
<p>
Mauris venenatis quam sed egestas auctor. Fusce lacus eros, condimentum nec quam vel, malesuada gravida libero. Praesent vel sollicitudin justo. Donec mattis nisl id mauris scelerisque, quis placerat lectus scelerisque. Ut id justo a magna mattis luctus. Suspendisse massa est, pretium vel suscipit sit amet, iaculis at mi. Aenean vulputate ipsum non consectetur sodales. Proin aliquet erat nec mi eleifend, eu dapibus enim ultrices. Sed fringilla tortor ac rhoncus consectetur. Aliquam aliquam orci ultrices tortor bibendum facilisis.
</p>
<p>
Donec ultrices diam quam, non tincidunt purus scelerisque aliquam. Nam pretium interdum lacinia. Donec sit amet diam odio. Donec eleifend nibh ut arcu dictum, in vulputate magna malesuada. Nam id dignissim tortor. Suspendisse commodo, nunc sit amet blandit laoreet, turpis nibh rhoncus mi, et finibus nisi diam sed erat. Vivamus diam arcu, placerat in ultrices eu, porta ut tellus. Aliquam vel nisi nisi.
</p>
<p>
Integer ornare finibus sem, eget vulputate lacus ultrices ac. Vivamus aliquam arcu sit amet urna facilisis consectetur. Sed molestie dolor et tortor elementum, nec bibendum tortor cursus. Nulla ipsum nulla, luctus nec fringilla id, sagittis et sem. Etiam at dolor in libero pharetra consequat. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Suspendisse quis turpis non diam mattis varius. Praesent at gravida mi. Etiam suscipit blandit dolor, nec convallis lectus mattis vitae. Mauris placerat erat ipsum, vitae interdum mauris consequat quis. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</p>
<p>
Nunc efficitur scelerisque elit. Integer ac massa ipsum. Cras volutpat nulla purus, quis molestie dolor iaculis eget. Maecenas ut ex nulla. Pellentesque sem augue, ornare ut arcu eu, porttitor consectetur orci. Aenean iaculis blandit quam, in efficitur justo sodales auctor. Vivamus dignissim pellentesque risus eget consequat. Pellentesque sit amet nisi in urna convallis egestas vitae nec mauris. 
</p>

dakur
la source
1
C'est plutôt mignon. Espérons qu'il sera adopté plus largement!
Tomalak
Quelle est la difference entre scroll-padding-topet scroll-margin-top?
Flimm
scroll-margin-toppour ce cas d'utilisation n'est malheureusement pas implémenté dans Safari 11-13: bugs.webkit.org/show_bug.cgi?id=189265
fabb
Dans Safari, il s'appelle scroll-snap-margin-top: caniuse.com/#search=scroll-margin-top
Mu-Tsun Tsai
@ Mu-TsunTsai C'est un peu plus compliqué. Cela existe vraiment sur Safari, mais cela ne fonctionne pas avec le comportement de défilement pour fragmenter. Voir mon commentaire dans le numéro de navigateur-compatibilité-données: github.com/mdn/browser-compat-data/issues/…
dakur
8

Pour Chrome / Safari / Firefox, vous pouvez ajouter un display: blocket utiliser une marge négative pour compenser le décalage, comme:

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

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

MrSwed
la source
7

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);
webvitaly
la source
Pas ".target", devrait être ": target"
Mert S. Kaplan
@ MertS.Kaplan ".target" est la classe 'cible'.
webvitaly
7

Je viens de découvrir une autre solution CSS pure qui a fonctionné comme un charme pour moi!

html {
  scroll-padding-top: 80px; /* height of your sticky header */
}

Trouvé sur ce site !

jamawe
la source
2
Quelques autres ont découvert cette solution avant vous, voir les réponses à la page 1, par exemple stackoverflow.com/a/56467997/18771
Tomalak
Désolé, je n'ai pas remarqué! Merci!
jamawe
Cela ne fonctionne pas pour faire défiler la page entière dans Edge et Safari ( bugs.webkit.org/show_bug.cgi?id=179379 ).
Juliusz Gonera
5

Vous pouvez 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 introduira un léger espace supplémentaire en haut de votre en-tête, mais il ne sera visible que lorsque l'utilisateur sautera à l'ancre, puis défilera vers le haut. J'ai créé cette solution pour mon site en ce moment, mais elle ne montre qu'une petite barre fixe en haut de la page, rien de trop haut.

ygoe
la source
Mh. Pas mal, mais tout de même un hack (et ne fonctionne malheureusement pas sous IE).
Tomalak
5

Je l'ai fait fonctionner facilement avec CSS et HTML, en utilisant la méthode "anchor: before" mentionnée ci-dessus. Je pense que cela fonctionne le mieux, car il 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 */
}

Cela ne semble pas fonctionner pour la première division de la page, mais vous pouvez y remédier en ajoutant un remplissage à cette première division.

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

Voici un violon fonctionnel: http://jsfiddle.net/FRpHE/24/

Eric Wood
la source
5

Ça marche pour moi:

LIEN HTML vers l'ancre:

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

Ancre HTML:

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

CSS:

.anchor::before {
    content: "";
    display: block;
    margin-top: -50px;
    position: absolute;
}
Avila
la source
5

Je n'ai pas eu de chance avec la réponse ci-dessus et j'ai fini par utiliser cette solution qui fonctionnait parfaitement ...

Créez un intervalle vierge à l'endroit où vous souhaitez définir votre ancre.

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

Et appliquez la classe suivante:

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

Cette solution fonctionnera même si les sections ont des arrière-plans colorés différents! J'ai trouvé la solution sur ce lien.

Matt Underwood
la source
1
N'est-ce pas exactement la même méthode que Guillaume Le Mière et quelques autres ont montré dans ce fil?
Tomalak
C'est très similaire mais je pense que c'est plus facile à comprendre et une réponse plus détaillée avec un lien encore plus approfondi avec une source extérieure.
Matt Underwood
C'est la même solution, mais je peux comprendre et suivre celle-ci facilement. Les autres ne m'ont pas donné suffisamment d'informations.
MacroMan
4

J'utilise la réponse de @ Jpsy, mais pour des raisons de performances, 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();
      }
  };
sandre89
la source
OP a demandé de ne pas utiliser javascript.
Giulio Caccin
Fonctionne avec des liens externes mais pas avec des liens sur la page.
snap
4

J'ai eu beaucoup de problèmes avec la plupart des réponses ici et ailleurs car mes ancres mises en signet étaient des en-têtes de section dans une page FAQ, donc la compensation de l'en-tête n'a pas aidé car le reste du contenu resterait simplement où il était. J'ai donc pensé poster.

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 du signet HTML:

    <a href="#01">What is your FAQ question again?</a>
  2. Le contenu mis en signet 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' spanélément n'est pas seulement caché, il est essentiellement réduit et ne remplit pas votre contenu.

Je ne peux pas prendre beaucoup de crédit pour cette solution car elle provient d'un tas de ressources différentes, mais cela a fonctionné le mieux pour moi dans ma situation.

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

SteveCinq
la source
1
Merci beaucoup pour le partage! Quel que soit le fil, il ne semble toujours pas y avoir de solution canonique à ce problème.
Tomalak
1
+ SteveCinq Vous avez lu dans mes pensées - j'étais confronté aux mêmes problèmes où les solutions partagées ne fonctionnaient pas comme prévu. L'ajout <span>de l'ancre dans la travée, ainsi que l'ajout du rembourrage et de la marge ont fonctionné pour moi. Merci beaucoup d'avoir pris le temps de soumettre cette réponse malgré l'âge du fil!
twknab
3

Cela semble un peu hacky à mon esprit puriste, mais en tant que solution CSS uniquement, vous pouvez ajouter un remplissage à l'élément ancré actif à l'aide du :targetsélecteur:

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>

Moob
la source
1
Ce n'est pas du tout hacky! Belle solution.
Tomalak
3

Je trouve que je devais utiliser les deux MutttenXd « s et Badabam Les solutions CSS » ensemble, comme le premier n'a pas fonctionné dans Chrome et le second n'a pas fonctionné 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>
...
tshalif
la source
3

La manière que je trouve la plus propre est la suivante:

  #bar::before {
    display: block;
    content: " ";
    margin-top: -150px;
    height: 150px;
    visibility: hidden;
    pointer-events: none;
  }
Guillaume Le Mière
la source
2

Une approche minimalement intrusive utilisant jQuery:

Lien:

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

Contenu:

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

Scénario:

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

En affectant la classe de lien d'ancrage aux liens, le comportement des autres liens (comme les contrôles d'accordéon ou de tabulation) n'est pas affecté.

La question ne veut pas de javascript mais l'autre question plus populaire est fermée à cause de celle-ci et je n'ai pas pu y répondre.

Hüseyin Yağlı
la source
2

J'avais besoin de quelque chose qui fonctionne pour les liens entrants, les liens sur la page ET qui peuvent être ciblés par JS afin que la page puisse répondre aux changements de hauteur de l'en-tête

HTML

<ul>
  <li><a href="#ft_who">Who?</a></li>
  <li><a href="#ft_what">What?</a></li>
  <li><a href="#ft_when">When?</a></li>
</ul>
...
<h2 id="ft_who" class="fragment-target">Who?</h2> 
...
<a href="#">Can I be clicked?</a>
<h2 id="ft_what" class="fragment-target">What?</h2>
...
<h2 id="ft_when" class="fragment-target">When?</h2> 

CSS

.fragment-target {
    display: block;
    margin-top: -HEADER_HEIGHTpx;
    padding-top: HEADER_HEIGHTpx;
    z-index: -1;
}

Le z-index: -1permet aux liens dans la «zone de remplissage» au-dessus d'une cible-fragment d'être toujours cliquables, comme l'a commenté @MuttenXd sur sa réponse

Je n'ai pas encore trouvé de problème dans IE 11, Edge 15+, Chrome 38+, FF 52+ ou Safari 9.1+

Arth
la source
1
<div style="position:relative; top:-45px;">
    <a name="fragment"> </a>
</div>

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

EDIT: Si l'utilisation de jQuery est une option, j'ai également réussi à utiliser jQuery.localScroll avec une valeur de décalage définie. L'option de décalage fait partie de jQuery.scrollTo, sur laquelle jQuery.localScroll est construit. Une démo est disponible ici: http://demos.flesler.com/jquery/scrollTo/ (deuxième fenêtre, sous 'offset')

fourk
la source
cette solution fonctionne en effet, mais elle n'est pas à l'épreuve des balles et elle nécessite beaucoup de mise au point pour différents navigateurs :( bon essai thoug. Je recherche une solution sans balisage supplémentaire.
vlad saling
Dommage que ce soit si compliqué, cela signifie que vous ne pouvez pas simplement utiliser des identifiants. J'adorerais trouver une solution, j'ai essayé toutes sortes de choses.
théoriser le
1

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

Supposons que les éléments de la barre de navigation ressemblent à 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 code jquery suivant pour compenser le défilement:

$(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) {

    });
}
Tonnerre
la source
J'ai pu utiliser une version légèrement modifiée de ce code de Thunder. J'ai essayé de nombreuses solutions CSS uniquement et plus simples sur cette page et sur stackoverflow.com/questions/10732690/… et sur stackoverflow.com/questions/10732690/… mais elles n'étaient pas utilisables en raison de mes besoins. La page est une page de FAQ avec de nombreuses ancres à positionner, à la fois sur et hors de la page, donc pourrait avoir beaucoup de taches vides. Suite dans le commentaire suivant ....
Jeffrey Simon
1
Pour que cela fonctionne pour moi, voici les changements mineurs: (1) changer "<=" dans la ligne href.index en "<" pour permettre la navigation sur la page; (2) changer "a.navigation" qui devait être "#faq a" pour mon usage; (3) changer var de Top = 250 à un ternaire basé sur window.innerWidth pour les différences entre mobile et bureau; (4) changez 400 dans l'animation en 1, car l'animation n'est pas souhaitée et 0 ne fonctionne pas; (5) ajoutez if ($ ('my-page-selector'). Length avant l'appel à offSetScrollFromLocation dans la fonction anonyme pour éviter les appels inutiles sur les pages où cela n'est pas nécessaire.
Jeffrey Simon
1

L'implémentation a :beforefonctionné très bien jusqu'à ce que nous réalisions que le pseudo-élément couvrait et bloquait réellement les événements de pointeur qui se trouvaient dans la zone du pseudo-élément. Utiliser quelque chose comme pointer-events: nonesur 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'ancrage absolu, puis d'ajuster sa position pour qu'elle soit le décalage / la hauteur de la zone fixe.

Ancre décalée sans bloquer les événements de pointeur

.section-marker {

    position: absolute;
    top: -300px;
}

La valeur de ceci est que nous ne bloquons aucun élément qui pourrait tomber dans ces 300 pixels. L'inconvénient est que la saisie de la position de cet élément dans Javascript doit prendre en compte ce décalage, de sorte que toute logique doit être ajustée.

skabob11
la source
1

C'est ainsi que je l'ai fait pour enfin aller au bon endroit lorsque vous cliquez sur la navigation. J'ai ajouté un gestionnaire d'événements pour les clics de navigation. Ensuite, vous pouvez simplement utiliser "scrollBy" pour vous déplacer vers le haut sur le décalage.

var offset = 90;

 $('.navbar li a').click(function(event) {
    event.preventDefault();
    $($(this).attr('href'))[0].scrollIntoView();
    scrollBy(0, -offset);
 });
Mile Mijatović
la source
2
Résout le problème, mais pas la partie "sans l'aide de Javascript" ...
Tomalak
1

J'ai créé un div avec quelques sauts de ligne et j'ai donné l'id, j'ai ensuite mis le code que je voulais montrer en dessous. Le lien vous mènerait alors à l'espace au-dessus de l'image et l'en-tête ne serait plus gênant:

<a href="#image">Image</a>
<div id="image"><br><br></div>
<img src="Image.png">

Bien sûr, vous pouvez modifier le nombre de sauts de ligne en fonction de vos besoins. Cela a parfaitement fonctionné pour moi, je ne sais pas s'il y a des problèmes, j'apprends encore le HTML.

Anonyme
la source
Pragmatique, mais il y a un inconvénient - cela ne fonctionne que pour le premier titre d'une page. S'il y a plus de titres, vous commencerez à voir de grandes lacunes dans le texte à cause des <br>balises avant chaque titre.
Tomalak
1

Utilisé ce script

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

    $('html, body').animate({
        scrollTop: $($.attr(this, 'href')).offset().top -140
    }, 1000);
});
Aadil Memon
la source
Veuillez essayer d'expliquer pourquoi vous pensez que ce script résoudrait le problème
Ali Kanat
1

Je pense que cette approche est plus utile:

<h2 id="bar" title="Bar">Bar</h2>

[id]:target {
    display: block;
    position: relative;
    top: -120px;
    visibility: hidden;
}

[id]:target::before {
    content: attr(title);
    top: 120px;
    position: relative;
    visibility: visible;
}
Enes Shahin
la source