El encabezado de página fijo se superpone a los anclajes en página

359

Si tengo un encabezado sin desplazamiento en una página HTML, fijado en la parte superior, que tiene una altura definida:

¿Hay alguna manera de usar el anclaje de URL (la #fragmentparte) para que el navegador se desplace a un cierto punto de la página, pero aún respete la altura del elemento fijo sin la ayuda de JavaScript ?

http://foo.com/#bar
Incorrecto (pero el comportamiento común): CORRECTO:
+ --------------------------------- + + -------------- ------------------- +
El | BAR ///////////////////// encabezado | El | //////////////////////// encabezado |
+ --------------------------------- + + -------------- ------------------- +
El | Aquí está el resto del texto | El | BAR |
El | ... | El | El |
El | ... | El | Aquí está el resto del texto |
El | ... | El | ... |
+ --------------------------------- + + -------------- ------------------- +
Tomalak
fuente
3
@ax SÍ, esa es la mejor respuesta. También consulte nicolasgallagher.com/jump-links-and-viewport-positioning/demo dentro de él. Esto funcionó mejor para mí:.dislocate50px, #bar { padding: 50px 0 0; margin: -50px 0 0; -webkit-background-clip: content-box; background-clip: content-box; }
flen
Estoy buscando una solución que * funcione para las anclas que provienen de la misma página u otra página, * y que ajuste la pulsación de teclas de página abajo para que el contenido no se recorte por encabezado, * y que permita que el pie de página sib-div desplazarse hacia arriba con content-div. ¡Aún no he encontrado una solución! Pero debo decir que creo que la forma correcta apuntaría a todo el contenido div, y no a cada ancla individual. stackoverflow.com/questions/51070758/…
johny why
@hacha. CSS-tricks.com tiene un artículo mucho más nuevo scroll-padding-topaquí: css-tricks.com/… Respuesta correspondiente: stackoverflow.com/a/56467997/247696
Flimm

Respuestas:

167

Yo tuve el mismo problema. Lo resolví agregando una clase al elemento de anclaje con la altura de la barra superior como el valor de relleno superior.

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

Y luego simplemente el CSS:

.anchor { padding-top: 90px; }
MutttenXd
fuente
19
@Tomalak Tenga en cuenta que esta solución hace que no se pueda hacer clic en los enlaces dentro del área de relleno. Para solucionar esto, debe usar el índice z y establecer el valor de los enlaces más alto que el del ancla. Recuerde que la barra superior debe tener el valor de índice z más alto, de modo que el contenido de la página no flote encima de la barra superior cuando se desplace.
MutttenXd
No funcionó en Chrome v28 debido a un error de posición fija de WebKit que hacía que el encabezado desapareciera. Esta respuesta hizo el truco en mi caso.
Knickedi
2
MuttenXd ... eres mi héroe. Tuve un extraño problema de enlace no funcional en mi sitio (no relacionado con las anclas) que me estaba volviendo loco. Su comentario no cliqueable realmente ayudó. Te debo mucho!
zipzit
99
Como se sugiere en la respuesta de Roy Shoa, agregue margin-top: -90px;para contrarrestar la brecha creada por el relleno.
Skippy le Grand Gourou
37
Lo usé .anchor:target {padding-top: 90px;}para que solo agregara el relleno cuando usaron la etiqueta de anclaje. De esta manera, no siempre hay un montón de relleno si la página se carga en la parte superior. Solo cuando carga un punto específico más abajo en la página.
jimmyplaysdrums
265

Si no puede o no quiere establecer una nueva clase, agregue un ::beforepseudo-elemento de altura fija a la :targetpseudo-clase en CSS:

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

O desplazarse por la página en relación :targetcon jQuery:

var offset = $(':target').offset();
var scrollto = offset.top - 60; // minus fixed header height
$('html, body').animate({scrollTop:scrollto}, 0);
Adrian Garner
fuente
30
Realmente me gusta tu solución. Es la solución más limpia que encontré.
Itay Grudev
55
Esta es la solución que funcionó perfectamente para mí sin rellenar nada más en mi diseño de página.
Jamie Carl
2
La solución CSS tiene un problema cuando se usa con la lista en WebKit. Mire: stackoverflow.com/questions/39547773/…
Mert S. Kaplan
14
No funcionará si el objetivo tiene un relleno o borde superior, ya que depende del colapso del margen.
krulik
99
:targetfue genial!
Sin fin
125

Yo uso este enfoque:

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

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

Agrega un elemento invisible antes de cada objetivo. Funciona IE8 +.

Aquí hay más soluciones: http://nicolasgallagher.com/jump-links-and-viewport-positioning/

Jeremias Erbs
fuente
mira el enlace que Badabam proporcionó, hay una segunda solución, que uso y que funciona en Chrome y Firefox
carroñero
Probé esto en el último Firefox (55.0.3 en PC) y ahora funciona. :-)
RachieVee
46

