锚点定位的元素如何间隔地址栏一段距离

2020年3月11日23点16分

一、导航栏的分隔符

导航栏的分隔

这种文字之间的分割线,传统省事的做法是使用管道符(|)来替代 。但是效果并不是太好,自定义程度不是太高。所以一般会使用盒模型的边框 border 来模拟,在配合使用强大的 CSS3 伪类和伪元素更是如鱼得水。一句 CSS 语句就解决了:🆒

li:not(:last-child)::after{}

二、滑入和滑出

滑入和滑出

这种滑入滑出的效果,在 JQuery 里面对应的是 slideDown() 和 slideUp() 方法。但是在 MVVM 时代,写项目的时候为了这个小小的效果就引入一个 Jquery 库怎么想也是不划算的,所以自己实现。

如果你不在乎效果,只求功能能够实现,可以采用的做法是控制 display 属性值在 none 和其他值之间切换。

以下部分来自张鑫旭的 「CSS 世界」推荐这本书:

按照常规思路我们会使用height+overflow:hidden实现。但是,很多时候,我们展开的元素内容是动态的,换句话说高度是不固定的,因此,height使用的值是默认的auto,应该都知道的auto是个关键字值,并非数值,正如height:100%的100%无法和auto相计算一样,从0px到auto也是无法计算的,因此无法形成过渡或动画效果。

因此,下面代码呈现的效果也是生硬地展开和收起:

.element {
    height: 0;
    overflow: hidden;
    transition: height .25s;
}
.element:hover {
    height: auto; /* 没有transition效果,只是生硬地展开 */
}

难道就没有什么一劳永逸的实现方法吗?有,不妨试试max-height,CSS代码如下:

.element {
    max-height: 0;
    overflow: hidden;
    transition: max-height .25s;
}
.element.hover {
    max-height: 666px; /* 一个足够大的最大高度值 */
}

其中展开后的max-height值,我们只需要设定为保证比展开内容高度大的值就可以,因为max-height值比height计算值大的时候,元素的高度
就是height属性的计算高度,在本交互中,也就是height:auto时候的高度值。于是,一个高度不定的任意元素的展开动画效果就实现了。

但是,使用此方法也有一点要注意,即虽然说从适用范围讲,max-height值越大使用场景越多,但是,如果max-height值太大,在收起的
时候可能会有“效果延迟”的问题,一般我会给设置为500px、或600px,也有延迟但基本不会察觉。

三、锚点定位的元素如何间隔地址栏一段距离

锚点定位的元素如何间隔地址栏一段距离

上面这个演示效果是我在项目中碰到的一个真实需求。导航条是通过position:fixed;固定定位在页面中的。这时候我们点击导航条来加载对应的部分。因为使用的是锚点定位技术,所以页面定位元素会紧贴着地址栏。这就会造成固定定位的导航栏覆盖定位元素。这时候我们需要。定位元素和浏览器最顶端产生一定的距离。我们首先想到的就是给定位元素添加一个padding-top来产生距离。但是这个方法会影响当前页面的布局。

有没有一个方法,在不影响当中页面布局的情况下,达到我们想要的效果。这时候就需要用到内联元素垂直方向上的padding对当前页面布局无影响,来达到这个目的。

例如:我们给一个内联元素设置垂直方向的padding:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        *{margin:0;padding:0;}
        h3{
            padding-top: 200px;
        }
        span{
            padding-top: 100px;
        }
    </style>
</head>
<body>
    <h3>小标题</h3>
    <span>内联元素</span>
</body>
</html>
页面布局未受影响

这时给 span 填上背景色:

span{
    padding-top: 100px;
    background-color: rgba(23,45,12,0.2);
}

观察发现可得,内联元素的padding在垂直方向同样会影响布局,影响视觉表现。只是因为内联元素没有可视宽度和可视高度的说法(clientHeight和clientWidth永远是0),垂直方向的行为表现完全受line-height和vertical-align的影响,视觉上并没有改变和上一行下一行内容的间距,因此,给我们的感觉就会是垂直padding没有起作用。

就利用内联元素padding在垂直方向上对布局没影响,但是又有布局效果来实现锚点定位的元素间隔地址栏一段距离

四、返回顶部动画

页面返回顶部用到的也是锚点定位技术。但是锚点定位技术,有一个体验特别不好的地方就是没有动画效果,具体表现为一触即达。

