Tạo liên kết cố định đi một số pixel phía trên nơi nó được liên kết với


124

Tôi không chắc cách tốt nhất để hỏi / tìm kiếm câu hỏi này:

Khi bạn nhấp vào một liên kết cố định, nó sẽ đưa bạn đến phần đó của trang với khu vực được liên kết đến bây giờ ở RẤT ĐẦU của trang. Tôi muốn liên kết neo đưa tôi đến phần đó của trang, nhưng tôi muốn có một số khoảng trống ở trên cùng. Như trong, tôi không muốn nó đưa tôi đến phần được liên kết với nó ở RẤT ĐẦU, tôi muốn khoảng trống 100 pixel ở đó.

Điều này có nghĩa không? Điều này có khả thi không?

Đã chỉnh sửa để hiển thị mã - nó chỉ là một thẻ liên kết:

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

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


Câu trả lời:


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

Điều này sẽ cho phép trình duyệt thực hiện công việc chuyển đến neo cho chúng tôi và sau đó chúng tôi sẽ sử dụng vị trí đó để bù đắp.

CHỈNH SỬA 1:

Như đã được chỉ ra bởi @erb, điều này chỉ hoạt động nếu bạn ở trên trang trong khi mã băm được thay đổi. Việc nhập trang #somethingđã có trong URL không hoạt động với mã trên. Đây là một phiên bản khác để xử lý điều đó:

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

LƯU Ý: Để sử dụng jQuery, bạn chỉ có thể thay thế window.addEventListenerbằng $(window).ontrong các ví dụ. Cảm ơn @Neon.

CHỈNH SỬA 2:

Như đã chỉ ra bởi một số người, ở trên sẽ không thành công nếu bạn nhấp vào cùng một liên kết neo hai hoặc nhiều lần liên tiếp vì không có hashchangesự kiện nào để buộc bù đắp.

Giải pháp này là phiên bản được sửa đổi rất nhẹ của đề xuất từ ​​@Mave và sử dụng bộ chọn jQuery để đơn giản hóa

// 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 cho ví dụ này ở đây


1
Điều này chỉ hoạt động khi người dùng đã ở trên trang, chẳng hạn như khi người dùng truy cập example.com/#anchortừ example.com/about/.
erb

7
Cảm ơn @erb. Câu hỏi của OP không yêu cầu trường hợp đó, nhưng để giúp những người khác, tôi đã thêm một phiên bản triển khai khác.
Eric Olson

2
Vẫn còn thiếu một chi tiết nhỏ. Nếu bạn nhấp vào một neo, sau đó cuộn lên sau đó nhấp lại vào cùng một liên kết, không có sự thay đổi hàm băm nên nó sẽ không sử dụng phần bù đắp. Ý tưởng?
Teo Maragakis

Bạn có thể đi cho $('a[href^="#"]').on('click', function() { offsetAnchor(); });. Bằng cách này, nếu phần tử hrefcủa một aphần tử bắt đầu bằng a #, bạn sẽ gọi hàm tương tự.
Mave