Respuesta adoptada oficial de Bootstrap:

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

Créditos

Unir

blnc
fuente
1
Muchas gracias por incluir esto, +1 por lo completo.
amjoconn
2
Esta solución tiene un problema cuando se usa con list en WebKit. Mire: stackoverflow.com/questions/39547773/…
Mert S. Kaplan
Tenga en cuenta que esto no funcionará si el elemento de destino en sí tiene display: flex;o padding-top. Utilice un elemento de anclaje dedicado (como <a name="my_link">{leave this empty}</a>) en esos casos.
WoodrowShigeru
Esto no funcionará si el elemento objetivo es <tr>
Ivan Gusev
42
html {
  scroll-padding-top: 70px; /* height of sticky header */
}

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

François Romain
fuente
Funciona para mi. Estoy navegando al ancla desde otra página. Otros no funcionaron. ¡Gracias!
davidloper
1
Esto no funciona para desplazarse por toda la página en Edge y Safari ( bugs.webkit.org/show_bug.cgi?id=179379 ).
Juliusz Gonera
1
¡Salvador! Simple, en punto. Ninguna de las otras soluciones funcionó para mí porque estoy usando display: flex. Muchas gracias, fue muy frustrante probar todas las soluciones.
Priya Payyavula
Esta es una solución HERMOSA, utilicé el comportamiento de desplazamiento: suave! Importante; también para anclar, realmente simple en dos líneas de código
yehanny
30

La mejor manera que encontré para manejar este problema es (reemplace 65 px con la altura de su elemento fijo):

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

Si no le gusta usar el selector de objetivos , también puede hacerlo de esta manera:

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

Nota: este ejemplo no funcionará si el elemento de destino tiene un color de fondo que difiere de su padre. por ejemplo:

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

en este caso, el color verde del elemento my-target sobrescribirá su elemento rojo padre en 65px. No encontré ninguna solución CSS pura para manejar este problema, pero si no tiene otro color de fondo, esta solución es la mejor.

Roy Shoa
fuente
2
¡De todas las respuestas, esta es la única que me ha funcionado!
Javier Arias
18

Si bien algunas de las soluciones propuestas funcionan para enlaces de fragmentos (= enlaces hash) dentro de la misma página (como un enlace de menú que se desplaza hacia abajo), descubrí que ninguno de ellos funcionaba en Chrome actual cuando desea usar enlaces de fragmentos provenientes de otros páginas .

Llamar a www.mydomain.com/page.html#foo desde cero NO compensará su objetivo en Chrome actual con ninguna de las soluciones CSS o JS dadas.

También hay un informe de error jQuery que describe algunos detalles del problema.

SOLUCIÓN

La única opción que encontré hasta ahora que realmente funciona en Chrome es JavaScript que no se llama onDomReady pero con retraso.

// 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);
    }
}

RESUMEN

Sin un retraso JS, las soluciones probablemente funcionarán en Firefox, IE, Safari, pero no en Chrome.