以前常用的办法是使用 JQ 的animate 动画来实现。有没有更简单的办法呢?比如说使用纯CSS将它实现。下面介绍两种简单的办法让页面滚动平滑:

  • CSS 的 scroll-behavior
  • JS 的 scrollIntoView

CSS 的 scroll-behavior 演示代码:凡是需要滚动的地方都加一句scroll-behavior:smooth就好了!

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        html,body{
            scroll-behavior: smooth;
        }
        .inner{
            width: 1000px;
            margin: 0 auto;
        }
        p{
            margin: 120px 0;
        }
    </style>
</head>
<body>
    <div class="inner">
        <p>
            眼见那少年与中年汉子已拆到七十余招,剑招越来越紧,兀自未分胜败。突然中年汉子一剑挥出,用力猛了,身子微微一晃,似欲摔跌。西边宾客中一个身穿青衫的年轻男子忍不住“嗤”的一声笑。他随即知道失态,忙伸手按住了口。
        </p>
        <p>
            眼见那少年与中年汉子已拆到七十余招,剑招越来越紧,兀自未分胜败。突然中年汉子一剑挥出,用力猛了,身子微微一晃,似欲摔跌。西边宾客中一个身穿青衫的年轻男子忍不住“嗤”的一声笑。他随即知道失态,忙伸手按住了口。
        </p>
        <p>
            眼见那少年与中年汉子已拆到七十余招,剑招越来越紧,兀自未分胜败。突然中年汉子一剑挥出,用力猛了,身子微微一晃,似欲摔跌。西边宾客中一个身穿青衫的年轻男子忍不住“嗤”的一声笑。他随即知道失态,忙伸手按住了口。
        </p>
        <p>
            眼见那少年与中年汉子已拆到七十余招,剑招越来越紧,兀自未分胜败。突然中年汉子一剑挥出,用力猛了,身子微微一晃,似欲摔跌。西边宾客中一个身穿青衫的年轻男子忍不住“嗤”的一声笑。他随即知道失态,忙伸手按住了口。
        </p>
        <p>
            眼见那少年与中年汉子已拆到七十余招,剑招越来越紧,兀自未分胜败。突然中年汉子一剑挥出,用力猛了,身子微微一晃,似欲摔跌。西边宾客中一个身穿青衫的年轻男子忍不住“嗤”的一声笑。他随即知道失态,忙伸手按住了口。
        </p>
        <p>
            眼见那少年与中年汉子已拆到七十余招,剑招越来越紧,兀自未分胜败。突然中年汉子一剑挥出,用力猛了,身子微微一晃,似欲摔跌。西边宾客中一个身穿青衫的年轻男子忍不住“嗤”的一声笑。他随即知道失态,忙伸手按住了口。
        </p>
        <a href="#">返回顶部</a>
    </div>
</body>
</html>

JS 的 scrollIntoView

如果我们的网页已经通过CSS设置了scroll-behavior:smooth声明,则我们直接执行target.scrollIntoView()方法就会有平滑滚动,无需再额外设置behavior参数。

使用方式为:

dom.scrollIntoView({
    behavior: "smooth"
});

五、最后

综合演示源代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>导航栏</title>
    <style>
        *{margin:0;padding:0;}
        html,body{
            scroll-behavior: smooth;
        }
        .inner{
            width: 1000px;
            margin: 0 auto;
        }
        ul{
            list-style: none;
            position: fixed;
            top: 0;
            left: 50%;
            transform: translateX(-50%);
        }
        li{
            width: 100px;height: 60px;
            float: left;
            background-color: rgba(135, 206, 2350, 1);
            text-align: center;
            position: relative;
        }
        li:not(:last-child)::after{
            content: "";
            position: absolute;
            left: 100%;
            top: 50%;
            transform: translate(-50%,-50%);
            z-index: 99;
            height: 20px;
            border-left: 1px solid #333;
        }
        li > a{
            text-decoration: none;
            display: inline-block;
            line-height: 60px;
            width: 100%;
            color: #000;
        }
        li > a:active{
            color:#000;
        }
        li > a:hover{
            /*background-color: #ab47bc;*/
            color: #fff;
        }
        /*滑入滑出*/
        li a dl dd{
            max-height: 0;
            background-color: skyblue;
            overflow: hidden;
            transition: max-height 0.5s ease 0s;
        }
        li a:hover dl dd{
            max-height: 500px;
        }
        .content{
            margin-top: 60px;
        }
        h3 > a{
            display: inline-block;
            font-size: 22px;
            line-height: 60px;
            color: #000;
            text-decoration: none;
        }
        h3 > a:hover{
            text-decoration: underline;
        }
        section div p {
            overflow: hidden;
            margin: 30px 0;
            font-size: 18px;
        }
        section h3 a span{
            padding-top: 75px;
            background-color: yellow;
        }
    </style>
