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>
damon
źródło

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

Eric Olson
źródło
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.

user3364768
źródło
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.

Tomasz
źródło
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 !

user127091
źródło
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>
Никита Андрейчук
źródło
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);
    }
})();
MK
źródło
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 .

David mówi, że przywróć Monikę
źródło
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.

dMehta
źródło
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

Mespr
źródło
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.

rppc
źródło
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);
});
Maricar Onggon
źródło
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>
Edalat Mojaveri
źródło
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.

HondaGuy
źródło
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;}
Gero
źródło
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>
dantefff
źródło
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>";
}
MohsenB
źródło
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);
});

wołowina
źródło
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);
});
Carlos A. Ortiz
źródło
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>

Josef Tukachinsky
źródło
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();
    });
Umair Mehmood
źródło
-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
źródło
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