Jpsy
fuente
3
He llegado a la misma conclusión y solución. Parece que todos los demás se están olvidando de los enlaces externos que usan los hashtags.
AJJ
Hoy tengo ese problema y he usado tu solución. Aunque parece que no necesitas tiempo de espera. Esto funciona como IIFE también.
kwiat1990
1
@ kwiat1990: Sí, eso puede ser posible, pero solo si su JS se coloca al final del código HTML. De lo contrario, es posible que su objetivo de desplazamiento aún no esté en el DOM. En realidad, ese es el objetivo de usar onDomReady. Así que supongo que la versión de tiempo de espera es la forma estable de hacerlo.
Jpsy
Esta respuesta fue la única que funcionó para enlaces externos. Sin embargo, no funciona para mí cuando se llama al enlace en la misma página :( ¿Alguna idea?
Augusto Samamé Barrientos
@Augusto, ¿encontraste una solución? Estoy teniendo el mismo problema.
Jesse
9

A medida que la especificación CSS Scroll Snap entra en juego, es fácilmente posible con la scroll-margin-toppropiedad. Actualmente se ejecuta en Chrome y Opera (abril de 2019). También Safari 11+ debería admitir esto, pero no pude ejecutarlo en Safari 11. Probablemente tengamos que esperar a que los chicos lo arreglen allí.

Ejemplo 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
fuente
1
Eso es muy dulce ¡Esperemos que se adopte más ampliamente!
Tomalak
¿Cuál es la diferencia entre scroll-padding-topy scroll-margin-top?
Flimm
scroll-margin-toppara este caso de uso, lamentablemente no se implementa en Safari 11-13: bugs.webkit.org/show_bug.cgi?id=189265
fabb
En Safari se llama scroll-snap-margin-top: caniuse.com/#search=scroll-margin-top
Mu-Tsun Tsai
@ Mu-TsunTsai Es un poco más complicado. Esto realmente existe en Safari, pero no funciona con el comportamiento de desplazamiento a fragmento. Vea mi comentario en el problema browser-compat-data: github.com/mdn/browser-compat-data/issues/…
dakur
8

Para Chrome / Safari / Firefox, puede agregar ay display: blockusar un margen negativo para compensar el desplazamiento, como:

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

Ver ejemplo http://codepen.io/swed/pen/RrZBJo

MrSwed
fuente
7

Puedes hacer esto con jQuery:

var offset = $('.target').offset();
var scrollto = offset.top - 50; // fixed_top_bar_height = 50px
$('html, body').animate({scrollTop:scrollto}, 0);
webvitaly
fuente
No ".target", debería ser ": target"
Mert S. Kaplan
@ MertS.Kaplan ".target" es el "objetivo" de la clase.
webvitaly
7

¡Acabo de descubrir otra solución CSS pura que funcionó como un encanto para mí!

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

Encontrado en este sitio !

jamawe
fuente
2
Algunos otros han descubierto esta solución antes que usted, vea las respuestas en la página 1, por ejemplo stackoverflow.com/a/56467997/18771
Tomalak
Lo siento, no me he dado cuenta! ¡Gracias!
jamawe
Esto no funciona para desplazarse por toda la página en Edge y Safari ( bugs.webkit.org/show_bug.cgi?id=179379 ).
Juliusz Gonera
5

Podrías probar esto:

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

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

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

Establezca el valor de relleno superior a la altura real de su encabezado. Esto introducirá un pequeño espacio adicional en la parte superior de su encabezado, pero solo será visible cuando el usuario salte al ancla y luego se desplace hacia arriba. He creado esa solución para mi sitio en este momento, pero solo muestra una pequeña barra fija en la parte superior de la página, nada demasiado alto.

ygoe
fuente
Mh No está mal, pero sigue siendo un hack (y lamentablemente no funciona en IE).
Tomalak
5

Lo tengo trabajando fácilmente con CSS y HTML, usando el método "ancla: antes" mencionado anteriormente. Creo que funciona mejor, porque no crea un relleno masivo entre tus divs.

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

No parece funcionar para el primer div de la página, pero puede contrarrestar eso agregando relleno a ese primer div.

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

Aquí hay un violín que funciona: http://jsfiddle.net/FRpHE/24/

Eric Wood
fuente
5

Esto funciona para mi:

HTML LINK to Anchor:

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

Ancla HTML:

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

CSS:

.anchor::before {
    content: "";
    display: block;
    margin-top: -50px;
    position: absolute;
}
avila
fuente
4

Estoy usando la respuesta de @ Jpsy, pero por razones de rendimiento solo configuro el temporizador si el hash está presente en la 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
fuente
OP solicitó no usar javascript.
Giulio Caccin
Funciona con enlaces externos pero no con enlaces in-page.
complemento
4

Tuve muchos problemas con muchas de las respuestas aquí y en otros lugares, ya que mis anclas marcadas eran encabezados de sección en una página de preguntas frecuentes, por lo que compensar el encabezado no ayudó, ya que el resto del contenido simplemente se quedaría donde estaba. Así que pensé en publicar.

Lo que terminé haciendo fue una combinación de algunas soluciones:

  1. El CSS:

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

Donde "120px" es la altura del encabezado fijo (quizás más un margen)

  1. El enlace del marcador HTML:

    <a href="#01">What is your FAQ question again?</a>
  2. El contenido marcado 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>

Lo bueno de esta solución es que el spanelemento no solo está oculto, sino que está esencialmente colapsado y no rellena su contenido.

No puedo tomar mucho crédito por esta solución, ya que proviene de una gran cantidad de recursos diferentes, pero funcionó mejor para mí en mi situación.

Puedes ver el resultado real aquí .

SteveCinq
fuente
1
¡Muchas gracias por compartir! Por viejo que sea el hilo, todavía no parece haber una solución canónica a este problema.
Tomalak
1
+ SteveCinq Has leído mi mente: me enfrentaba a los mismos problemas en los que las soluciones compartidas no funcionaban según lo previsto. Agregar el <span>con el ancla en el lapso, junto con agregar el relleno y el margen funcionó para mí. ¡Muchas gracias por tomarse el tiempo de enviar esta respuesta a pesar de la antigüedad del hilo!
twknab
4

No tuve suerte con la respuesta mencionada anteriormente y terminé usando esta solución que funcionó perfectamente ...

Cree un espacio en blanco donde desee establecer su ancla.

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

Y aplique la siguiente clase:

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

¡Esta solución funcionará incluso si las secciones tienen fondos de diferentes colores! Encontré la solución en este enlace.

Matt Underwood
fuente
1
¿No es exactamente el mismo método que Guillaume Le Mière y algunos otros han mostrado en este hilo?
Tomalak
Es muy similar, pero creo que es más fácil de entender y una respuesta más detallada con un enlace aún más profundo a una fuente externa.
Matt Underwood el
Es la misma solución, pero puedo entender y seguir esta fácilmente. Los otros no me dieron suficiente información.
MacroMan
3

Para mi mente purista, se siente algo hacky, pero como solución de solo CSS puede agregar relleno al elemento anclado activo usando el :targetselector:

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
fuente
1
¡Eso no es hacky en absoluto! Buena solución
Tomalak
3

Me encontré con que tenía que usar tanto MutttenXd 's y Badabam soluciones CSS s' juntos, como la primera no funcionó en Chrome y el segundo no funcionaba en 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
fuente
3

La forma en que me parece más limpia es la siguiente:

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

Un enfoque mínimamente intrusivo usando jQuery:

Enlace:

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

Contenido:

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

Guión:

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

Al asignar la clase de enlace de anclaje a los enlaces, el comportamiento de otros enlaces (como los acordeones o los controles de tabulación) no se ven afectados.

La pregunta no quiere JavaScript pero la otra pregunta más popular está cerrada debido a esta y no pude responder allí.

Hüseyin Yağlı
fuente
2

Necesitaba algo que funcione para enlaces entrantes, enlaces en la página, Y que JS pueda orientar para que la página pueda responder a los cambios en la altura del encabezado

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;
}