</head>
<body>
    <nav>
        <ul class="inner">
            <li><a href="#tianlongbabu">
                <dl>
                    <dt>天龙八部</dt>
                    <dd>
                        <p>灭门</p>
                        <p>聆秘</p>
                        <p>救难</p>
                        <p>坐斗</p>
                        <p>治伤</p>
                        <p>洗手</p>
                    </dd>
                </dl>
            </a></li>
            <li><a href="#ludingji">
                <dl>
                    <dt>鹿鼎记</dt>
                    <dd>
                        <p>第一回</p>
                        <p>第二回</p>
                        <p>第三回</p>
                    </dd>
                </dl>
            </a></li>
            <li><a href="">笑傲江湖</a></li>
            <li><a href="">射雕英雄传</a></li>
            <li><a href="">神雕侠侣</a></li>
            <li><a href="">倚天屠龙记</a></li>
            <li><a href="">侠客行</a></li>
            <li><a href="">雪山飞狐</a></li>
            <li><a href="">飞狐外传</a></li>
            <li><a href="">越女剑</a></li>
        </ul>
    </nav>
    <section class="inner content">
        <h3><a><span id="tianlongbabu">天龙八部</span></a></h3>
        <div>
            <p>
                青光闪动,一柄青钢剑倏地刺出,指向中年汉子左肩,使剑少年不等剑招用老,腕抖剑斜,剑锋已削向那汉子右颈。那中年汉子竖剑挡格,铮的一声响,双剑相击,嗡嗡作声,震声未绝,双剑剑光霍霍,已拆了三招。中年汉子长剑猛地击落,直砍少年顶门。那少年避向右侧,左手剑诀一引,青钢剑疾刺那汉子大腿。
            </p>
            <p>两人剑法迅捷,全力相搏。</p>
            <p>
                练武厅东边坐着二人。上首是个四十左右的中年道姑,铁青着脸,嘴唇紧闭。下首是个五十余岁的老者,右手捻着长须,神情甚是得意。两人的座位相距一丈有余,身后各站着二十余名男女弟子。西边一排椅子上坐着十余位宾客。东西双方的目光都集注于场中二人的角斗。
            </p>
            <p>
                眼见那少年与中年汉子已拆到七十余招,剑招越来越紧,兀自未分胜败。突然中年汉子一剑挥出,用力猛了,身子微微一晃,似欲摔跌。西边宾客中一个身穿青衫的年轻男子忍不住“嗤”的一声笑。他随即知道失态,忙伸手按住了口。
            </p>
            <p>便在这时,场中少年左手呼的一掌拍出,击向那汉子后心。那汉子向前跨出一步避开,手中长剑蓦地圈转,喝一声:“着!”那少年左腿已然中剑,腿下一个踉跄,长剑在地下一撑,站直身子待欲再斗,那中年汉子已还剑入鞘,笑道:“褚师弟,承让,承让,伤得不厉害么?”那少年脸色苍白,咬着嘴唇道:“多谢龚师兄剑下留情。”</p>
            <p>那长须老者满脸得色,微微一笑,说道:“东宗已胜了三阵,看来这‘剑湖宫’又要让东宗再住五年了。辛师妹,咱们还须比下去么?”坐在他上首的那中年道姑强忍怒气,说道:“左师兄果然调教得好徒儿。但不知左师兄对‘无量玉壁’的钻研,这五年来可已大有心得么?”长须老者向她瞪了一眼,正色道:“师妹怎地忘了本派的规矩?”那道姑哼了一声,便不再说下去了。</p>
            <p>这老者姓左,名叫子穆,是“无量剑”东宗的掌门。那道姑姓辛,道号双清,是“无量剑”西宗掌门。</p>
            <p>“无量剑”原分东、北、西三宗,北宗近数十年来已趋式微,东西二宗却均人材鼎盛。“无量剑”于五代后唐年间在南诏无量山创派,掌门人居住无量山剑湖宫。自于大宋仁宗年间分为三宗之后,每隔五年,三宗门下弟子便在剑湖宫中比武斗剑,获胜的一宗得在剑湖宫居住五年,至第六年上重行比试。五场斗剑,赢得三场者为胜。这五年之中,败者固然极力钻研,以图在下届剑会中洗雪前耻,胜者也是丝毫不敢松懈。北宗于四十年前获胜而入住剑湖宫,五年后败阵出宫,掌门人一怒而率领门人迁往山西,此后即不再参预比剑,与东西两宗也不通音问。三十五年来,东西二宗互有胜负。东宗胜过四次,西宗胜过两次,那龚姓中年汉子与褚姓少年相斗,已是本次比剑中的第四场,姓龚的汉子既胜,东宗四赛三胜,第五场便不用比了。</p>
        </div>
        <h3><a><span id="ludingji">鹿鼎记</span></a></h3>
        <div>
            <p>北风如刀,满地冰霜。</p>
            <p>江南近海滨的一条大路上,一队清兵手执刀枪,押着七辆囚车,冲风冒寒,向北而行。前面三辆囚车中分别监禁的是三个男子,都作书生打扮,一个是白发老者,两个是中年人。后面四辆中坐的是女子,最后一辆囚车中是个少妇,怀中抱着个女婴。女婴啼哭不休。她母亲温言相呵,女婴只是大哭。囚车旁一名清兵恼了,伸腿在车上踢了一脚,喝道:“再哭,再哭!老子踢死你!”那女婴一惊,哭得更加响了。</p>
            <p>离开道路数十丈处有座大屋,屋檐下站着一个中年文士,一个十一二岁的小孩。那文士见到这等情景,不禁长叹一声,眼眶也红了,说道:“可怜,可怜!”</p>
            <p>那小孩子问道:“爹爹,他们犯了什么罪了?”那文士道:“又犯了什么罪?昨日和今朝,已逮去了三十几人,都是我们浙江有名的读书人,个个都是无辜株连。”他说到“无辜株连”四字,声音压得甚低,生怕给押送囚车的官兵听见了。那小孩道:“那个小女孩还在吃奶,难道也犯了罪?真没道理。”那文士道:“你懂得官兵没道理,真是好孩子。唉,人为刀俎,我为鱼肉,人为鼎镬,我为糜鹿!”那小孩子道:“爹,你前几天教过我,‘人为刀俎,我为鱼肉’,就是给人家斩割屠杀的意思。人家是切菜刀,是砧板,我们就是鱼和肉。‘人为鼎镬,我为糜鹿’这两句话,意思也差不多么?”那文士道:“正是!”眼见官兵和囚车已经去远,拉着小孩的手道:“外面风大,我们回屋里去。”当下父子二人走进书房。</p>
            <p>那文士提笔蘸上了墨,在纸上写了个“鹿”字,说道:“鹿这种野兽,虽是庞然大物,性子却极为和平,只吃青草树叶,从来不伤害别的野兽。凶猛的野兽要伤它吃它,它只有逃跑,倘若逃不了,那只有给人家吃了。”又写了“逐鹿”两字,说道:“因此古人常常拿鹿来比喻天下。世上百姓都温顺善良,只有给人欺压残害的份儿。《汉书》上说:‘秦失其鹿,天下共逐之。’那就是说,秦朝失了天下,群雄并起,大家争夺,最后汉高祖打败了楚霸王,就得了这只又肥又大的鹿。”</p>
            <p>那小孩点头道:“我明白了。小说书上说‘逐鹿中原’,就是大家争着要做皇帝的意思。”那文士甚是喜欢,点了点头,在纸上画了一只鼎的图形,道:“古人煮食,不用灶头锅子,用这样三只脚的鼎,下面烧柴,捉到了鹿,就在鼎里煮来吃。</p>
            <p>皇帝和大官都很残忍,心里不喜欢谁,就说他犯了罪,把他放在鼎里活活煮熟。《史记》中记载蔺相如对秦王说:‘臣知欺大王之罪当诛也,臣请就鼎镬。’就是说:‘我该死,将我在鼎里烧死了罢!’”</p>
            <p>那小孩道:“小说书上又常说‘问鼎中原’,这跟‘逐鹿中原’好像意思差不多。”</p>
            <p>那文士道:“不错。夏禹王收九州之金,铸了九口大鼎。</p>
            <p>当时的所谓‘金’其实是铜。每一口鼎上铸了九州的名字和山川图形,后世为天下之主的,便保有九鼎。《左传》上:‘楚子观兵于周疆。定王使王孙满劳楚子。楚子问鼎之大小轻重焉。’只有天下之主,方能保有九鼎。楚王只是楚国的诸侯,他问鼎的轻重大小,便是心存不轨,想取周王之位而代之。”</p>
        </div>
    </section>
</body>
</html>