由于这是表示方面的问题,因此纯CSS解决方案是理想的。但是,此问题是在2012,中提出的,尽管已建议了相对定位/负边距解决方案,但这些方法似乎相当笨拙,会产生潜在的流问题,并且无法动态响应DOM /视口中的更改。
考虑到这一点,我相信使用JavaScript是still (February 2017)最好的方法。下面是一个普通的JS解决方案,它将响应锚定单击并在加载(See JSFiddle)时解析页面哈希。如果需要动态计算,请修改.getFixedOffset()
方法。如果使用jQuery, here's a modified solution with better event delegation and smooth scrolling。
(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);