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

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

есть ли способ использовать якорь 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    |
| ...                             |      | ...                             |
+---------------------------------+      +---------------------------------+

26 ответов


у меня была та же проблема. Я решил это, добавив класс к элементу anchor с высотой верхней панели в качестве значения 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);

Я использую такой подход:

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


Официальный Бутстрэп Принял Ответ:

*[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, когда вы хотите использовать фрагмент ссылки, входящие в С других страниц.

so calling 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.


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

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

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


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

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

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

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

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

привязки HTML:

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

CSS:

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

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

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

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

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

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


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

.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-единственного решения вы можете добавить дополнение к активному якорному элементу с помощью :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;
  }

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

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

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

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

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


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

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

минимально интрузивный подход с использованием 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;
});

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

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


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

этот код должен делать трюк. Замените 45px на высоту панели заголовка.

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


вот полное решение 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) {

    });
}

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

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

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

.section-marker {

    position: absolute;
    top: -300px;
}

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


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

var offset = 90;

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

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

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

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.
  • bootstrap версия: 3.3.7

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


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

см.https://codepen.io/pikeshmn/pen/mMxEdZ

подход: мы получаем высоту фиксированной навигации с помощью документ.метода getElementById('заголовок').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;
  });

П. С.:

  • оно включает славную разницу в 5 пикселов между заголовок и текст!--17-->
  • эффект прокрутки не жесткий, а гладкий; плавная прокрутка

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

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

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

    .paddingtop{ 
       padding-top: 90px; 
     }

очень простой ответ CSS только поставить это в верхней части таблицы стилей:

a{padding-top: 90px;}
a:link{padding-top: unset;}

первый стиль регулирует все теги привязки, где второй стиль привязывает теги с гиперссылкой.

Примечание: В настоящее время это работает в Firefox и Edge, но не в Chrome.