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

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

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

http://foo.com/#bar
WRONG (but the common behavior):         CORRECT:
+---------------------------------+      +---------------------------------+
| BAR///////////////////// header |      | //////////////////////// header |
+---------------------------------+      +---------------------------------+
| Here is the rest of the Text    |      | BAR                             |
| ...                             |      |                                 |
| ...                             |      | Here is the rest of the Text    |
| ...                             |      | ...                             |
+---------------------------------+      +---------------------------------+

Ответы

Ответ 1

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

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

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

.anchor { padding-top: 90px; }

Ответ 2

Если вы не хотите или не хотите устанавливать новый класс, добавьте псевдоним элемента fixed-height ::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);

Ответ 3

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

/* 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/

Ответ 4

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

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

Кредиты

Объединить

Ответ 5

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

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

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

.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 для решения этой проблемы, но если у вас нет другого цвета фона, это решение является лучшим.

Ответ 6

В то время как некоторые из предложенных решений работают для фрагментных ссылок (= хеш-ссылки) внутри на той же странице (например, ссылку на меню, которая прокручивается вниз), я обнаружил, что ни один из них не работал в текущем 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.

Ответ 7

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

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

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

Ответ 8

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

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

Ответ 9

Вы можете попробовать следующее:

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

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

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

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

Ответ 10

Это работает для меня:

HTML LINK to Anchor:

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

HTML Якорь:

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

CSS:

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

Ответ 11

Я легко работаю с 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/

Ответ 12

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

Ответ 13

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

Ответ 14

Я использую @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();
      }
  };

Ответ 15

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

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

Ответ 16

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

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

  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 не только скрыт, он, по сути, свернут и не дополняет ваш контент.

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

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

Ответ 17

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

Ответ 18

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

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

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

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

Ответ 19

Мне нужно что-то, что работает для входящих ссылок, ссылок на странице, и что может быть нацелено на 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+

Ответ 20

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

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

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

Ответ 21

Вот полное jquery-решение, которое будет работать в IE:

Предположим, что элементы панели навигации выглядят примерно так:

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

Вы можете использовать следующий фрагмент jquery для смещения прокрутки:

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

    });
}

Ответ 22

Реализовано с использованием :before отлично работало, пока мы не поняли, что псевдоэлемент фактически перекрывал и блокировал события указателя, которые находились в области псевдоэлемента. Использование чего-то типа pointer-events: none на :before или даже прямо на якоре не повлияло.

В результате мы сделали абсолютное позиционирование анкера, а затем установили его положение как смещение/высоту фиксированной области.

Смещение анкера без блокировки событий указателя

.section-marker {

    position: absolute;
    top: -300px;
}

Значение с этим заключается в том, что мы не блокируем какие-либо элементы, которые могут упасть в пределах этих 300 пикселей. Недостатком является то, что захват этой позиции элемента из Javascript должен учитывать это смещение, поэтому любая логика должна быть скорректирована.

Ответ 23

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

var offset = 90;

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

Ответ 24

Я создал div с несколькими переносами строк и дал идентификатор, а затем поместил код, который хотел показать ниже. Затем ссылка приведет вас к месту над изображением, и заголовок больше не будет мешать:

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

Конечно, вы можете изменить количество разрывов строк в соответствии с вашими потребностями. Это отлично сработало для меня, но я не уверен, что есть какие-то проблемы, но я все еще изучаю HTML.

Ответ 25

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

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

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

Ответ 26

Когда в игру вступает спецификация 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 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 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>

Ответ 27

Добавьте класс с "paddingtop", чтобы он работал;)

<h1><a class="paddingtop">Bar</a></h1>

И для CSS у вас есть:

.paddingtop { 
   padding-top: 90px; 
}

Ответ 28

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

Ответ 29

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

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

Замените раздел классом, если хотите.

источник: Переместить ссылки и расположение в окне просмотра

  • Протестировано на Firefox 45 и Chrome 52.
  • Загрузочная версия: 3.3.7

Для тех, кто мне не верит, я любезно подготовил jsfiddle с решением: SOLUTION

Ответ 30

Трюк CSS будет обходным путем. Правильное решение, которое будет работать во всех сценариях, может быть реализовано с помощью jQuery.

Обратитесь к https://codepen.io/pikeshmn/pen/mMxEdZ

Подход: Мы получаем высоту фиксированного nav, используя 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:

  • Он включает в себя приятную 5-кратную разницу между заголовком и целью
  • Эффект прокрутки не является сложным, довольно гладким; Гладкая прокрутка