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

124

Я не уверен, как лучше всего задать / найти этот вопрос:

Когда вы нажимаете якорную ссылку, она переносит вас в тот раздел страницы, где связанная область теперь находится ОЧЕНЬ ВЕРХНЕЙ страницы. Я хочу, чтобы якорная ссылка отправляла меня в эту часть страницы, но мне нужно немного места вверху. То есть, я не хочу, чтобы он отправлял меня в связанную часть с ним в ОЧЕНЬ ВЕРХНЕМУ, я бы хотел, чтобы там было около 100 пикселей.

Имеет ли это смысл? Это возможно?

Отредактировано для отображения кода - это просто тег привязки:

<a href="#anchor">Click me!</a>

<p id="anchor">I should be 100px below where I currently am!</p>
Дэймон
источник
Дублирование? stackoverflow.com/questions/11386807/…
XCS
Связанный: stackoverflow.com/questions/4086107/…
flen

Ответы:

158
window.addEventListener("hashchange", function () {
    window.scrollTo(window.scrollX, window.scrollY - 100);
});

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

РЕДАКТИРОВАТЬ 1:

Как было указано @erb, это работает только в том случае, если вы находитесь на странице во время изменения хеша. Вход на страницу с #somethingуже в URL не работает с приведенным выше кодом. Вот еще одна версия, чтобы справиться с этим:

// The function actually applying the offset
function offsetAnchor() {
    if(location.hash.length !== 0) {
        window.scrollTo(window.scrollX, window.scrollY - 100);
    }
}

// This will capture hash changes while on the page
window.addEventListener("hashchange", offsetAnchor);

// This is here so that when you enter the page with a hash,
// it can provide the offset in that case too. Having a timeout
// seems necessary to allow the browser to jump to the anchor first.
window.setTimeout(offsetAnchor, 1); // The delay of 1 is arbitrary and may not always work right (although it did in my testing).

Примечание: Для того, чтобы использовать JQuery, можно просто заменить window.addEventListenerс $(window).onв примерах. Спасибо @Neon.

РЕДАКТИРОВАТЬ 2:

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

Это решение является слегка измененной версией предложения от @Mave и для простоты использует селекторы jQuery.

// The function actually applying the offset
function offsetAnchor() {
  if (location.hash.length !== 0) {
    window.scrollTo(window.scrollX, window.scrollY - 100);
  }
}

// Captures click events of all <a> elements with href starting with #
$(document).on('click', 'a[href^="#"]', function(event) {
  // Click events are captured before hashchanges. Timeout
  // causes offsetAnchor to be called after the page jump.
  window.setTimeout(function() {
    offsetAnchor();
  }, 0);
});

// Set the offset when entering page with hash present in the url
window.setTimeout(offsetAnchor, 0);

JSFiddle для этого примера находится здесь

