Зробіть посилання на якір, перейдіть на кілька пікселів вище, де це пов’язано


124

Я не впевнений, що найкращий спосіб задати / шукати це питання:

Коли ви натискаєте на якірне посилання, він перенесе вас до того розділу сторінки із зоною зв’язку, яка зараз знаходиться в ДУЖЕМУ ТОПі сторінки. Я хотів би, щоб посилання на якір надсилало мене до тієї частини сторінки, але хотілося б трохи місця вгорі. Як і в іншому, я не хочу, щоб він надсилав мене до частини, пов'язаної з нею в ДУЖЕ ТОПІ, я хотів би 100 пікселів місця там.

Це має сенс? Чи можливо це?

Відредагований для показу коду - це просто тег прив’язки:

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

<p id="anchor">I should be 100px below where I currently am!</p>


Відповіді:


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

Це дозволить браузеру виконати роботу зі стрибків на якір для нас, і тоді ми будемо використовувати це положення для зміщення.

EDIT 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

EDIT 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. Питання ОП не вимагало цього випадку, але для допомоги іншим я додав ще одну версію реалізації.
Ерік Олсон

2
Досі відсутня незначна деталь. Якщо ви натиснете на якір, то прокрутіть вгору, потім знову натисніть на той же якір, немає зміни хеш-коду, щоб він не використовував зміщення. Ідеї?
Тео Марагакіс

Ви могли б піти $('a[href^="#"]').on('click', function() { offsetAnchor(); });. Таким чином, якщо hrefз aелемента починається з #, ви викликаєте ту ж функцію.
Mave

2
Не потрібно jQuery - просто замініть $(window).on("hashchange",наwindow.addEventListener("hashchange",
Неон

90

Працюючи лише з css, ви можете додати прокладку до прикріпленого елемента (як у розчині вище). Щоб уникнути зайвого пробілу, ви можете додати негативний запас однакової висоти:

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

Я не впевнений, чи найкраще це рішення в будь-якому випадку, але це добре працює для мене.


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
Дуже корисно з фіксованими верхніми планками для завантаження
Outside_Box

1
@CZorio Якщо я правильно зрозумів, це (геніально) створити якірний елемент (може бути щось інше, як-от "span" замість "a") і розташувати його відносно внизу, так що якір, що href="#anchor"знаходиться в ньому, буде вказувати там, замість того, щоб <p>безпосередньо вказувати на елемент. Але одне попередження: використання idзамість nameв HTML5, см: stackoverflow.com/questions/484719/html-anchors-with-name-or-id
Flen

1
Воістину краще рішення :)
Бобі Сокира

22

Ось відповідь на 2020 рік для цього:

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

Тому що це широко підтримується !


1
Незважаючи на те, що, хоча це буде добре, воно НЕ підтримується широко. Ні Opera mobile / mini, ні браузер safari / ios, навіть перший Edge це не підтримують повністю.
Беда Шмід

1
Трохи менше 90% усіх браузерів (у тому числі iOS з прокруткою-оснащенням-вершиною поля) має бути достатньо для відмови від рішення javascript, особливо якщо вплив користувача просто потрібно прокручувати. Але ей, давайте сприймемо такий підхід, перш ніж хтось заподіяє шкоду.
користувач127091

Така проста і робоча відповідь. Досить скоро досягне 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);
    }
})();

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
Єдина проблема з цим полягає в тому, що він зараз підштовхує цей фактичний поділ далі вниз по сторінці. В ідеалі, якірний зв'язок просто би знизився на 100 пікс менше, ніж зазвичай. Я готовий використовувати JS або jQuery, якщо потрібно для цього.
damon

3
Це не вирішує проблему, це просто додає пробіл перед елементом.
XCS

user1925805: див. оновлену відповідь на рішення JavaScript. @Cristy: Я знаю , я чітко зазначив, що у самій відповіді: елемент все ще розташований у верхній частині вікна, але, очевидно, він повинен бути розташований на деякій відстані від верху .
Девід каже повернути Моніку

Найкраще, чисте рішення з вашим JS. Дякую, це працює на мене дуже добре!
DanielaB67

Це лише робочі зміни, що відбулися на сторінці. Але використання переспрямовано з ідентифікатором, тоді це не працює
Рохан Худе

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 на те, що відповідає вашому прив'язному каналу.


3

Якщо ви використовуєте явні імена якоря, наприклад,

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

то в css можна просто встановити

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

Це буде працювати до тих пір, поки ваші прив’язні теги HREF також не визначають атрибут NAME


Дякую. Це єдине рішення з цього списку, яке працювало на мене.
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();
});

Це також позбавляє нас від цього довільного чинника.


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> селектори елементів може бути корисний :

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>необхідно оголосити обов'язкове.


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>

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

0

Я знаю, що це трохи пізно, але я знайшов щось дуже важливе, щоб ввести ваш код, якщо ви використовуєте Scrollspy Bootstrap. ( 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);
});


Лише 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таким чином, щоб встановити зсув а не прокрутіла до ангкор. setTimeout()робота , якщо час обділяти для прокрутки до кінця , але він все ще не дуже добре. тому моє рішення полягало в тому, щоб додати позитивний абсолютний діл в ангкорі, з height:[the height of the nav]і bottom:100%. у цьому випадку цей дів закінчився у верхній частині елемента ангкор, і починайте з того місця, куди вам потрібно прокрутити ангкор. Тепер все, що я роблю, - це встановити посилання ангкор на цей абсолютний дів і що вже зроблено :)

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>

4
Це по суті така ж відповідь, як і ця . Якщо ви публікуєте відповіді на старе запитання, спробуйте додати щось нове. Наприклад, ви могли б описати, чому це працює.
Artjom B.

1
Я заперечую, що будь-яка відповідь повинна мати якийсь опис того, чому це працює. ;-)
Філл Хілі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.