Ustaw łącze kotwicy na kilka pikseli powyżej miejsca, z którym jest połączone


124

Nie jestem pewien, jak najlepiej zadać / wyszukać to pytanie:

Kliknięcie linku zakotwiczenia przenosi Cię do tej sekcji strony, w której obszar linków znajduje się teraz na BARDZO NA GÓRZE strony. Chciałbym, aby link do zakotwiczenia odsyłał mnie do tej części strony, ale chciałbym mieć trochę miejsca na górze. Tak jak w przypadku, nie chcę, aby wysyłał mnie do połączonej części z tym na BARDZO TOP, chciałbym tam około 100 pikseli.

Czy to ma sens? czy to możliwe?

Edytowano, aby pokazać kod - to tylko tag kotwicy:

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

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


Odpowiedzi:


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

Pozwoli to przeglądarce wykonać za nas pracę polegającą na skakaniu do kotwicy, a następnie użyjemy tej pozycji do przesunięcia.

EDYCJA 1:

Jak wskazał @erb, działa to tylko wtedy, gdy jesteś na stronie, podczas gdy hash jest zmieniany. Wpisanie strony z #somethingjuż w adresie URL nie działa z powyższym kodem. Oto inna wersja, która sobie z tym poradzi:

// 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).

UWAGA: Aby użyć jQuery, możesz po prostu wymienić window.addEventListener się $(window).onw przykładach. Dzięki @Neon.

EDYCJA 2:

Jak wskazało kilka osób, powyższe nie powiedzie się, jeśli klikniesz to samo łącze zakotwiczenia dwa lub więcej razy z rzędu, ponieważ nie ma hashchange zdarzenia wymuszającego przesunięcie.

To rozwiązanie jest bardzo nieznacznie zmodyfikowaną wersją sugestii @Mave i dla uproszczenia wykorzystuje selektory 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 dla tego przykładu jest tutaj


1
To działa tylko wtedy, gdy użytkownik jest już na stronie, to nie robi na przykład, gdy użytkownik odwiedza example.com/#anchorod example.com/about/.
erb

7
Dzięki @erb. Pytanie PO nie wymagało tego przypadku, ale aby pomóc innym dodałem kolejną wersję wdrożenia.
Eric Olson

2
Wciąż brakuje drobnego szczegółu. Jeśli klikniesz kotwicę, a następnie przewiniesz w górę, a następnie ponownie klikniesz tę samą kotwicę, nie ma zmiany hash, więc nie użyje przesunięcia. Pomysły?
Teo Maragakis

Możesz iść $('a[href^="#"]').on('click', function() { offsetAnchor(); });. W ten sposób, jeśli hrefsię z aelementu zaczyna się od #, wywołać tę samą funkcję.
Mave