Эрик Олсон
источник
1
Это работает, только когда пользователь уже находится на странице, но не работает, например, когда пользователь заходит example.com/#anchorс example.com/about/.
erb
7
Спасибо @erb. Вопрос OP не требовал этого случая, но, чтобы помочь другим, я добавил другую версию реализации.
Эрик Олсон
2
По-прежнему отсутствует небольшая деталь. Если вы нажмете якорь, затем прокрутите вверх, а затем снова щелкните тот же якорь, хеш-изменения нет, поэтому он не будет использовать смещение. Идеи?
Teo Maragakis
Вы могли пойти на $('a[href^="#"]').on('click', function() { offsetAnchor(); });. Таким образом, если hrefиз aэлемента начинается с #, вы вызываете ту же функцию.
Mave
2
Не нужно jQuery - просто замените $(window).on("hashchange",наwindow.addEventListener("hashchange",
Neon
90

Работая только с css, вы можете добавить отступ к закрепленному элементу (как в решении выше). Чтобы избежать ненужных пробелов, вы можете добавить отрицательное поле той же высоты:

#anchor {
    padding-top: 50px;
    margin-top: -50px;
}

Я не уверен, что это лучшее решение в любом случае, но мне оно подходит.

user3364768
источник
3
если есть ссылка в пределах 50 пикселей над ней, я думаю, она может быть скрыта и сделана не кликабельной
Эндрю
@Andrew: Кажется, это не проблема для IE10 или Chrome.
Зловещая Борода
11
вы можете сделать то же самое, используя position: relativeсвойство css. Итак, это было бы какposition: relative; top: -50px;
Алекс Дорохович
@AleksDorohovich - Вы можете опубликовать это как отдельный ответ, так как он уникален среди существующих.
BSMP
Моя страница
64

Еще лучшее решение:

<p style="position:relative;">
    <a name="anchor" style="position:absolute; top:-100px;"></a>
    I should be 100px below where I currently am!
</p>

Просто разместите <a>тег с абсолютным позиционированием внутри относительно позиционированного объекта.

Работает при входе на страницу или через изменение хеша на странице.

Томас
источник
4
Я предпочитаю ваше решение, потому что оно не использует javascript. Спасибо!
Розарио Руссо
1
Я не понимаю этого ответа. Вы ссылаетесь на эту ссылку на объект или на сам объект?
CZorio
3
Очень полезно с загрузочными панелями
навигации
1
@CZorio Если я правильно понял, он (гениально) создает элемент привязки (может быть что-то еще, например «span» вместо «a») и размещает его относительно ниже, так что привязка с href="#anchor"in it будет указывать туда, вместо того, чтобы указывать на <p>элемент напрямую. Но одно предупреждение: используйте idвместо nameHTML5, см .: stackoverflow.com/questions/484719/html-anchors-with-name-or-id
flen
1
Действительно лучшее решение :)
Bobby Axe
24

Вот ответ 2020 года на это:

#anchor {
  scroll-margin-top: 100px;
}

Потому что это широко поддерживается !

user127091
источник
1
Проголосовали против, потому что, хотя это было бы неплохо, это НЕ поддерживается широко. Ни Opera Mobile / Mini, ни Safari browser / iOS, ни даже первый Edge не поддерживают это полностью.
Беда Шмид,
1
Чуть менее 90% всех браузеров (включая iOS с scroll-snap-margin-top) должно быть достаточно, чтобы отказаться от решения javascript, особенно если пользователю просто нужно прокручивать страницу. Но послушайте, давайте проголосуем против этого подхода, прежде чем он кому-то навредит.
user127091
Такой простой и рабочий ответ. Достаточно скоро достигнет 100% поддержки (для современных браузеров).
Леонель Бесерра,
17

Лучшее решение

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

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

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

<style>
.anchor{
  display: block;
  height: 115px; /*same height as header*/
  margin-top: -115px; /*same height as header*/
  visibility: hidden;
}
</style>
Никита Андрейчук
источник
8
Почему это лучшее решение? Кроме того, будет намного полезнее, если вы дадите некоторый уровень объяснения / рассуждения с ответом.
Фил Хили
Поскольку вы в любом случае добавляете HTML, чтобы сделать якорь, добавление диапазона не сильно отличается. Затем, просто добавив немного CSS, вы сможете решить эту проблему без каких-либо ошибок; как и некоторые другие решения.
Сондре,
11

Это будет работать без jQuery и при загрузке страницы.

(function() {
    if (document.location.hash) {
        setTimeout(function() {
            window.scrollTo(window.scrollX, window.scrollY - 100);
        }, 10);
    }
})();
MK
источник
1
Работает для меня и имеет преимущество перед методом css в том, что он применяется ко всем расположениям хэшей на странице, так что вам не нужно писать стиль с каждым включенным хешем и не забудьте изменить стиль, когда вы добавляете еще один параграф с новый хеш. Это также позволяет стилизовать цель с цветом фона без этого расширения на 100 пикселей (или что-то еще) выше, как в ответе от @ user3364768, хотя есть способ обойти это.
Дэвид
4

Чтобы создать ссылку на элемент, а затем «расположить» этот элемент на произвольном расстоянии от верха страницы, используя чистый CSS, вам придется использовать padding-top, таким образом элемент по-прежнему располагается в верхней части окна, но он появляется , видимо, должен быть расположен на некотором расстоянии от верхней части обзора-порта, например:

<a href="#link1">Link one</a>
<a href="#link2">Link two</a>

<div id="link1">
    The first.
</div>

<div id="link2">
    The second.
</div>

CSS:

div {
    /* just to force height, and window-scrolling to get to the elements.
       Irrelevant to the demo, really */
    margin-top: 1000px;
    height: 1000px;
}

#link2 {
    /* places the contents of the element 100px from the top of the view-port */
    padding-top: 100px;
}

Демо JS Fiddle .

Чтобы использовать простой подход JavaScript:

function addMargin() {
    window.scrollTo(0, window.pageYOffset - 100);
}

window.addEventListener('hashchange', addMargin);

Демо JS Fiddle .

Дэвид просит восстановить Монику
источник
1
Единственная проблема с этим заключается в том, что теперь он подталкивает этот фактический div вниз по странице. В идеале якорная ссылка должна быть на 100 пикселей меньше, чем обычно. Я готов использовать JS или jQuery, если это необходимо.
Дэймон 08
3
Это не решает проблему, это просто добавляет пробел перед элементом.
XCS
user1925805: см. обновленный ответ для решения JavaScript. @Cristy: Я знаю , я прямо заявил, что в самом ответе: элемент по-прежнему расположен в верхней части окна, но, по всей видимости, он находится на некотором расстоянии от вершины .
Дэвид требует восстановить Монику на работе
Лучшее чистое решение с вашим JS. Спасибо, у меня все работает очень хорошо!
DanielaB67
Это только работает, хеш-изменения произошли на странице. Но использование было перенаправлено с идентификатором, тогда это не работает
Рохан Худе 02
4

Это должно работать:

    $(document).ready(function () {
    $('a').on('click', function (e) {
        // e.preventDefault();

        var target = this.hash,
            $target = $(target);

       $('html, body').stop().animate({
        'scrollTop': $target.offset().top-49
    }, 900, 'swing', function () {
    });

        console.log(window.location);

        return false;
    });
});

Просто измените .top-49 на то, что соответствует вашей якорной ссылке.

dMehta
источник
3

Если вы используете явные имена привязок, например,

<a name="sectionLink"></a>
<h1>Section<h1>

тогда в css вы можете просто установить

A[name] {
    padding-top:100px;
}

Это будет работать, если ваши теги привязки HREF также не указывают атрибут NAME.

Mespr
источник
Спасибо. Это единственное решение из этого списка, которое сработало для меня.
MikeyBunny
3

Ответ Эрика великолепен, но вам действительно не нужен этот тайм-аут. Если вы используете jQuery, вы можете просто дождаться загрузки страницы. Поэтому я предлагаю изменить код на:

// The function actually applying the offset
function offsetAnchor() {
    if (location.hash.length !== 0) {
        window.scrollTo(window.scrollX, window.scrollY - 100);
    }
}

// This will capture hash changes while on the page
$(window).on("hashchange", function () {
    offsetAnchor();
});

// Let the page finish loading.
$(document).ready(function() {
    offsetAnchor();
});

Это также избавляет нас от этого произвольного фактора.

rppc
источник
3

попробуйте этот код, он уже имеет плавную анимацию при нажатии на ссылку.

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

    $('html, body').animate({
        scrollTop: $($.attr(this, 'href')).offset().top - 100
    }, 500);
});
Марикар Онггон
источник
1

Самое простое решение:

CSS

#link {
    top:-120px; /* -(some pixels above) */
    position:relative;
    z-index:5;
}

HTML

<body>
    <a href="#link">Link</a>
    <div>
        <div id="link"></div> /*this div should placed inside a target div in the page*/
        text
        text
        text
    <div>
</body>
Эдалат Моджавери
источник
1

Вариант решения Томаса: CSS element> element selectors может быть здесь полезен:

CSS

.paddedAnchor{
  position: relative;
}
.paddedAnchor > a{
  position: absolute;
  top: -100px;
}

HTML

<a href="#myAnchor">Click Me!</a>

<span class="paddedAnchor"><a name="myAnchor"></a></span>

Щелчок по ссылке переместит позицию прокрутки на 100 пикселей выше, где бы ни располагался элемент с классом paddedAnchor.

Поддерживается в браузерах, отличных от IE, и в IE, начиная с версии 9. Для поддержки IE 7 и 8 <!DOCTYPE>необходимо объявить a .

HondaGuy
источник
1

Я просто нашел для себя простое решение. Было верхнее поле 15 пикселей

HTML

<h2 id="Anchor">Anchor</h2>

CSS

h2{margin-top:-60px; padding-top:75px;}
Геро
источник
1

Использование только css и отсутствие проблем с закрытым и не кликабельным контентом раньше (суть в событиях указателя: нет):

CSS

.anchored::before {
    content: '';
    display: block;
    position: relative;
    width: 0;
    height: 100px;
    margin-top: -100px;
}

HTML

<a href="#anchor">Click me!</a>
<div style="pointer-events:none;">
<p id="anchor" class="anchored">I should be 100px below where I currently am!</p>
</div>
dantefff
источник
1

Поместите это в стиль:

.hash_link_tag{margin-top: -50px; position: absolute;}

и используйте этот класс в отдельном divтеге перед ссылками, например:

<div class="hash_link_tag" id="link1"></div> 
<a href="#link1">Link1</a>

или используйте этот php-код для тега эхо-ссылки:

function HashLinkTag($id)
{
    echo "<div id='$id' class='hash_link_tag'></div>";
}
MohsenB
источник
0

Я знаю, что это немного поздно, но я нашел кое-что очень важное, чтобы вставить в ваш код, если вы используете Bootstrap Scrollspy. ( http://getbootstrap.com/javascript/#scrollspy )

Это сводило меня с ума на несколько часов.

Смещение для шпиона прокрутки ДОЛЖНО соответствовать window.scrollY, иначе вы рискуете:

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

 var body = $('body');
    body.scrollspy({
        'target': '#nav',
        'offset': 100 //this must match the window.scrollY below or you'll have a bad time mmkay
});

$(window).on("hashchange", function () {
        window.scrollTo(window.scrollX, window.scrollY - 100);
});

beefsupreme
источник
Только js в сниппете? Это не сработает ни на что
0

На основе решения @Eric Olson просто немного измените, чтобы включить элемент привязки, который я хочу конкретно использовать

// Function that actually set offset
function offsetAnchor(e) {
    // location.hash.length different to 0 to ignore empty anchor (domain.me/page#)
    if (location.hash.length !== 0) {
        // Get the Y position of the element you want to go and place an offset
        window.scrollTo(0, $(e.target.hash).position().top - 150);
    }
}

// Catch the event with a time out to perform the offset function properly
$(document).on('click', 'a[href^="#"]', function (e) {
    window.setTimeout(function () {
        // Send event to get the target id later
        offsetAnchor(e);
    }, 10);
});
Карлос А. Ортис
источник
0

Просто у меня такая же проблема. У меня есть пиксель навигатора, и я хочу, чтобы ангкор запускался под навигатором. Решение window.addEventListener...не работает для меня, потому что я установил свою страницу таким scroll-behavior:smoothобразом, чтобы она устанавливала смещение, а не прокручивала до angkor. setTimeout()работа , если время обделяя для прокрутки до конца , но он все еще не очень хорошо. поэтому моим решением было добавить абсолютный div в angkor с помощью height:[the height of the nav]и bottom:100%. в этом случае этот div заканчивался в верхней части элемента angkor и начинался с позиции, в которой вы выбираете angkor для прокрутки. теперь все, что я делаю, это устанавливаю ссылку angkor на этот абсолютный div, и работа выполнена :)

html,body{
    margin:0;
    padding:0;
    scroll-behavior:smooth;
}

nav {
    height:30px;
    width:100%;
    font-size:20pt;
    text-align:center;
    color:white;
    background-color:black;
    position:relative;
}

#my_nav{
    position:fixed;
    z-index:3;
}
#fixer_nav{
    position:static;
}

