Исправлено перекрытие заголовка страницы внутри якоря страницы

Если у меня есть HTML-страница без прокрутки, прикрепленная к вершине с определенной высотой:

Есть ли способ использовать привязку URL (#fragment частично) чтобы браузер прокручивал до определенной точки на странице, но все же учитывал высоту фиксированного элемента без помощи JavaScript?

http://foo.com/#bar
НЕПРАВИЛЬНО (но обычное поведение): ПРАВИЛЬНО:
+---------------------------------+      +---------------------------------+
| БАР ///////////////////// header |      | //////////////////////// header |
+---------------------------------+      +---------------------------------+
| Вот остальная часть текста | | БАР |
|... | | |
|... | | Вот остальная часть текста |
|... | |... |
+ --------------------------------- + + -------------- ------------------- +

39 ответов

Решение

У меня такая же проблема. Я решил это, добавив класс к элементу привязки с высотой верхней панели в качестве значения padding-top.

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

А потом просто CSS:

.anchor { padding-top: 90px; }

Если вы не можете или не хотите устанавливать новый класс, добавьте фиксированную высоту ::before псевдоэлемент к :target псевдокласс в CSS:

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

Или прокрутите страницу относительно :target с помощью jQuery:

var offset = $(':target').offset();
var scrollto = offset.top - 60; // minus fixed header height
$('html, body').animate({scrollTop:scrollto}, 0);
html {
  scroll-padding-top: 70px; /* height of sticky header */
}

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

Я использую этот подход:

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

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

Он добавляет невидимый элемент перед каждой целью. Работает IE8+.

Вот больше решений: http://nicolasgallagher.com/jump-links-and-viewport-positioning/

Поскольку в игру входит спецификация CSS Scroll Snap, это легко scroll-margin-top имущество. В настоящее время работает на Chrome и Opera (апрель 2019). Также Safari 11+ должен поддерживать это, но я не смог запустить его на Safari 11. Вероятно, нам нужно подождать, пока парни не исправят это.

Пример 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>

Официальный ответ Bootstrap принят:

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

кредиты

сливаться

Лучший способ, который я нашел, чтобы решить эту проблему (заменить 65px с фиксированной высотой элемента):

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

Если вам не нравится использовать целевой селектор, вы также можете сделать это следующим образом:

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

Примечание: этот пример не будет работать, если целевой элемент имеет цвет фона, который отличается от его родителя. например:

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

в этом случае зеленый цвет элемента my-target перезапишет его родительский красный элемент в 65px. Я не нашел ни одного чистого CSS-решения для решения этой проблемы, но если у вас нет другого цвета фона, это решение будет лучшим.

Хотя некоторые из предложенных решений работают с фрагментными ссылками (= хэш-ссылками) на одной и той же странице (например, ссылка меню, которая прокручивается вниз), я обнаружил, что ни одна из них не работает в текущем Chrome, если вы хотите использовать фрагментированные ссылки, поступающие из других страницы

Поэтому вызов www.mydomain.com/page.html#foo с нуля НЕ сместит вашу цель в текущем Chrome ни с одним из указанных CSS-решений или JS-решений.

Существует также отчет об ошибке jQuery, описывающий некоторые детали проблемы.

РЕШЕНИЕ

Единственный вариант, который я нашел, который действительно работает в Chrome, - это JavaScript, который не вызывается onDomReady, но с задержкой.

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

РЕЗЮМЕ

Без задержки JS решения, вероятно, будут работать в Firefox, IE, Safari, но не в Chrome.

Теперь вы можете использовать scroll-margin-top, что довольно широко распространено.

Просто добавьте следующий CSS к элементу, к которому вы хотите перейти:

.element {
  scroll-margin-top: 2em;
}

Я не видел возможности просто использовать :target в качестве опции. я нашел это

:target { margin-top: -100px; padding-top: 100px; }

похоже, работает в предоставленном сценарии. :target также совместим со всеми современными браузерами. https://caniuse.com/?search=%3Atarget

Для Chrome/Safari/Firefox вы можете добавить display: block и использовать отрицательное поле для компенсации смещения, например:

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

Смотрите пример http://codepen.io/swed/pen/RrZBJo

Я легко работал с CSS и HTML, используя метод "anchor:before", упомянутый выше. Я думаю, что это работает лучше всего, потому что это не создает массового заполнения между вашими div.

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

Похоже, что это не работает для первого div на странице, но вы можете противостоять этому, добавив отступ к этому первому div.

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

Вот рабочая скрипка: http://jsfiddle.net/FRpHE/24/

Только что открыл для себя еще одно решение на чистом CSS, которое мне очень понравилось!

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

Нашел на этом сайте!

Вы можете сделать это с помощью jQuery:

var offset = $('.target').offset();
var scrollto = offset.top - 50; // fixed_top_bar_height = 50px
$('html, body').animate({scrollTop:scrollto}, 0);

Вы можете попробовать это:

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

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

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

Установите верхнее значение отступа к фактической высоте вашего заголовка. Это создаст небольшой дополнительный пробел в верхней части заголовка, но он будет виден только тогда, когда пользователь переходит на якорь и затем прокручивается вверх. Я разработал это решение для своего сайта прямо сейчас, но он показывает только небольшую фиксированную полосу в верхней части страницы, ничего слишком высокого.

Мне не повезло с ответом, перечисленным выше, и я решил использовать это решение, которое отлично сработало...

Создайте пустой промежуток, где вы хотите установить свой якорь.

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

И применить следующий класс:

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

Это решение будет работать, даже если разделы имеют разноцветный фон! Я нашел решение по этой ссылке.

Я решаю свою проблему с помощью свойства scroll-margin-top для элемента привязки

      scroll-margin-top: 100px;

https://developer.mozilla.org/en-US/docs/Web/CSS/scroll-margin-top

Меня устраивает:

HTML-ссылка на якорь:

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

Якорь HTML:

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

CSS:

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

У меня было много проблем со многими ответами здесь и в других местах, так как якорями, отмеченными закладками, были заголовки разделов на странице часто задаваемых вопросов, поэтому смещение заголовка не помогло, так как остальная часть контента просто осталась бы на своем месте. Так что я думал, что отправлю.

То, что я закончил, было составом из нескольких решений:

  1. CSS:

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

Где "120px" - это ваша фиксированная высота заголовка (возможно, плюс некоторое поле).

  1. Ссылка на закладку HTML:

    <a href="#01">What is your FAQ question again?</a>

  2. Содержимое закладок 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>

Хорошая вещь об этом решении состоит в том, что span элемент не только скрыт, он по сути свернут и не дополняет ваш контент.

Я не могу много доверять этому решению, так как оно исходит от множества различных ресурсов, но в моей ситуации оно сработало лучше всего.

Вы можете увидеть фактический результат здесь.

Я использую ответ @Jpsy, но по соображениям производительности я устанавливаю таймер только в том случае, если в 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();
      }
  };