El z-index: -1permite enlaces en el 'área de relleno' por encima de un fragmento de la diana de estar todavía puede hacer clic, como han comentado en @MuttenXd en su respuesta

Todavía no he encontrado un problema en IE 11, Edge 15+, Chrome 38+, FF 52+ o Safari 9.1+

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

Este código debería hacer el truco. Cambia 45 px por la altura de tu barra de encabezado.

EDITAR: si usar jQuery es una opción, también he tenido éxito usando jQuery.localScroll con un conjunto de valores de desplazamiento. La opción de desplazamiento es parte de jQuery.scrollTo, sobre la cual se basa jQuery.localScroll. Una demostración está disponible aquí: http://demos.flesler.com/jquery/scrollTo/ (segunda ventana, debajo de 'desplazamiento')

fourk
fuente
esta solución funciona de hecho, pero no es a prueba de balas y requiere gran cantidad de ajuste fino para diferentes navegadores :( buena oportunidad thoug Estoy buscando una solución sin marcaje adicional..
Vlad Vela a
Es una pena que esto sea tan desordenado, significa que no puedes usar IDs. Me encantaría encontrar una solución, he intentado todo tipo de cosas.
teorizar
1

Aquí hay una solución completa de jquery que funcionará en IE:

Supongamos que los elementos de la barra de navegación son algo como esto:

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

Puede usar el siguiente fragmento de jquery para compensar el desplazamiento:

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

    });
}
Trueno
fuente
Pude usar una versión ligeramente modificada de este código de Thunder. Probé muchas de las soluciones CSS y más simples en esta página y en stackoverflow.com/questions/10732690/… y en stackoverflow.com/questions/10732690/… pero no fueron utilizables debido a mis requisitos. La página es una página de preguntas frecuentes con muchos anclajes para posicionar, tanto dentro como fuera de la página, por lo que podría tener muchos espacios en blanco. Continúa en el próximo comentario ....
Jeffrey Simon
1
Para que funcione para mí, aquí están los cambios menores: (1) cambie "<=" en la línea href.index a "<" para permitir la navegación en la página; (2) cambiar "a.navigation" que tenía que ser "#faq a" para mi uso; (3) cambie var fromTop = 250 a un ternario basado en window.innerWidth para diferencias en dispositivos móviles frente a equipos de escritorio; (4) cambie 400 en el animado a 1, ya que la animación no es deseada y 0 no funciona; (5) agregue if ($ ('my-page-selector'). Length antes de la llamada a offSetScrollFromLocation en la función anónima para evitar llamadas innecesarias en páginas donde no es necesario.
Jeffrey Simon
1

Implementado usando :beforefuncionó muy bien hasta que nos dimos cuenta de que el pseudo elemento en realidad estaba cubriendo y bloqueando los eventos de puntero que se encontraban dentro del área del pseudo elemento. Usar algo como pointer-events: noneel :beforeo incluso directamente en el ancla no tuvo ningún efecto.

Lo que terminamos haciendo fue hacer que la posición del ancla sea absoluta y luego ajustar su posición para que sea el desplazamiento / altura del área fija.

Ancla de desplazamiento sin bloquear eventos de puntero

.section-marker {

    position: absolute;
    top: -300px;
}

El valor con esto es que no estamos bloqueando ningún elemento que pueda caer dentro de esos 300px. La desventaja es que tomar la posición de ese elemento de Javascript debe tener en cuenta ese desplazamiento, por lo que cualquier lógica allí tuvo que ser ajustada.

skabob11
fuente
1

Así es como lo hice para finalmente ir al lugar apropiado cuando haces clic en la navegación. Agregué un controlador de eventos para los clics de navegación. Luego puede usar "scrollBy" para moverse hacia arriba en el desplazamiento.

var offset = 90;

 $('.navbar li a').click(function(event) {
    event.preventDefault();
    $($(this).attr('href'))[0].scrollIntoView();
    scrollBy(0, -offset);
 });
Mile Mijatović
fuente
2
Resuelve el problema, pero no la parte "sin la ayuda de Javascript" ...
Tomalak
1

Creé un div con algunos saltos de línea y le di la identificación, luego puse el código que quería mostrar debajo. El enlace lo llevaría al espacio sobre la imagen y el encabezado ya no estaría en el camino:

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

Por supuesto, puede cambiar el número de saltos de línea para satisfacer sus necesidades. Esto funcionó perfectamente para mí, aunque no estoy seguro si hay algún problema, todavía estoy aprendiendo HTML.

Anónimo
fuente
Pragmático, pero hay un inconveniente: solo funciona para el primer encabezado de una página. Si hay más encabezados, comenzará a ver grandes espacios en el texto debido a las <br>etiquetas antes de cada encabezado.
Tomalak
1

Usó este script

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

    $('html, body').animate({
        scrollTop: $($.attr(this, 'href')).offset().top -140
    }, 1000);
});
Aadil Memon
fuente
Intenta explicar por qué crees que este script resolvería el problema
Ali Kanat
1

Creo que este enfoque es más útil:

<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
fuente