2
Không cần phải jQuery - chỉ cần thay thế $(window).on("hashchange",vớiwindow.addEventListener("hashchange",
Neon

90

Chỉ làm việc với css, bạn có thể thêm phần đệm vào phần tử cố định (như trong giải pháp ở trên) Để tránh khoảng trắng không cần thiết, bạn có thể thêm một lề âm có cùng chiều cao:

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

Tôi không chắc liệu đây có phải là giải pháp tốt nhất trong mọi trường hợp hay không, nhưng nó hoạt động tốt đối với tôi.


3
Nếu có một liên kết trong vòng 50px phía trên nó, nó có thể bị che và không thể nhấp vào, tôi tin rằng
Andrew

@Andrew Đó dường như không phải là vấn đề trên IE10 hoặc Chrome.
Sinister Beard,

11
bạn có thể làm điều tương tự bằng cách sử dụng thuộc tính position: relativecss. Vì vậy, nó sẽ giống nhưposition: relative; top: -50px;
Aleks Dorohovich

@AleksDorohovich - Bạn có thể đăng câu trả lời đó như một câu trả lời riêng biệt vì nó là duy nhất so với những câu hiện có.
BSMP

Trang của tôi trở nên hoang dã ... * _ *

64

Giải pháp tốt hơn nữa:

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

Chỉ định vị <a>thẻ với vị trí tuyệt đối bên trong của một đối tượng được định vị tương đối.

Hoạt động khi vào trang hoặc thông qua thay đổi băm trong trang.


4
Tôi thích giải pháp của bạn hơn vì nó không sử dụng javascript. Cảm ơn!
Rosario Russo

1
Tôi không hiểu câu trả lời này. Bạn đang tham chiếu liên kết này đến đối tượng hay chính đối tượng?
CZorio

3
Rất hữu ích với bootstrap cố định-top NavBars
Outside_Box

1
@CZorio Nếu tôi hiểu đúng, thì đó là (một cách khéo léo) tạo một phần tử neo (có thể là một cái gì đó khác, như "span" thay vì "a") và định vị nó tương đối bên dưới, sao cho mỏ neo href="#anchor"trong đó sẽ chỉ vào đó, thay vì trỏ đến <p>phần tử trực tiếp. Nhưng một cảnh báo: sử dụng idthay vì nametrong HTML5, hãy xem: stackoverflow.com/questions/484719/html-anchors-with-name-or-id
flen

1
Thực sự là một giải pháp tốt hơn :)
Bobby Axe

22

Đây là câu trả lời năm 2020 cho điều này:

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

Bởi vì nó được hỗ trợ rộng rãi !


1
Bị phản đối vì mặc dù điều này sẽ tốt nhưng nó KHÔNG được hỗ trợ rộng rãi. Cả opera mobile / mini, hay safari browser / ios, thậm chí cả Edge đầu tiên cũng không hỗ trợ đầy đủ điều này.
Beda Schmid

1
Ít hơn 90% tất cả các trình duyệt (bao gồm iOS với scroll-snap-margin-top) là đủ để chọn không tham gia giải pháp javascript, đặc biệt nếu tác động của người dùng chỉ là cuộn. Nhưng này, chúng ta hãy từ chối phương pháp này trước khi nó gây hại cho ai đó.
dùng127091

Một câu trả lời đơn giản và hiệu quả như vậy. Sẽ sớm đạt được 100% hỗ trợ (cho các trình duyệt hiện đại).
Leonel Becerra

17

Giải pháp tốt nhất

<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
Tại sao đây là giải pháp tốt nhất? Ngoài ra, sẽ hữu ích hơn rất nhiều nếu bạn đưa ra một số mức độ giải thích / lập luận với một câu trả lời.
Phill Healey

Vì bạn đang thêm HTML để tạo liên kết, nên việc thêm khoảng cách không có nhiều khác biệt. Sau đó, chỉ cần thêm một chút CSS, bạn có thể giải quyết vấn đề này mà không mắc phải bất kỳ lỗi nào; như một số giải pháp khác có thể làm.
Sondre

11

Điều này sẽ hoạt động mà không cần jQuery và khi tải trang.

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

1
Phù hợp với tôi và có lợi thế hơn phương pháp css là nó áp dụng cho tất cả các vị trí băm trên một trang, do đó bạn không cần phải viết một kiểu với mỗi hàm băm được bao gồm và hãy nhớ sửa đổi kiểu khi bạn thêm một para khác với một hàm băm mới. Nó cũng cho phép người ta tạo kiểu cho mục tiêu bằng màu nền mà không cần mở rộng 100px (hoặc bất kỳ thứ gì) ở trên như trong câu trả lời từ @ user3364768, mặc dù có một cách làm điều đó.
David

4

Để liên kết đến một phần tử và sau đó 'định vị' phần tử đó một khoảng cách tùy ý so với đầu trang, bằng cách sử dụng CSS thuần túy, bạn phải sử dụng padding-top, theo cách đó phần tử vẫn được đặt ở đầu cửa sổ, nhưng nó xuất hiện , rõ ràng, được đặt ở một khoảng cách nào đó so với đầu cổng xem, ví dụ:

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

Bản demo JS Fiddle .

Để sử dụng phương pháp JavaScript đơn giản:

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

window.addEventListener('hashchange', addMargin);

Bản demo JS Fiddle .


1
Vấn đề duy nhất với điều này là bây giờ nó đẩy div thực sự xuống trang. Lý tưởng nhất là liên kết neo sẽ giảm 100px so với bình thường. Tôi sẵn sàng sử dụng JS hoặc jQuery nếu cần thiết để đạt được điều này.
damon

3
Điều này không giải quyết được vấn đề, điều này chỉ đơn giản là thêm khoảng trắng trước phần tử.
XCS

user1925805: xem câu trả lời được cập nhật cho giải pháp JavaScript. @Cristy: Tôi biết , tôi đã tuyên bố rõ ràng rằng trong chính câu trả lời: phần tử vẫn được đặt ở đầu cửa sổ, nhưng nó xuất hiện, rõ ràng, được đặt ở vị trí cách phần trên cùng một khoảng cách .
David nói hãy phục hồi Monica vào

Giải pháp tốt nhất, sạch sẽ với JS của bạn. Cảm ơn nó làm việc cho tôi rất tốt!
DanielaB67 17/12/17

Điều này chỉ hoạt động thay đổi băm xảy ra trong trang. Nhưng sử dụng đã được chuyển hướng với ID, sau đó điều này không hoạt động
Rohan Khude

4

Điều này sẽ hoạt động:

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

Chỉ cần thay đổi .top-49 thành phù hợp với liên kết neo của bạn.


3

Nếu bạn sử dụng các tên liên kết rõ ràng chẳng hạn như,

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

thì trong css, bạn có thể chỉ cần đặt

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

Điều này sẽ hoạt động miễn là thẻ liên kết HREF của bạn cũng không chỉ định thuộc tính NAME


Cảm ơn. Đây là giải pháp duy nhất từ ​​danh sách này phù hợp với tôi.
MikeyBunny

3

Câu trả lời của Eric rất hay, nhưng bạn thực sự không cần thời gian chờ đó. Nếu bạn đang sử dụng jQuery, bạn chỉ cần đợi trang tải. Vì vậy, tôi khuyên bạn nên thay đổi mã thành:

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

Điều này cũng giúp chúng tôi loại bỏ yếu tố tùy tiện đó.


3

hãy thử mã này, nó đã có một hoạt ảnh mượt mà khi nhấp vào liên kết.

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

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

1

Giải pháp đơn giản nhất:

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

Một biến thể của giải pháp của Thomas: Phần tử CSS > bộ chọn phần tử có thể hữu ích tại đây:

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>

Một cú nhấp chuột vào liên kết sẽ di chuyển vị trí cuộn lên 100px phía trên bất cứ nơi nào phần tử có lớp paddedAnchorđược định vị.

Được hỗ trợ trong các trình duyệt không phải IE và trong IE từ phiên bản 9. Để được hỗ trợ trên IE 7 và 8, <!DOCTYPE>phải khai báo a.


1

Tôi chỉ tìm thấy một giải pháp dễ dàng cho chính mình. Có lề đầu 15px

HTML

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

CSS

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

1

Chỉ sử dụng css và không gặp vấn đề gì với nội dung bị che phủ và không thể nhấp vào trước đây (điểm của vấn đề này là con trỏ-sự kiện: không có):

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

Đặt cái này theo kiểu:

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

và sử dụng lớp này trong divthẻ riêng biệt trước các liên kết, ví dụ:

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

hoặc sử dụng mã php này cho thẻ liên kết echo:

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

0

Tôi biết điều này là hơi muộn, nhưng tôi thấy một thứ rất quan trọng cần đưa vào mã của bạn nếu bạn đang sử dụng Bootstrap's Scrollspy. ( http://getbootstrap.com/javascript/#scrollspy )

Điều này đã khiến tôi phát điên trong nhiều giờ.

Phần bù cho gián điệp cuộn PHẢI khớp với window.scrollY, nếu không bạn sẽ gặp rủi ro:

  1. Nhận được hiệu ứng nhấp nháy kỳ lạ khi cuộn
  2. Bạn sẽ thấy rằng khi bạn nhấp vào neo, bạn sẽ hạ cánh trong phần đó, nhưng gián điệp cuộn sẽ cho rằng bạn đang ở trên phần đó.

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


Chỉ j trong đoạn mã? Nó sẽ không làm việc không có vấn đề gì

0

Dựa trên giải pháp @Eric Olson, chỉ cần sửa đổi một chút để bao gồm phần tử neo mà tôi muốn đi cụ thể

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

Tôi chỉ có cùng một vấn đề. Tôi có một nav được đặt pixed và tôi muốn angkor bắt đầu dưới nav. Giải pháp window.addEventListener...không hiệu quả với tôi vì tôi đã đặt trang của mình để scroll-behavior:smoothnó đặt độ lệch thay vì cuộn đến angkor. các setTimeout()công việc nếu thời gian là anough cho cuộn đến cuối cùng nhưng nó vẫn không tìm kiếm tốt. vì vậy giải pháp của tôi là thêm một div tuyệt đối được đặt trong angkor, với height:[the height of the nav]bottom:100%. trong trường hợp này, div này đã kết thúc ở đầu phần tử angkor và bắt đầu ở vị trí mà bạn cuộn angkor đến. Bây giờ tất cả những gì tôi làm là đặt liên kết angkor đến div tuyệt đối này và việc làm xong :)

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

tôi đã gặp phải vấn đề tương tự và tôi đã giải quyết bằng cách sử dụng mã sau

$(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
Về cơ bản đó là câu trả lời giống như câu này . Nếu bạn đăng câu trả lời cho câu hỏi cũ, hãy thử thêm nội dung mới. Ví dụ, bạn có thể mô tả lý do tại sao điều đó hoạt động.
Artjom B.

1
Tôi cho rằng bất kỳ câu trả lời nào cũng nên có một số mô tả về lý do tại sao nó hoạt động. ;-)
Phill Healey
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.