Мне кажется, что это немного странно, но в качестве решения только для css вы можете добавить заполнение к активному привязанному элементу, используя :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>

Путь, который я считаю самым чистым, следующий:

  #bar::before {
    display: block;
    content: " ";
    margin-top: -150px;
    height: 150px;
    visibility: hidden;
    pointer-events: none;
  }

Я обнаружил, что должен был использовать CSS-решения как MutttenXd, так и Badabam, так как первое не работало в Chrome, а второе не работало в 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>
...

Минимально навязчивый подход с использованием jQuery:

Ссылка на сайт:

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

Содержание:

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

Автор сценария:

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

При назначении ссылочного класса якорной ссылки на поведение других ссылок (например, аккордеона или элементов управления вкладками) это не влияет.

Вопрос не нуждается в javascript, но другой более популярный вопрос закрыт из-за этого, и я не смог ответить на него.

Мне нужно что-то, что работает для входящих ссылок, ссылок на странице, и что может быть нацелено на JS, чтобы страница могла реагировать на изменения высоты заголовка

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

z-index: -1 позволяет ссылкам в "области заполнения" над целевым фрагментом по-прежнему нажиматься, как прокомментировал @MuttenXd в своем ответе

Я еще не нашел проблему в IE 11, Edge 15+, Chrome 38+, FF 52+ или Safari 9.1+

Вот так я и получил, чтобы наконец перейти в нужное место при нажатии на навигацию. Я добавил обработчик событий для кликов навигации. Тогда вы можете просто использовать "scrollBy" для перемещения вверх по смещению.

var offset = 90;

 $('.navbar li a').click(function(event) {
    event.preventDefault();
    $($(this).attr('href'))[0].scrollIntoView();
    scrollBy(0, -offset);
 });

Думаю, такой подход более полезен:

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

Использовал этот скрипт

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

    $('html, body').animate({
        scrollTop: $($.attr(this, 'href')).offset().top -140
    }, 1000);
});

Простой и легкий способ, добавивscroll-padding-topсвойство, чтобы решить эту проблему, просто добавьте этот код в свой файл CSS и увидите волшебство.

для динамических переменных высоты и зазора

      html {   
    --headerHeight:79px;   
    --gap:40px;   
    scroll-padding-top: calc(var(--headerHeight) + var(--gap)); 
}

для фиксированного значения зазора

      html { 
    scroll-padding-top: 120px; 
}
<div style="position:relative; top:-45px;">
    <a name="fragment"> </a>
</div>

Этот код должен сделать свое дело. Поменяйте 45px на высоту панели заголовка.

РЕДАКТИРОВАТЬ: Если использование jQuery является опцией, я также успешно использовал jQuery.localScroll с установленным значением смещения. Опция смещения является частью jQuery.scrollTo, на которой построен jQuery.localScroll. Демо-версия доступна здесь: http://demos.flesler.com/jquery/scrollTo/ (второе окно, в разделе "смещение")

Другие вопросы по тегам