我正在尝试清理我的锚的工作方式。我有一个固定在页面顶部的标题,所以当您链接到页面其他位置的锚点时,页面会跳转,因此锚点位于页面顶部,将内容留在固定标题后面(我希望那讲得通)。我需要一种方法将锚点从标题的高度偏移 25px。我更喜欢 HTML 或 CSS,但也可以接受 Javascript。
28 回答
你可以只使用没有任何 javascript 的 CSS。
给你的主播上课:
<a class="anchor" id="top"></a>
然后,您可以通过将锚定为块元素并进行相对定位,将锚定位在高于或低于实际出现在页面上的位置的位置。-250px 将锚点向上定位 250px
a.anchor {
display: block;
position: relative;
top: -250px;
visibility: hidden;
}
我找到了这个解决方案:
<a name="myanchor">
<h1 style="padding-top: 40px; margin-top: -40px;">My anchor</h1>
</a>
这不会在内容中产生任何间隙,并且锚链接的效果非常好。
我也在寻找解决方案。就我而言,这很容易。
我有一个包含所有链接的列表菜单:
<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>
在它应该去的标题之下。
<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>
现在因为我的页面顶部有一个固定菜单,所以我不能让它转到我的标签,因为那会在菜单后面。
相反,我在我的标签中放置了一个带有正确 id 的跨度标签。
<h3><span id="one"></span>one</h3>
现在使用 2 行 CSS 来正确定位它们。
h3{ position:relative; }
h3 span{ position:absolute; top:-200px;}
更改顶部值以匹配固定标题的高度(或更多)。现在我假设这也适用于其他元素。
FWIW 这对我有用:
[id]::before {
content: '';
display: block;
height: 75px;
margin-top: -75px;
visibility: hidden;
}
由于这是一个演示问题,因此纯 CSS 解决方案将是理想的。然而,这个问题是在 2012 年提出的,虽然已经提出了相对定位/负边距解决方案,但这些方法看起来相当老套,会产生潜在的流量问题,并且无法动态响应 DOM/视口的变化。
考虑到这一点,我相信使用 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);
受 Alexander Savin 启发的纯 CSS 解决方案:
a[name] {
padding-top: 40px;
margin-top: -40px;
display: inline-block; /* required for webkit browsers */
}
如果目标仍然不在屏幕上,您可能需要添加以下内容:
vertical-align: top;
我的解决方案结合了我们 CMS 的 target 和 before 选择器。其他技术不考虑锚点中的文本。将高度和负边距调整为您需要的偏移量...
:target::before {
content: '';
display: block;
height: 180px;
margin-top: -180px;
}
这从以前的答案中提取了许多元素,并组合成一个很小的(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);
如果您不喜欢动画,请替换
$('html, body')
.stop()
.animate({
scrollTop: $anchor.offset().top - fixedElementHeight
}, 200);
和:
window.scrollTo(0, $anchor.offset().top - fixedElementHeight);
丑化版:
!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);
对于现代浏览器,只需将 CSS3 :target 选择器添加到页面。这将自动应用于所有锚点。
:target {
display: block;
position: relative;
top: -100px;
visibility: hidden;
}
您可以在不使用 js 且不更改 html 的情况下执行此操作。它是纯 CSS 的。
a[id]::before {
content: '';
display: block;
height: 50px;
margin: -30px 0 0;
}
这将在每个带有 id 的 a-tag 之前附加一个伪元素。调整值以匹配标题的高度。
我一直面临着类似的问题,不幸的是,在实施了上述所有解决方案之后,我得出了以下结论。
- 我的内部元素有一个脆弱的 CSS 结构,并实现位置相对/绝对播放,完全破坏了页面设计。
- CSS 不是我的强项。
我写了这个简单的滚动 js,它解释了由于标题引起的偏移,并将 div 重新定位到下面大约 125 像素。请按您认为合适的方式使用它。
的HTML
<div id="#anchor"></div> <!-- #anchor here is the anchor tag which is on your URL -->
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;
}
}
});
在此处查看实时实现。
改变位置属性的解决方案并不总是可行的(它会破坏布局),因此我建议这样做:
HTML:
<a id="top">Anchor</a>
CSS:
#top {
margin-top: -250px;
padding-top: 250px;
}
用这个:
<a id="top"> </a>
尽量减少重叠,并将字体大小设置为 1px。空锚在某些浏览器中不起作用。
正如@moeffju 建议的那样,这可以通过 CSS来实现。我遇到的问题(我很惊讶我还没有看到讨论过)是用填充或透明边框重叠先前元素的技巧防止在这些部分的底部悬停和单击操作,因为以下一个在z 顺序。
我发现的最佳解决方法是将部分内容放在以下div
位置z-index: 1
:
// Apply to elements that serve as anchors
.offset-anchor {
border-top: 75px solid transparent;
margin: -75px 0 0;
-webkit-background-clip: padding-box;
-moz-background-clip: padding;
background-clip: padding-box;
}
// Because offset-anchor causes sections to overlap the bottom of previous ones,
// we need to put content higher so links aren't blocked by the transparent border.
.container {
position: relative;
z-index: 1;
}
对于同样的问题,我使用了一个简单的解决方案:在每个锚点上放置一个 40px 的 padding-top。
借用此链接给出的答案中的一些代码(未指定作者),您可以在锚点上添加一个很好的平滑滚动效果,同时使其停在锚点上方 -60px 处,很好地适合固定引导导航下方栏(需要 jQuery):
$(".dropdown-menu a[href^='#']").on('click', function(e) {
// prevent default anchor click behavior
e.preventDefault();
// animate
$('html, body').animate({
scrollTop: $(this.hash).offset().top - 60
}, 300, function(){
});
});
如果您的锚点是表格元素或表格(行或单元格)内,则上述方法效果不佳。
我不得不使用 javascript 并绑定到窗口hashchange
事件来解决这个问题(演示):
function moveUnderNav() {
var $el, h = window.location.hash;
if (h) {
$el = $(h);
if ($el.length && $el.closest('table').length) {
$('body').scrollTop( $el.closest('table, tr').position().top - 26 );
}
}
}
$(window)
.load(function () {
moveUnderNav();
})
.on('hashchange', function () {
moveUnderNav();
});
* 注意:hashchange事件并非在所有浏览器中都可用。
与其拥有一个与页面的其余内容重叠的固定位置导航栏(整个页面正文可滚动),不如考虑使用一个带有静态导航栏的不可滚动正文,然后将页面内容放在下面是绝对定位的可滚动 div。
也就是说,有这样的HTML......
<div class="static-navbar">NAVBAR</div>
<div class="scrollable-content">
<p>Bla bla bla</p>
<p>Yadda yadda yadda</p>
<p>Mary had a little lamb</p>
<h2 id="stuff-i-want-to-link-to">Stuff</h2>
<p>More nonsense</p>
</div>
...和这样的CSS:
.static-navbar {
height: 100px;
}
.scrollable-content {
position: absolute;
top: 100px;
bottom: 0;
overflow-y: scroll;
width: 100%;
}
然而,这种方法有一个明显的缺点,即当页面标题中的元素被聚焦时,用户将无法使用键盘滚动页面(例如,通过向上和向下箭头或 Page Up 和Page Down 键)。
这是受到 Shouvik 回答的启发——与他的概念相同,只是固定标头的大小不是硬编码的。只要您的固定标头位于第一个标头节点中,这应该“正常工作”
/*jslint browser: true, plusplus: true, regexp: true */
function anchorScroll(fragment) {
"use strict";
var amount, ttarget;
amount = $('header').height();
ttarget = $('#' + fragment);
$('html,body').animate({ scrollTop: ttarget.offset().top - amount }, 250);
return false;
}
function outsideToHash() {
"use strict";
var fragment;
if (window.location.hash) {
fragment = window.location.hash.substring(1);
anchorScroll(fragment);
}
}
function insideToHash(nnode) {
"use strict";
var fragment;
fragment = $(nnode).attr('href').substring(1);
anchorScroll(fragment);
}
$(document).ready(function () {
"use strict";
$("a[href^='#']").bind('click', function () {insideToHash(this); });
outsideToHash();
});
a[name]:not([href])
您可以使用css 选择器在没有 ID 的情况下实现此目的。这只是查找具有名称且没有 href 的链接,例如<a name="anc1"></a>
一个示例规则可能是:
a[name]:not([href]){
display: block;
position: relative;
top: -100px;
visibility: hidden;
}
我在 TYPO3 网站中遇到了这个问题,其中所有“内容元素”都用以下内容包装:
<div id="c1234" class="contentElement">...</div>
我改变了渲染,所以它呈现如下:
<div id="c1234" class="anchor"></div>
<div class="contentElement">...</div>
这个CSS:
.anchor{
position: relative;
top: -50px;
}
固定的顶栏高度为 40 像素,现在锚点再次工作并在顶栏下方 10 像素处开始。
这种技术的唯一缺点是您不能再使用:target
.
我在每个元素之前添加了 40px 高度.vspace
的元素来固定锚点h1
。
<div class="vspace" id="gherkin"></div>
<div class="page-header">
<h1>Gherkin</h1>
</div>
在 CSS 中:
.vspace { height: 40px;}
它工作得很好,空间也不拥挤。
带有可链接 ID 的隐藏跨度标签如何提供导航栏的高度:
#head1 {
padding-top: 60px;
height: 0px;
visibility: hidden;
}
<span class="head1">somecontent</span>
<h5 id="headline1">This Headline is not obscured</h5>
继承人的小提琴:http: //jsfiddle.net/N6f2f/7
@Jan 的出色答案的另一个转折是将其合并到使用 jQuery(或 MooTools)的#uberbar 固定标题中。(http://davidwalsh.name/persistent-header-opacity)
我已经调整了代码,因此内容的顶部始终位于固定标题下方,并且还再次添加了来自@Jan 的锚点,以确保锚点始终位于固定标题下方。
CSS:
#uberbar {
border-bottom:1px solid #0000cc;
position:fixed;
top:0;
left:0;
z-index:2000;
width:100%;
}
a.anchor {
display: block;
position: relative;
visibility: hidden;
}
jQuery(包括对 #uberbar 和锚方法的调整:
<script type="text/javascript">
$(document).ready(function() {
(function() {
//settings
var fadeSpeed = 200, fadeTo = 0.85, topDistance = 30;
var topbarME = function() { $('#uberbar').fadeTo(fadeSpeed,1); }, topbarML = function() { $('#uberbar').fadeTo(fadeSpeed,fadeTo); };
var inside = false;
//do
$(window).scroll(function() {
position = $(window).scrollTop();
if(position > topDistance && !inside) {
//add events
topbarML();
$('#uberbar').bind('mouseenter',topbarME);
$('#uberbar').bind('mouseleave',topbarML);
inside = true;
}
else if (position < topDistance){
topbarME();
$('#uberbar').unbind('mouseenter',topbarME);
$('#uberbar').unbind('mouseleave',topbarML);
inside = false;
}
});
$('#content').css({'margin-top': $('#uberbar').outerHeight(true)});
$('a.anchor').css({'top': - $('#uberbar').outerHeight(true)});
})();
});
</script>
最后是 HTML:
<div id="uberbar">
<!--CONTENT OF FIXED HEADER-->
</div>
....
<div id="content">
<!--MAIN CONTENT-->
....
<a class="anchor" id="anchor1"></a>
....
<a class="anchor" id="anchor2"></a>
....
</div>
也许这对喜欢#uberbar 褪色固定标题的人有用!
您还可以使用以下属性添加锚点:
(text-indent:-99999px;)
visibility: hidden;
position:absolute;
top:-80px;
并给父容器一个相对位置。
非常适合我。
添加到 Ziav 的答案(感谢 Alexander Savin),我需要使用老派<a name="...">...</a>
,因为我们<div id="...">...</div>
在代码中用于另一个目的。我在使用时遇到了一些显示问题display: inline-block
——每个元素的第一行都<p>
略微右缩进(在 Webkit 和 Firefox 浏览器上)。我最终尝试了其他display
价值观,并且display: table-caption
非常适合我。
.anchor {
padding-top: 60px;
margin-top: -60px;
display: table-caption;
}
这是我们在网站上使用的解决方案。将变量调整为headerHeight
您的标题高度。将js-scroll
类添加到应在单击时滚动的锚点。
// SCROLL ON CLICK
// --------------------------------------------------------------------------
$('.js-scroll').click(function(){
var headerHeight = 60;
$('html, body').animate({
scrollTop: $( $.attr(this, 'href') ).offset().top - headerHeight
}, 500);
return false;
});
@AlexanderSavin 的解决方案WebKit
对我来说在浏览器中效果很好。
我还必须使用:target伪类,它将样式应用于选定的锚点以调整FF
, Opera
&中的填充IE9
:
a:target {
padding-top: 40px
}
请注意,此样式不适用于Chrome
/ Safari
,因此您可能必须使用 css-hacks、条件注释等。
此外,我想注意到 Alexander 的解决方案之所以有效,是因为目标元素是inline
. 如果您不想要链接,您可以简单地更改display
属性:
<div id="myanchor" style="display: inline">
<h1 style="padding-top: 40px; margin-top: -40px;">My anchor</h1>
</div>
我遇到了同样的问题并最终手动处理了点击事件,例如:
$('#mynav a').click(() ->
$('html, body').animate({
scrollTop: $($(this).attr('href')).offset().top - 40
}, 200
return false
)
当然,滚动动画是可选的。