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 partie #fragment
) pour faire défiler le navigateur 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 /////////////////////// header | | //////////////////////// header | + -------------------- ------------- + + --------------------------------- + | Voici le reste du texte | | BAR | | ... | | | | ... | | Voici le reste du texte | | ... | | ... | + --------------------------------- + + ------- -------------------------- +
J'ai eu le même problème… .. Je l'ai résolu en ajoutant une classe à l'élément anchor avec la hauteur de la barre supérieure en tant que valeur padding-top.
<h1><a class="anchor" name="barlink">Bar</a></h1>
Et puis simplement le css:
.anchor { padding-top: 90px; }
Si vous ne pouvez ou ne voulez pas définir une nouvelle classe, ajoutez un pseudo-élément ::before
à hauteur fixe au pseudo-classe :target
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 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 */
}
Il ajoute un élément invisible avant chaque cible. Cela fonctionne IE8 +.
Voici d'autres solutions: http://nicolasgallagher.com/jump-links-and-viewport-positioning/
La meilleure façon que j'ai trouvée de 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 target , vous pouvez également le faire de cette manière:
.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 celle 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 remplacera son élément parent rouge en 65px . Je n'ai trouvé aucune solution CSS pure pour gérer ce problème, mais si vous n'avez pas d'autre couleur d'arrière-plan, cette solution est la meilleure.
Bien que certaines des solutions proposées fonctionnent pour les 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'aucune d'entre elles ne fonctionnait dans Chrome actuel lorsque vous souhaitez utiliser des liens de fragment. venant d'autres pages.
Par conséquent, si vous appelez www.mondomaine.com/page.html#foo à partir de zéro, ET NON ne décalera pas votre cible dans Chrome actuel avec l’une des solutions CSS ou JS données.
Il existe également 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);
}
}
R&EACUTE;SUM&EACUTE;
Sans un délai JS, les solutions fonctionneront probablement dans Firefox, IE, Safari, mais pas dans Chrome.
Pour Chrome/Safari/Firefox, vous pouvez ajouter un display: block
et utiliser une marge négative pour compenser le décalage, par exemple:
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 à 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;
}
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 sur 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 vers l'ancre puis fera défiler vers le haut. Je compose cette solution pour mon site pour le moment, mais elle ne montre qu'une petite barre fixe en haut de la page, rien de trop élevé.
Je travaille facilement avec CSS et HTML, en utilisant la méthode "anchor: before" mentionnée ci-dessus. Je pense que cela fonctionne le mieux, car cela ne crée pas un 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 div de la page, mais vous pouvez y remédier en ajoutant un remplissage à cette première div.
#anchor-one{padding-top: 60px;}
Voici un violon qui fonctionne: http://jsfiddle.net/FRpHE/24/
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();
}
};
J'ai découvert que je devais utiliser les solutions CSS de both MutttenXd et Badabam, car la première ne fonctionnait pas dans Chrome et la seconde 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>
...
La façon dont je trouve 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 difficulté avec de nombreuses réponses ici et ailleurs, mes ancres marquées étant des en-têtes de section dans une page FAQ, le décalage de l'en-tête n'aide à rien, le reste du contenu restant ainsi à la place . Alors j'ai pensé poster.
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 la hauteur de votre en-tête fixe (peut-être plus une marge).
Le lien de signet HTML:
<a href="#01">What is your FAQ question again?</a>
Le contenu HTML mis en signet:
<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 réduit et ne masque pas votre contenu.
Je ne peux pas prendre beaucoup de crédit pour cette solution car elle provient d'un swag de ressources différentes, mais cela a fonctionné mieux pour moi dans ma situation.
Vous pouvez voir le résultat réel ici .
Cela me semble quelque peu hacky, mais en tant que solution CSS, vous pouvez ajouter un remplissage à l'élément ancré actif à l'aide du 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>
J'avais besoin de quelque chose qui fonctionne pour les liens entrants, les liens sur la page ET pouvant être ciblé par JS afin que la page puisse répondre aux changements de hauteur
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: -1
permet de cliquer sur les liens de la zone de remplissage située au-dessus d'un fragment-cible, comme l'a commenté @MuttenXd dans 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+.
Une approche peu 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 anchor-link aux liens, le comportement des autres liens (tels que les contrôles accordéon ou à onglet) 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 ne peux pas y répondre.
J'ai créé une div avec quelques sauts de ligne et lui ai donné l'identifiant. J'ai ensuite placé le code que je voulais montrer. Le lien vous mènerait alors à l'espace au-dessus de l'image et l'en-tête ne serait plus un obstacle:
<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, mais je ne suis pas sûr qu'il y ait des problèmes, j'apprends toujours le HTML.
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/
Implémenté en utilisant :before
a bien fonctionné jusqu'à ce que nous réalisions que le pseudo-élément recouvrait et bloquait les événements de pointeur qui se trouvaient 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.
Nous avons fini par définir le positionnement absolu de l'ancre, puis l'ajuster de manière à correspondre au 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 susceptible de tomber dans ces 300 pixels. L'inconvénient est que, pour saisir la position de cet élément à partir de Javascript, il faut tenir compte de cette compensation, de sorte que toute logique doit y être ajustée.
C’est ainsi que je l’ai obtenu pour aller enfin 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 augmenter le décalage.
var offset = 90;
$('.navbar li a').click(function(event) {
event.preventDefault();
$($(this).attr('href'))[0].scrollIntoView();
scrollBy(0, -offset);
});
Utilisé ce script
$(document).on('click', 'a[href^="#"]', function (event) {
event.preventDefault();
$('html, body').animate({
scrollTop: $($.attr(this, 'href')).offset().top -140
}, 1000);
});
Comme Spéc. CSS Scroll Snap entre en jeu, il est facilement possible avec la propriété scroll-margin-top
. Fonctionne actuellement sur Chrome et Opera (avril 2019). Safari 11+ devrait également supporter cela, mais je n’étais pas capable de le faire sur Safari 11. Nous devons probablement attendre que les gars le réparent.
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>
Voici une solution complète de jquery 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 le fragment de code jQuery suivant pour décaler 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) {
});
}
<div style="position:relative; top:-45px;">
<a name="fragment"> </a>
</div>
Ce code devrait faire l'affaire. Échangez 45px pour la hauteur de votre barre d’entête.
EDIT: Si jQuery est une option, j’ai également réussi à utiliser jQuery.localScroll avec une valeur de décalage définie. L'option offset 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')
Ajouter une classe avec un "paddingtop", donc ça marche;)
<h1><a class="paddingtop">Bar</a></h1>
Et pour css vous avez:
.paddingtop{
padding-top: 90px;
}
// 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();
}
});
Une réponse CSS très simple consiste à placer ceci en haut de votre feuille de style:
a{padding-top: 90px;}
a:link{padding-top: unset;}
Le premier style régit toutes les balises d'ancrage, tandis que le second style les ancre avec un lien hypertexte.
Remarque: Cela fonctionne actuellement dans Firefox et Edge, mais pas dans Chrome.
J'utilise cette méthode car, pour une raison quelconque, aucune des autres solutions proposées ne fonctionnait réellement pour moi. Je 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;
}
Remplacez section par une classe si vous préférez.
source: Liens de saut et positionnement de la fenêtre d'affichage
Pour ceux qui ne me croient pas, j’ai gentiment préparé un scénario avec la solution qu'il contient: SOLUTION
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 une étendue vide 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 de couleurs différentes! J'ai trouvé la solution à ce lien.
Astuce CSS sera une solution de contournement. Une solution appropriée qui fonctionnera dans tous les scénarios peut être mise en œuvre à l'aide de jQuery.
Reportez-vous à https://codepen.io/pikeshmn/pen/mMxEdZ
Approche: Nous obtenons la hauteur de navigation fixe en utilisant document.getElementById ('header'). OffsetHeight
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: