O cabeçalho da página fixo sobrepõe as âncoras na página

358

Se eu tiver um cabeçalho sem rolagem em uma página HTML, fixo na parte superior, com uma altura definida:

Existe uma maneira de usar a âncora da URL (a #fragmentparte) para fazer o navegador rolar para um determinado ponto da página, mas ainda respeitar a altura do elemento fixo sem a ajuda do JavaScript ?

http://foo.com/#bar
ERRADO (mas o comportamento comum): CORRETO:
+ --------------------------------- + + -------------- ------------------- +
| BAR ///////////////////// header | | //////////////////////// header |
+ --------------------------------- + + -------------- ------------------- +
| Aqui está o resto do texto | | BAR
| ... | |
| ... | Aqui está o resto do texto |
| ... | ...
+ --------------------------------- + + -------------- ------------------- +
Tomalak
fonte
3
@ax SIM, essa é a melhor resposta. Verifique também nicolasgallagher.com/jump-links-and-viewport-positioning/demo dentro dele. Isso funcionou melhor para mim:.dislocate50px, #bar { padding: 50px 0 0; margin: -50px 0 0; -webkit-background-clip: content-box; background-clip: content-box; }
flen
Estou procurando uma solução que * funcione para âncoras vindas da mesma página ou de outra página * e que ajusta o pressionamento de tecla da página para baixo para que o conteúdo não seja cortado pelo cabeçalho * e que permita que o rodapé sib-div role para cima com content-div. Ainda não encontrou uma solução! Mas devo dizer, acho que o caminho certo teria como alvo todo o conteúdo div, e não cada âncora individual. stackoverflow.com/questions/51070758/…
johny why
@machado. CSS-tricks.com tem um artigo muito melhor e mais recente scroll-padding-topaqui: css-tricks.com/… Resposta correspondente: stackoverflow.com/a/56467997/247696
Flimm

Respostas:

167

Eu tive o mesmo problema. Eu o resolvi adicionando uma classe ao elemento anchor com a altura da barra superior como o valor de padding-top.

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

E então simplesmente o css:

.anchor { padding-top: 90px; }
MutttenXd
fonte
19
@Tomalak Esteja ciente de que esta solução torna os links dentro da área de preenchimento não clicáveis. Para corrigir isso, você deve usar o z-index e definir o valor dos links mais alto que o da âncora. Lembre-se de que a barra superior deve ter o valor mais alto do índice z, para que o conteúdo da página não flutue na parte superior da barra superior quando você rolar.
MutttenXd #
Não funcionou no Chrome v28 devido a um erro de posição fixa do WebKit que fazia o cabeçalho desaparecer. Esta resposta fez o truque no meu caso.
precisa saber é o seguinte
2
MuttenXd .. você é meu herói. Eu tive um problema estranho de link que não funcionava no meu site (não relacionado a âncoras) me deixando louca. Seu comentário não clicável realmente ajudou. Eu devo muito a você!
zipzit
9
Conforme sugerido na resposta de Roy Shoa, adicione margin-top: -90px;para compensar a lacuna criada pelo preenchimento.
Skippy le Grand Gourou
37
Eu usei .anchor:target {padding-top: 90px;}para que ele só adicionasse o preenchimento quando eles usassem a marca de âncora. Dessa forma, nem sempre há um monte de preenchimento se a página carregar na parte superior. Somente quando ele carrega um ponto específico mais baixo na página.
Jimmyplaysdrums # 4/15
265

Se você não pode ou não deseja definir uma nova classe, adicione um ::beforepseudo-elemento de altura fixa à :targetpseudo-classe em CSS:

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

Ou role a página em relação ao :targetjQuery:

var offset = $(':target').offset();
var scrollto = offset.top - 60; // minus fixed header height
$('html, body').animate({scrollTop:scrollto}, 0);
Adrian Garner
fonte
30
Eu realmente gosto da sua solução. É a solução mais limpa que encontrei.
Itay Grudev
5
Esta é a solução que funcionou perfeitamente para mim sem encher mais nada no layout da minha página.
Jamie Carl
2
A solução CSS tem um problema quando usado com a lista no WebKit. Veja como: stackoverflow.com/questions/39547773/…
Mert S. Kaplan
14
Não funcionará se o destino tiver preenchimento ou borda superior, pois depende do colapso da margem.
precisa saber é o seguinte
9
:targetfoi simplesmente brilhante!
Endless
125

Eu uso essa abordagem:

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

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

Ele adiciona um elemento invisível antes de cada destino. Funciona com o IE8 +.

Aqui estão mais soluções: http://nicolasgallagher.com/jump-links-and-viewport-positioning/

Jeremias Erbs
fonte
olhar para o link Badabam desde que, há uma segunda solução, que eu uso e que funciona no Chrome e Firefox
limpador
Testei isso no Firefox mais recente (55.0.3 no PC) e funciona agora. :-)
RachieVee 4/17/17
46

Resposta adotada pelo Bootstrap oficial:

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

Créditos

Mesclar

blnc
fonte
11
Muito obrigado por incluir isso, +1 pela integridade.
amjoconn
2
Esta solução tem um problema quando usada com a lista no WebKit. Veja como: stackoverflow.com/questions/39547773/…
Mert S. Kaplan
Observe que isso não funcionará se o próprio elemento de destino tiver display: flex;ou padding-top. Use um elemento âncora dedicado (como <a name="my_link">{leave this empty}</a>) nesses casos.
precisa saber é o seguinte
Isso não funcionará se o elemento de destino for <tr>
Ivan Gusev
42
html {
  scroll-padding-top: 70px; /* height of sticky header */
}

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

François Romain
fonte
Funciona para mim. Estou navegando para a âncora de outra página. Outros não funcionaram. Obrigado!
Davidloper 6/12/19
11
Isso não funciona para rolar a página inteira no Edge e Safari ( bugs.webkit.org/show_bug.cgi?id=179379 ).
Juliusz Gonera
11
Salvador! Simples, no ponto. Nenhuma das outras soluções funcionou para mim porque estou usando o display: flex. Muito obrigado, foi muito frustrante tentar todas as soluções.
Priya Payyavula 31/03
Esta é uma solução BONITA, usei o comportamento de rolagem: suave! Importante; também para ancorar, realmente simples em duas linhas de código
yehanny
30

A melhor maneira que encontrei para lidar com esse problema é (substitua 65px pela altura fixa do elemento):

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

Se você não gosta de usar o seletor de destino, também pode fazê-lo desta maneira:

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

Nota: este exemplo não funcionará se o elemento de destino tiver uma cor de fundo diferente do pai. por exemplo:

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

nesse caso, a cor verde do elemento my-target substituirá o elemento vermelho pai em 65px. Não encontrei nenhuma solução CSS pura para lidar com esse problema, mas se você não tiver outra cor de plano de fundo, essa solução é a melhor.

Roy Shoa
fonte
2
De todas as respostas, esta é a única que funcionou para mim!
Javier Arias
18

Embora algumas das soluções propostas funcionem para links de fragmentos (= links de hash) na mesma página (como um link de menu que rola para baixo), descobri que nenhuma delas funcionava no Chrome atual quando você deseja usar links de fragmentos provenientes de outros sites. Páginas .

Assim, ligar para www.mydomain.com/page.html#foo do zero NÃO compensará seu destino no Chrome atual com nenhuma das soluções CSS ou JS fornecidas.

Há também um relatório de bug do jQuery descrevendo alguns detalhes do problema.

SOLUÇÃO

A única opção que encontrei até agora que realmente funciona no Chrome é o JavaScript que não é chamado onDomReady, mas com um atraso.

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

RESUMO

Sem um atraso de JS, as soluções provavelmente funcionarão no Firefox, IE, Safari, mas não no Chrome.

Jpsy
fonte
3
Cheguei à mesma conclusão e solução. Parece que todo mundo está esquecendo os links externos que usam as hashtags.
AJJ 13/07
Eu tenho esse problema hoje e usei sua solução. Embora pareça que você não precisa de tempo limite. Isso funciona como IIFE também.
precisa saber é o seguinte
11
@ kwiat1990: Sim, isso pode ser possível - mas apenas se o seu JS for colocado no final do código HTML. Caso contrário, seu destino de rolagem talvez ainda não esteja no DOM. Na verdade, esse é o objetivo de usar o onDomReady. Então acho que a versão do timeout é o caminho estável a seguir.
precisa saber é o seguinte
Essa resposta foi a única que funcionou para links externos. No entanto ele não funciona para mim quando o link é chamado na mesma página :( Alguma idéia?
Augusto Samamé Barrientos
@Augusto, você encontrou uma solução? Eu estou tendo o mesmo problema.
Jesse
9

Como a especificação CSS Scroll Snap entra em jogo, é facilmente possível com a scroll-margin-toppropriedade. Atualmente, é executado no Chrome e Opera (abril de 2019). Além disso, o Safari 11+ deve suportar isso, mas não consegui executá-lo no Safari 11. Provavelmente, temos que esperar que os caras o consertem.

Exemplo 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
fonte
11
Isso é muito fofo. Vamos torcer para que seja adotado mais amplamente!
amigos estão
Qual é a diferença entre scroll-padding-tope scroll-margin-top?
Flimm
scroll-margin-toppara este caso de uso, infelizmente, não está implementado no Safari 11-13: bugs.webkit.org/show_bug.cgi?id=189265
fabb
No Safari, ele é chamado scroll-snap-margin-top: caniuse.com/#search=scroll-margin-top
Mu-Tsun Tsai
@ Mu-TsunTsai É um pouco mais complicado. Isso realmente existe no Safari, mas não funciona com o comportamento de rolagem para fragmento. Veja meu comentário na edição de dados compatíveis
dakur
8

No Chrome / Safari / Firefox, você pode adicionar um display: blocke usar uma margem negativa para compensar o deslocamento, como:

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

Veja o exemplo http://codepen.io/swed/pen/RrZBJo

MrSwed
fonte
7

Você pode fazer isso com o jQuery:

var offset = $('.target').offset();
var scrollto = offset.top - 50; // fixed_top_bar_height = 50px
$('html, body').animate({scrollTop:scrollto}, 0);
webvitaly
fonte
Não ".target", deve ser ": target"
Mert S. Kaplan
@ MertS.Kaplan ".target" é a classe 'target'.
Webvitaly
7

Acabei de descobrir outra solução CSS pura que funcionou como um charme para mim!

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

Encontrado neste site !

jamawe
fonte
2
Algumas outras pessoas descobriram essa solução antes de você. Consulte as respostas na página 1, por exemplo, stackoverflow.com/a/56467997/18771
Tomalak
Desculpe, não percebi! Obrigado!
jamawe 10/12/19
Isso não funciona para rolar a página inteira no Edge e Safari ( bugs.webkit.org/show_bug.cgi?id=179379 ).
Juliusz Gonera
5

Você pode tentar o seguinte:

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

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

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

Defina o valor do preenchimento superior para a altura real do seu cabeçalho. Isso introduzirá um pequeno espaço extra na parte superior do cabeçalho, mas só será visível quando o usuário pular para a âncora e depois rolar para cima. Eu criei essa solução para o meu site agora, mas ela mostra apenas uma pequena barra fixa na parte superior da página, nada muito alto.

ygoe
fonte
Mh. Não é ruim, mas ainda assim um hack (e não funciona no IE, infelizmente).
28812 Tomalak
5

Eu tenho que trabalhar facilmente com CSS e HTML, usando o método "anchor: before" mencionado acima. Eu acho que funciona melhor, porque não cria preenchimento maciço entre seus divs.

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

Parece não funcionar para a primeira div da página, mas você pode combater isso adicionando preenchimento à primeira div.

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

Aqui está um violino de trabalho: http://jsfiddle.net/FRpHE/24/

Eric Wood
fonte
5

Funciona para mim:

LINK HTML para ancorar:

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

Âncora HTML:

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

CSS:

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

Estou usando a resposta do @ Jpsy, mas por razões de desempenho, só estou configurando o timer se o hash estiver presente no 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
fonte
O OP pediu para não usar javascript.
Giulio Caccin
Funciona com links externos, mas não com links in-page.
snap
4

Eu tive muitos problemas com muitas das respostas aqui e em outros lugares, pois minhas âncoras marcadas eram cabeçalhos de seção em uma página de Perguntas frequentes, portanto, compensar o cabeçalho não ajudou, pois o restante do conteúdo simplesmente permaneceu onde estava. Então eu pensei em postar.

O que acabei fazendo foi um composto de algumas soluções:

  1. O CSS:

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

Onde "120px" é a altura fixa do cabeçalho (talvez mais alguma margem).

  1. O link do marcador HTML:

    <a href="#01">What is your FAQ question again?</a>
  2. O conteúdo marcado como 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>

O bom dessa solução é que o spanelemento não está apenas oculto, é essencialmente recolhido e não preenche seu conteúdo.

Não posso ter muito crédito por esta solução, pois ela provém de vários recursos diferentes, mas funcionou melhor para mim na minha situação.

Você pode ver o resultado real aqui .

SteveCinq
fonte
11
Muito obrigado por compartilhar! Por mais antiga que seja a discussão, ainda não parece haver uma solução canônica para esse problema.
Tomalak
11
+ SteveCinq Você leu minha opinião - eu estava enfrentando os mesmos problemas em que as soluções compartilhadas não estavam funcionando como previsto. Adicionando no <span>com a âncora no período, juntamente com a adição de preenchimento e margem funcionou para mim. Muito obrigado por reservar um tempo para enviar esta resposta, apesar da idade do tópico!
twknab
4

Eu não estava tendo sorte com a resposta listada acima e acabei usando esta solução que funcionou perfeitamente ...

Crie um espaço em branco onde deseja definir sua âncora.

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

E aplique a seguinte classe:

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

Esta solução funcionará mesmo se as seções tiverem fundos coloridos diferentes! Encontrei a solução neste link.

Matt Underwood
fonte
11
Não é exatamente o mesmo método que Guillaume Le Mière e alguns outros mostraram neste tópico?
amigos estão
É muito parecido, mas acho que é mais fácil de entender e uma resposta mais detalhada com um link ainda mais aprofundado para uma fonte externa.
Matt Underwood
É a mesma solução, mas eu posso entender e seguir essa facilmente. Os outros não me deram informações suficientes.
MacroMan
3

Parece um pouco hacky para minha mente purista, mas como uma solução somente em CSS, você pode adicionar preenchimento ao elemento ancorado ativo usando o :targetseletor:

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
fonte
11
Isso não é hacky! Ótima solução.
amigos estão
3

Eu descobri que eu tinha que usar tanto MutttenXd 's e Badabam ' soluções CSS s juntos, como o primeiro não funcionou no Chrome eo segundo não funcionou no 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
fonte
3

A maneira que eu acho mais limpa é a seguinte:

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

Uma abordagem minimamente invasiva usando jQuery:

Ligação:

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

Conteúdo:

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

Roteiro:

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

Ao atribuir a classe de link âncora aos links, o comportamento de outros links (como controles de acordeão ou tabulação) não é afetado.

A pergunta não quer javascript, mas a outra pergunta mais popular está encerrada por causa dessa e não pude responder lá.

Hüseyin Yağlı
fonte
2

Eu precisava de algo que funcione para links de entrada, links na página E que possa ser direcionado por JS, para que a página possa responder a alterações na altura do cabeçalho

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

Ele z-index: -1permite que os links na 'área de preenchimento' acima de um alvo de fragmento ainda sejam clicáveis, como comentado por @MuttenXd em sua resposta

Ainda não encontrei um problema no IE 11, Edge 15+, Chrome 38+, FF 52+ ou Safari 9.1+

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

Este código deve fazer o truque. Troque 45 px pela altura da barra de cabeçalho.

Edição: Se usando jQuery é uma opção, eu também tive sucesso usando jQuery.localScroll com um valor de deslocamento definido. A opção de deslocamento faz parte do jQuery.scrollTo, sobre o qual o jQuery.localScroll se baseia. Uma demonstração está disponível aqui: http://demos.flesler.com/jquery/scrollTo/ (segunda janela, em 'deslocamento')

fourk
fonte
esta solução funciona de fato, mas não é à prova de balas e que exige muita ajuste fino para diferentes navegadores :( boa thoug tentativa Estou à procura de uma solução sem marcação extra..
Vlad saling
Pena que isso é tão complicado, significa que você não pode simplesmente usar IDs. Gostaria de encontrar uma solução, eu tentei todos os tipos de coisas.
teorise
1

Aqui está uma solução jquery completa que funcionará no IE:

Suponha que os elementos da barra de navegação sejam algo assim:

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

Você pode usar o seguinte snippet de jquery para deslocar a rolagem:

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

    });
}
Trovão
fonte
Consegui usar uma versão ligeiramente modificada desse código do Thunder. Tentei muitas das soluções mais simples e somente CSS nesta página e em stackoverflow.com/questions/10732690/… e em stackoverflow.com/questions/10732690/…, mas elas não eram utilizáveis ​​devido aos meus requisitos. A página é uma página de Perguntas frequentes com muitas âncoras para posicionar, dentro e fora da página, portanto, pode haver muitos espaços em branco. Continua no próximo comentário ....
Jeffrey Simon
11
Para que funcione para mim, eis as pequenas alterações: (1) altere "<=" na linha href.index para "<" para permitir a navegação na página; (2) alterar "a.navigation" que precisava ser "#faq a" para meu uso; (3) altere var deTop = 250 para um ternário com base em window.innerWidth para diferenças entre dispositivos móveis e computadores; (4) altere 400 no animado para 1, pois a animação não é desejada e 0 não funciona; (5) add if ($ ( 'my-page-selector') Comprimento antes da chamada para offSetScrollFromLocation na função anônima para evitar chamadas desnecessárias em páginas onde não são necessários..
Jeffrey Simon
1

Implementado usando :beforefuncionou muito bem até que percebemos que o pseudo-elemento estava realmente cobrindo e bloqueando eventos de ponteiro localizados na área do pseudo-elemento. Usar algo como pointer-events: nonena :beforeâncora ou mesmo diretamente na âncora não afetou.

O que acabamos fazendo foi tornar o posicionamento da âncora absoluto e, em seguida, ajustar sua posição para ser o deslocamento / altura da área fixa.

Deslocar âncora sem bloquear eventos de ponteiro

.section-marker {

    position: absolute;
    top: -300px;
}

O valor disso é que não estamos bloqueando nenhum elemento que possa estar dentro desses 300px. A desvantagem é que a captura da posição desse elemento do Javascript precisa levar em conta esse deslocamento, para que qualquer lógica tenha que ser ajustada.

skabob11
fonte
1

Foi assim que finalmente cheguei ao local apropriado quando você clica na navegação. Eu adicionei um manipulador de eventos para os cliques de navegação. Então você pode simplesmente usar "scrollBy" para subir no deslocamento.

var offset = 90;

 $('.navbar li a').click(function(event) {
    event.preventDefault();
    $($(this).attr('href'))[0].scrollIntoView();
    scrollBy(0, -offset);
 });
Mile Mijatović
fonte
2
Resolve o problema, mas não a parte "sem a ajuda de Javascript" ...
Tomalak
1

Criei uma div com algumas quebras de linha e dei esse ID, depois coloquei o código que queria mostrar por baixo. O link levaria você ao espaço acima da imagem e o cabeçalho não estaria mais no caminho:

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

Obviamente, você pode alterar o número de quebras de linha para atender às suas necessidades. Isso funcionou perfeitamente para mim, mas não tenho certeza se há algum problema, ainda estou aprendendo HTML.

Anônimo
fonte
Pragmático, mas há uma desvantagem - só funciona no primeiro título de uma página. Se houver mais títulos, você começará a ver grandes lacunas no texto devido às <br>tags antes de cada título.
precisa
1

Utilizou este script

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

    $('html, body').animate({
        scrollTop: $($.attr(this, 'href')).offset().top -140
    }, 1000);
});
Aadil Memon
fonte
Por favor, tente explicar por que você acha que esse script resolveria o problema
Ali Kanat
1

Eu acho que essa abordagem é mais ú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
fonte