当锚点定位遇上固定定位导航栏

800 阅读3分钟

文章主要用于记录遇到固定定位导航栏时,锚点定位元素应如何避免被导航栏遮挡。

零、锚点定位的实现方法

1、利用url上的hash

利用hash进行锚点定位是一种传统的锚点定位方法。如url为www.xxx.com/#target,那么页面就会使id为target的元素滚动至可视范围内。

使用这种方法,目的就是改变浏览器窗口url的hash,一般而言有两种方法:

方法一:利用a标签的href属性进行跳转

<a href="#target1">滚动至target1</a>
<a href="#target2">滚动至target2</a>

<div id="target1">
    这是target1盒子
</div>

<div id="target2">
    这是target2盒子
</div>

方法二:使用js更改hash

window.location.hash="target1"

上述两种方法都能更改url的hash,从而实现锚点定位。但是,利用hash进行定位有一个比较致命的弊端,就是会更改url,刷新页面。

2、利用srollIntoView方法

scrollIntoView是存放在Element.prototype中的方法,也就是说,所有元素节点都能调用此方法。

我们可以将希望展示的元素节点选取出来,然后调用其scrollIntoView方法来实现锚点定位。

function scrollToTarget(id){
    // 选取元素节点
    var target = document.getElementById(id)
    // 平滑滚动,其他参数可参考MDN文档
    target.scrollIntoView({ behavior: "smooth" })
}

scrollToTarget('target1')
scrollToTarget('target2')

使用这种方法的好处就是不需要刷新页面,url美观,而且使用简单。

一、当锚点定位遇上固定定位导航栏

上述篇幅我们简述了两种实现锚点定位的方法,一般情况下,他们都会将需要定位的元素滚动至页面的可视区域中,即元素的上边界与可视区域的上边界重合。

那么这就引出了一个问题:如果在这个页面中,存在一个使用固定定位(fixed)的导航栏,它始终固定在可视区域的顶部。那么当我们使用锚点定位时,元素的一部分将会被导航栏所覆盖。

针对这个需求,我们尝试使用scrollIntoView及配合css布局来解决。

<style>
*{
    padding: 0;
    margin: 0;
}
.nav{
    height: 50px;
    width: 100%;
    border: 1px solid black;
    position: fixed;
    top: 0;
    left: 0;
    background-color: #fff;
}
.other-content1{
    height: 500px;
    border: 1px solid orange;
    margin-top: 50px;
}
.other-content2{
    height: 2000px
}
.target{
    height: 100px;
    background: pink;
}
</style>

<div class="nav">
    我是固定定位导航栏
</div>

<div class="other-content1">
    我是其他占位内容1
</div>

<div class="target">
    我是锚点定位目标元素
</div>

<div class="other-content2">
    我是其他占位内容2
</div>

function scrollToTarget(className){
    var target = document.getElementsByClassName(className)[0]
    target.scrollIntoView({ behavior: "smooth" })
}

scrollToTarget('target')

上述方法就是未经处理的情况,虽然target元素的确实现了定位的目标,但是它的一部分是被处于顶部的导航栏所遮盖。

image.png

为了避免上述被遮盖的情况出现,这里提供一种利用padding和margin来进行特殊布局的方法:

对target盒子设置padding-top: 导航栏高度; margin-top: -导航栏高度; 具体对target选择器的改写如下所示

.target{
    height: 100px;
    background: pink;
    padding-top: 50px; //撑高盒子
    margin-top: -50px; //将盒子向上移动
}
.other-content1{
    height: 500px;
    border: 1px solid blue;
    margin-top: 50px;
    position: relative; //使用定位,提高层级,盖住target的padding部分
}

如上设置之后,就可以使target盒子撑高,并向上移动,然后使用上面的盒子将其padding-top覆盖。那么在进行定位时,target的padding边界就会与可视区域边界重合,content区域则不会被遮挡。

image.png

二、总结

文章中使用到的padding-top: 导航栏高度; margin-top: -导航栏高度;方法,可能会导致页面布局变得复杂。如果大家对此问题有其他见解,欢迎留言讨论。