#angkor{
    position:absolute;
    bottom:100%;
    height:30px;
}
<nav id="my_nav"><a href="#angkor">fixed position nav<a/></nav>
<nav id="fixer_nav"></nav>

<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque nec lacus vel eros rutrum volutpat. Cras ultrices enim sit amet odio dictum, eget consectetur mi pellentesque. Sed mollis gravida nulla, eu euismod turpis efficitur id. Integer pretium posuere fringilla. Aenean laoreet, augue non pharetra elementum, lectus massa congue orci, a imperdiet neque enim ut dui. Praesent commodo orci bibendum leo suscipit viverra. Nunc fermentum semper eleifend. Pellentesque suscipit nulla aliquet, egestas lectus sed, egestas dui. Vivamus scelerisque maximus nibh, ac dignissim nunc tempor a. Praesent facilisis non lacus et aliquam. Proin ultricies lacus vitae nibh ullamcorper gravida. Proin elit arcu, convallis eget posuere quis, placerat id augue. Fusce ex risus, tempus nec orci vitae, feugiat faucibus quam. Integer risus metus, ornare et rhoncus vitae, accumsan a urna.
</p>

<nav><div id="angkor"></div>The angkor</nav>

<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque nec lacus vel eros rutrum volutpat. Cras ultrices enim sit amet odio dictum, eget consectetur mi pellentesque. Sed mollis gravida nulla, eu euismod turpis efficitur id. Integer pretium posuere fringilla. Aenean laoreet, augue non pharetra elementum, lectus massa congue orci, a imperdiet neque enim ut dui. Praesent commodo orci bibendum leo suscipit viverra. Nunc fermentum semper eleifend. Pellentesque suscipit nulla aliquet, egestas lectus sed, egestas dui. Vivamus scelerisque maximus nibh, ac dignissim nunc tempor a. Praesent facilisis non lacus et aliquam. Proin ultricies lacus vitae nibh ullamcorper gravida. Proin elit arcu, convallis eget posuere quis, placerat id augue. Fusce ex risus, tempus nec orci vitae, feugiat faucibus quam. Integer risus metus, ornare et rhoncus vitae, accumsan a urna.

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque nec lacus vel eros rutrum volutpat. Cras ultrices enim sit amet odio dictum, eget consectetur mi pellentesque. Sed mollis gravida nulla, eu euismod turpis efficitur id. Integer pretium posuere fringilla. Aenean laoreet, augue non pharetra elementum, lectus massa congue orci, a imperdiet neque enim ut dui. Praesent commodo orci bibendum leo suscipit viverra. Nunc fermentum semper eleifend. Pellentesque suscipit nulla aliquet, egestas lectus sed, egestas dui. Vivamus scelerisque maximus nibh, ac dignissim nunc tempor a. Praesent facilisis non lacus et aliquam. Proin ultricies lacus vitae nibh ullamcorper gravida. Proin elit arcu, convallis eget posuere quis, placerat id augue. Fusce ex risus, tempus nec orci vitae, feugiat faucibus quam. Integer risus metus, ornare et rhoncus vitae, accumsan a urna.

</p>

Йосеф Тукачинский
источник
0

Я столкнулся с аналогичной проблемой, и я решил ее, используя следующий код

$(document).on('click', 'a.page-scroll', function(event) {
        var $anchor = $(this);
        var desiredHeight = $(window).height() - 577;
        $('html, body').stop().animate({
            scrollTop: $($anchor.attr('href')).offset().top - desiredHeight
        }, 1500, 'easeInOutExpo');
        event.preventDefault();
    });
Умайр Мехмуд
источник
-1
<a href="#anchor">Click me!</a>

<div style="margin-top: -100px; padding-top: 100px;" id="anchor"></div>
<p>I should be 100px below where I currently am!</p>
Sportcanon
источник
4
По сути, это тот же ответ, что и этот . Если вы публикуете ответы на старый вопрос, попробуйте добавить что-нибудь новое. Например, вы можете описать, почему это работает.
Artjom B.
1
Я бы сказал, что любой ответ должен содержать какое-то описание того, почему он работает. ;-)
Фил Хили