Javascript 偏移 html 锚点以调整固定标题
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10732690/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
offsetting an html anchor to adjust for fixed header
提问by Matt Dryden
I am trying to clean up the way my anchors work. I have a header that is fixed to the top of the page, so when you link to an anchor elsewhere in the page, the page jumps so the anchor is at the top of the page, leaving the content behind the fixed header (I hope that makes sense). I need a way to offset the anchor by the 25px from the height of the header. I would prefer HTML or CSS, but Javascript would be acceptable as well.
我正在努力清理我的锚的工作方式。我有一个固定在页面顶部的标题,因此当您链接到页面其他位置的锚点时,页面会跳转,因此锚点位于页面顶部,将内容留在固定标题后面(我希望那讲得通)。我需要一种方法来将锚点从标题的高度偏移 25 像素。我更喜欢 HTML 或 CSS,但也可以接受 Javascript。
回答by Jan
You could just use CSS without any javascript.
您可以只使用 CSS 而不使用任何 javascript。
Give your anchor a class:
给你的主播上课:
<a class="anchor" id="top"></a>
You can then position the anchor an offset higher or lower than where it actually appears on the page, by making it a block element and relatively positioning it. -250px will position the anchor up 250px
然后,您可以通过将锚定为块元素并对其进行相对定位,将锚定为比它实际出现在页面上的位置高或低的偏移量。-250px 将定位点向上 250px
a.anchor {
display: block;
position: relative;
top: -250px;
visibility: hidden;
}
回答by Alexander Savin
I found this solution:
我找到了这个解决方案:
<a name="myanchor">
<h1 style="padding-top: 40px; margin-top: -40px;">My anchor</h1>
</a>
This doesn't create any gap in the content and anchor links works really nice.
这不会在内容中造成任何差距,锚链接的效果非常好。
回答by Hrvoje Miljak
I was looking for a solution to this as well. In my case, it was pretty easy.
我也在寻找解决方案。就我而言,这很容易。
I have a list menu with all the links:
我有一个包含所有链接的列表菜单:
<ul>
<li><a href="#one">one</a></li>
<li><a href="#two">two</a></li>
<li><a href="#three">three</a></li>
<li><a href="#four">four</a></li>
</ul>
And below that the headings where it should go to.
下面是它应该去的标题。
<h3>one</h3>
<p>text here</p>
<h3>two</h3>
<p>text here</p>
<h3>three</h3>
<p>text here</p>
<h3>four</h3>
<p>text here</p>
Now because I have a fixed menu at the top of my page I can't just make it go to my tag because that would be behind the menu.
现在,因为我的页面顶部有一个固定菜单,所以我不能只将它放到我的标签中,因为那会在菜单后面。
Instead, I put a span tag inside my tag with the proper id.
相反,我在我的标签中放置了一个带有正确 id 的 span 标签。
<h3><span id="one"></span>one</h3>
Now use 2 lines of CSS to position them properly.
现在使用 2 行 CSS 来正确定位它们。
h3{ position:relative; }
h3 span{ position:absolute; top:-200px;}
Change the top value to match the height of your fixed header (or more). Now I assume this would work with other elements as well.
更改顶部值以匹配固定标题(或更多)的高度。现在我假设这也适用于其他元素。
回答by Ian Clark
As this is a concern of presentation, a pure CSS solution would be ideal. However, this question was posed in 2012, and although relative positioning / negative margin solutions have been suggested, these approaches seem rather hacky, create potential flow issues, and cannot respond dynamically to changes in the DOM / viewport.
由于这是一个演示问题,纯 CSS 解决方案将是理想的。然而,这个问题是在 2012 年提出的,虽然已经提出了相对定位/负边距的解决方案,但这些方法似乎相当笨拙,会产生潜在的流量问题,并且无法动态响应 DOM/视口中的变化。
With that in mind I believe that using JavaScript is still(February 2017) the best approach. Below is a vanilla-JS solution which will respond both to anchor clicks and resolve the page hash on load (See JSFiddle). Modify the .getFixedOffset()
method if dynamic calculations are required. If you're using jQuery, here's a modified solution with better event delegation and smooth scrolling.
考虑到这一点,我相信使用 JavaScript仍然是(2017 年 2 月)最好的方法。下面是一个 vanilla-JS 解决方案,它将响应锚点点击并在加载时解析页面哈希(参见 JSFiddle)。.getFixedOffset()
如果需要动态计算,请修改方法。如果您使用 jQuery,这里有一个改进的解决方案,它具有更好的事件委托和平滑滚动。
(function(document, history, location) {
var HISTORY_SUPPORT = !!(history && history.pushState);
var anchorScrolls = {
ANCHOR_REGEX: /^#[^ ]+$/,
OFFSET_HEIGHT_PX: 50,
/**
* Establish events, and fix initial scroll position if a hash is provided.
*/
init: function() {
this.scrollToCurrent();
window.addEventListener('hashchange', this.scrollToCurrent.bind(this));
document.body.addEventListener('click', this.delegateAnchors.bind(this));
},
/**
* Return the offset amount to deduct from the normal scroll position.
* Modify as appropriate to allow for dynamic calculations
*/
getFixedOffset: function() {
return this.OFFSET_HEIGHT_PX;
},
/**
* If the provided href is an anchor which resolves to an element on the
* page, scroll to it.
* @param {String} href
* @return {Boolean} - Was the href an anchor.
*/
scrollIfAnchor: function(href, pushToHistory) {
var match, rect, anchorOffset;
if(!this.ANCHOR_REGEX.test(href)) {
return false;
}
match = document.getElementById(href.slice(1));
if(match) {
rect = match.getBoundingClientRect();
anchorOffset = window.pageYOffset + rect.top - this.getFixedOffset();
window.scrollTo(window.pageXOffset, anchorOffset);
// Add the state to history as-per normal anchor links
if(HISTORY_SUPPORT && pushToHistory) {
history.pushState({}, document.title, location.pathname + href);
}
}
return !!match;
},
/**
* Attempt to scroll to the current location's hash.
*/
scrollToCurrent: function() {
this.scrollIfAnchor(window.location.hash);
},
/**
* If the click event's target was an anchor, fix the scroll position.
*/
delegateAnchors: function(e) {
var elem = e.target;
if(
elem.nodeName === 'A' &&
this.scrollIfAnchor(elem.getAttribute('href'), true)
) {
e.preventDefault();
}
}
};
window.addEventListener(
'DOMContentLoaded', anchorScrolls.init.bind(anchorScrolls)
);
})(window.document, window.history, window.location);
回答by Mark Nottingham
FWIW this worked for me:
FWIW这对我有用:
[id]::before {
content: '';
display: block;
height: 75px;
margin-top: -75px;
visibility: hidden;
}
回答by Ziav
Pure css solution inspired by Alexander Savin:
受亚历山大·萨文启发的纯 css 解决方案:
a[name] {
padding-top: 40px;
margin-top: -40px;
display: inline-block; /* required for webkit browsers */
}
Optionally you may want to add the following if the target is still off the screen:
如果目标仍然不在屏幕上,您可能需要添加以下内容:
vertical-align: top;
回答by Lezz
My solution combines the target and before selectors for our CMS. Other techniques don't account for text in the anchor. Adjust the height and the negative margin to the offset you need...
我的解决方案为我们的 CMS 结合了目标和之前的选择器。其他技术不考虑锚中的文本。将高度和负边距调整到您需要的偏移量...
:target::before {
content: '';
display: block;
height: 180px;
margin-top: -180px;
}
回答by Lance
This takes many elements from previous answers and combines into a tiny (194 bytes minified) anonymous jQuery function. Adjust fixedElementHeightfor the height of your menu or blocking element.
这从以前的答案中提取了许多元素,并组合成一个很小的(缩小了 194 字节)匿名 jQuery 函数。为您的菜单或阻止元素的高度调整fixedElementHeight。
(function($, window) {
var adjustAnchor = function() {
var $anchor = $(':target'),
fixedElementHeight = 100;
if ($anchor.length > 0) {
$('html, body')
.stop()
.animate({
scrollTop: $anchor.offset().top - fixedElementHeight
}, 200);
}
};
$(window).on('hashchange load', function() {
adjustAnchor();
});
})(jQuery, window);
If you don't like the animation, replace
如果你不喜欢动画,请更换
$('html, body')
.stop()
.animate({
scrollTop: $anchor.offset().top - fixedElementHeight
}, 200);
with:
和:
window.scrollTo(0, $anchor.offset().top - fixedElementHeight);
Uglified version:
丑化版:
!function(o,n){var t=function(){var n=o(":target"),t=100;n.length>0&&o("html, body").stop().animate({scrollTop:n.offset().top-t},200)};o(n).on("hashchange load",function(){t()})}(jQuery,window);
回答by Shouvik
I had been facing a similar issue, unfortunately after implementing all the solutions above, I came to the following conclusion.
我一直面临类似的问题,不幸的是在实施了上述所有解决方案后,我得出了以下结论。
- My inner elements had a fragile CSS structure and implementing a position relative / absolute play, was completely breaking the page design.
- CSS is not my strong suit.
- 我的内部元素有一个脆弱的 CSS 结构,并实现了相对/绝对位置播放,完全破坏了页面设计。
- CSS 不是我的强项。
I wrote this simple scrolling js, that accounts for the offset caused due to the header and relocated the div about 125 pixels below. Please use it as you see fit.
我写了这个简单的滚动 js,它解释了由于标题引起的偏移,并将 div 重新定位在下面大约 125 像素处。请按照您认为合适的方式使用它。
The HTML
HTML
<div id="#anchor"></div> <!-- #anchor here is the anchor tag which is on your URL -->
The JavaScript
JavaScript
$(function() {
$('a[href*=#]:not([href=#])').click(function() {
if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'')
&& location.hostname == this.hostname) {
var target = $(this.hash);
target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
if (target.length) {
$('html,body').animate({
scrollTop: target.offset().top - 125 //offsets for fixed header
}, 1000);
return false;
}
}
});
//Executed on page load with URL containing an anchor tag.
if($(location.href.split("#")[1])) {
var target = $('#'+location.href.split("#")[1]);
if (target.length) {
$('html,body').animate({
scrollTop: target.offset().top - 125 //offset height of header here too.
}, 1000);
return false;
}
}
});
See a live implementation here.
回答by Zsolt Szilagyi
You can do it without js and without altering html. It′s css-only.
你可以在没有 js 和不改变 html 的情况下做到这一点。它仅限于 css。
a[id]::before {
content: '';
display: block;
height: 50px;
margin: -30px 0 0;
}
That will append a pseudo-element before every a-tag with an id. Adjust values to match the height of your header.
这将在每个带有 id 的 a-tag 之前附加一个伪元素。调整值以匹配标题的高度。