2
Nie ma potrzeby, aby jQuery - wystarczy wymienić $(window).on("hashchange",zwindow.addEventListener("hashchange",
Neon

90

Pracując tylko z css, możesz dodać dopełnienie do zakotwiczonego elementu (jak w rozwiązaniu powyżej) Aby uniknąć niepotrzebnych białych znaków, możesz dodać ujemny margines o tej samej wysokości:

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

Nie jestem pewien, czy to w każdym przypadku najlepsze rozwiązanie, ale dla mnie działa dobrze.


3
jeśli łącze znajduje się w odległości 50 pikseli nad nim, może być zakryte i uniemożliwić jego kliknięcie
Andrew

@Andrew To nie wydaje się być problemem w IE10 lub Chrome.
Sinister Beard

11
możesz zrobić to samo używając position: relativewłaściwości css. A więc byłoby takposition: relative; top: -50px;
Aleks Dorohovich

@AleksDorohovich - Możesz opublikować to jako oddzielną odpowiedź, ponieważ jest unikalna dla już istniejących.
BSMP

Moja strona oszalała ... * _ *

64

Jeszcze lepsze rozwiązanie:

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

Wystarczy umieścić <a>znacznik z pozycjonowaniem bezwzględnym wewnątrz względnie położonego obiektu.

Działa podczas wchodzenia na stronę lub poprzez zmianę skrótu na stronie.


4
Wolę twoje rozwiązanie, ponieważ nie używa javascript. Dzięki!
Rosario Russo

1
Nie rozumiem tej odpowiedzi. Czy odnosisz to łącze do obiektu czy do samego obiektu?
CZorio

3
Bardzo przydatne ze stałymi pasami
nawigacyjnymi

1
@CZorio Jeśli dobrze zrozumiałem, jest to (genialne) utworzenie elementu kotwicy (może to być coś innego, np. „Span” zamiast „a”) i umieszczenie go względnie poniżej, tak aby kotwica z href="#anchor"w nim wskazywała tam, zamiast wskazywać <p>bezpośrednio na element. Ale jedno ostrzeżenie: używaj idzamiast nameHTML5, zobacz: stackoverflow.com/questions/484719/html-anchors-with-name-or-id
flen

1
Naprawdę lepsze rozwiązanie :)
Bobby Axe

23

Oto odpowiedź w 2020 roku:

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

Ponieważ jest szeroko obsługiwany !


1
Głos w dół, ponieważ chociaż byłoby to miłe, NIE jest szeroko obsługiwane. Ani opera mobile / mini, ani przeglądarka Safari / iOS, nawet pierwszy Edge nie obsługuje tego w pełni.
Beda Schmid

1
Nieco mniej niż 90% wszystkich przeglądarek (w tym iOS z funkcją scroll-snap-margin-top) powinno wystarczyć, aby zrezygnować z rozwiązania javascript, zwłaszcza jeśli użytkownik odczuwa tylko przewijanie. Ale hej, odrzućmy to podejście, zanim komuś zaszkodzi.
user127091

Taka prosta i działająca odpowiedź. Wkrótce osiągnie 100% wsparcia (dla nowoczesnych przeglądarek).
Leonel Becerra

17

Najlepsze rozwiązanie

<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
Dlaczego to najlepsze rozwiązanie? O wiele bardziej pomocne jest również podanie odpowiedzi na pewien poziom wyjaśnienia / uzasadnienia.
Phill Healey

Ponieważ i tak dodajesz HTML, aby utworzyć kotwicę, dodanie zakresu nie różni się zbytnio. Następnie wystarczy dodać trochę CSS, aby rozwiązać ten problem bez żadnych błędów; jak w przypadku innych rozwiązań.
Sondre

11

To zadziała bez jQuery i podczas ładowania strony.

(function() {
    if (document.location.hash) {
        setTimeout(function() {
            window.scrollTo(window.scrollX, window.scrollY - 100);
        }, 10);
    }
})();

1
Działa dla mnie i ma tę przewagę nad metodą css, że stosuje ją do wszystkich lokalizacji skrótów na stronie, dzięki czemu nie musisz pisać stylu z każdym dołączonym hashem i pamiętaj o zmodyfikowaniu stylu, gdy dodajesz kolejną para nowy hash. Pozwala również na stylizowanie celu za pomocą koloru tła bez rozciągania powyżej 100 pikseli (lub cokolwiek), jak w odpowiedzi od @ user3364768, chociaż jest na to sposób.
David

4

Aby utworzyć link do elementu, a następnie „umieścić” ten element w dowolnej odległości od góry strony, używając czystego CSS, musisz użyć padding-top, w ten sposób element nadal jest umieszczony u góry okna, ale wydaje się być w widoczny sposób umieszczony w pewnej odległości od górnej części okienka widoku, na przykład:

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

Demo JS Fiddle .

Aby użyć prostego podejścia JavaScript:

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

window.addEventListener('hashchange', addMargin);

Demo JS Fiddle .


1
Jedynym problemem jest to, że teraz wypycha ten rzeczywisty div dalej w dół strony. Idealnie byłoby, gdyby link zakotwiczenia spadł o 100 pikseli mniej niż normalnie. Jeśli to konieczne, jestem skłonny użyć JS lub jQuery, aby to osiągnąć.
damon,

3
To nie rozwiązuje problemu, po prostu dodaje spację przed elementem.
XCS,

user1925805: zobacz zaktualizowaną odpowiedź dotyczącą rozwiązania JavaScript. @Cristy: Wiem , wyraźnie powiedziałem, że w samej odpowiedzi: element nadal znajduje się w górnej części okna, ale wydaje się być umieszczony w pewnej odległości od góry .
David mówi, że przywróć Monice

Najlepsze, czyste rozwiązanie z Twoim JS. Dzięki, dla mnie działa bardzo dobrze!
DanielaB67

Działa to tylko ze zmianami hash, które miały miejsce na stronie. Ale użycie zostało przekierowane z identyfikatorem, więc to nie działa
Rohan Khude

4

To powinno działać:

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

Po prostu zmień .top-49 na taki, który pasuje do twojego linku kotwicy.


3

Jeśli używasz jawnych nazw kotwic, takich jak,

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

następnie w css możesz po prostu ustawić

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

Będzie to działać, o ile tagi kotwicy HREF nie określają również atrybutu NAME


Dzięki. To jedyne rozwiązanie z tej listy, które u mnie zadziałało.
MikeyBunny

3

Odpowiedź Erica jest świetna, ale naprawdę nie potrzebujesz tego czasu. Jeśli używasz jQuery, możesz po prostu poczekać, aż strona się załaduje. Proponuję więc zmienić kod na:

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

To również pozwala nam pozbyć się tego arbitralnego czynnika.


3

wypróbuj ten kod, ma już płynną animację po kliknięciu linku.

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

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

1

Najłatwiejsze rozwiązanie:

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

Wariant rozwiązania Thomasa: selektory elementu CSS > elementu mogą być przydatne tutaj:

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>

Kliknięcie linku przesunie pozycję przewijania do 100px powyżej miejsca, w którym znajduje się element z klasą paddedAnchor.

Obsługiwane w przeglądarkach innych niż IE oraz w IE od wersji 9. Aby <!DOCTYPE>zapewnić obsługę IE 7 i 8, należy zadeklarować a.


1

Właśnie znalazłem dla siebie łatwe rozwiązanie. Miał górny margines 15 pikseli

HTML

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

CSS

h2{margin-top:-60px; padding-top:75px;}

1

Używając tylko css i nie mając wcześniej problemów z zakrytą i nieklikowalną zawartością (chodzi o to pointer-events: none):

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

Umieść to w stylu:

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

i użyj tej klasy w osobnym divtagu przed linkami, przykład:

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

lub użyj tego kodu php dla tagu linku echo:

function HashLinkTag($id)
{
    echo "<div id='$id' class='hash_link_tag'></div>";
}

0

Wiem, że jest trochę za późno, ale znalazłem coś bardzo ważnego do umieszczenia w kodzie, jeśli używasz Scrollspy Bootstrap. ( http://getbootstrap.com/javascript/#scrollspy )

To doprowadzało mnie do szału na wiele godzin.

Przesunięcie dla szpiega przewijania MUSI odpowiadać wartości window.scrollY, bo inaczej ryzykujesz:

  1. Uzyskanie dziwnego efektu migotania podczas przewijania
  2. Przekonasz się, że kiedy klikniesz na kotwice, wylądujesz w tej sekcji, ale szpieg zwojów założy, że jesteś nad nią.

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


Tylko js we fragmencie? To nie zadziała bez względu na wszystko

0

Opierając się na rozwiązaniu @Eric Olson , po prostu zmodyfikuj trochę, aby uwzględnić element kotwicy, który chcę konkretnie przejść

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

Po prostu mam ten sam problem. Mam piksele z nawigacją i chcę, aby angkor zaczął działać pod nawigacją. Rozwiązanie window.addEventListener...nie działa dla mnie, ponieważ ustawiłem moją stronę scroll-behavior:smoothtak, aby ustawić przesunięcie zamiast przewinąć do angkor. setTimeout()pracy, jeśli czas jest anough do przewijania do końca, ale to wciąż nie wygląda dobrze. więc moim rozwiązaniem było dodanie postawionego absolutnego div w angkor, z height:[the height of the nav]i bottom:100%. w tym przypadku ten element div kończył się u góry elementu angkor i zaczynał w miejscu, w którym chcesz przewinąć angkor. teraz wszystko, co robię, to ustawiam link angkor do tego absolutnego div i robię wszystko :)

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

napotkałem podobny problem i rozwiązałem go za pomocą następującego kodu

$(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
To w zasadzie ta sama odpowiedź, co ta . Jeśli publikujesz odpowiedzi na stare pytanie, spróbuj dodać coś nowego. Na przykład możesz opisać, dlaczego to działa.
Artjom B.

1
Twierdzę, że każda odpowiedź powinna mieć jakiś opis, dlaczego to działa. ;-)
Phill Healey
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.