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 | | ... | | ... | +---------------------------------+ +---------------------------------+
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; }
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);
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 /
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.
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.
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
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);
Ç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;
}
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.
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/
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>
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;
}
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:
-
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).
-
Le lien de signet HTML:
<a href="#01">What is your FAQ question again?</a>
-
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 .
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>
...
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();
}
};
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.
<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")
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) {
});
}
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.
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);
});
// 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();
}
});
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
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
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;
}
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.