自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

純CSS實(shí)現(xiàn)電梯導(dǎo)航!

開發(fā) 前端
通常要實(shí)現(xiàn)這樣一個交互肯定少不了JS,常規(guī)的做法是監(jiān)聽滾動事件,也可以用IntersectionObserver監(jiān)聽元素的滾動位置狀態(tài)。

我們經(jīng)常會在博客、文檔中看到類似這樣的側(cè)邊導(dǎo)航目錄,例如:

這種導(dǎo)航也被稱為“電梯導(dǎo)航”(當(dāng)然可能還有其他叫法,知道是這個交互就行)。它會隨著內(nèi)容的滾動而自動切換當(dāng)前選中態(tài),點(diǎn)擊任意目錄也會自動滾動到對應(yīng)標(biāo)題,就像這樣。

通常要實(shí)現(xiàn)這樣一個交互肯定少不了JS,常規(guī)的做法是監(jiān)聽滾動事件,也可以用IntersectionObserver監(jiān)聽元素的滾動位置狀態(tài),下面有一篇關(guān)于用IntersectionObserver的實(shí)現(xiàn)。

嘗試使用JS IntersectionObserver讓標(biāo)題和導(dǎo)航聯(lián)動:https://www.zhangxinxu.com/wordpress/2020/12/js-intersectionobserver-nav 。

大家可能也發(fā)現(xiàn)了,這個交互最大的特點(diǎn)就是滾動,是不是也可以聯(lián)想到 CSS滾動驅(qū)動動畫呢?經(jīng)過一番嘗試,發(fā)現(xiàn)純 CSS也能完美實(shí)現(xiàn),而且實(shí)現(xiàn)更加簡單(不到10行),下面是我復(fù)刻的效果。

是不是非常神奇?CSS 還能實(shí)現(xiàn)這樣的效果?一起看看吧!

一、CSS 滾動錨定

這個導(dǎo)航主要有兩個交互:

  • 點(diǎn)擊導(dǎo)航會自動滾動到頁面對應(yīng)位置。
  • 頁面滾動會自動切換導(dǎo)航選中態(tài)。

第一條比較容易,我們可以直接用a標(biāo)簽的能力實(shí)現(xiàn)錨定跳轉(zhuǎn)。假設(shè)HTML結(jié)構(gòu)如下:

<nav>
  <a>一、標(biāo)題一</a>
  <a>二、標(biāo)題二</a>
  <a>三、標(biāo)題三</a>
  <a>四、標(biāo)題四</a>
  <a>五、標(biāo)題五</a>
  <a>六、標(biāo)題六</a>
</nav>
<h1>CSS 電梯導(dǎo)航</h1>
<div class="content">
  <h2>一、標(biāo)題一</h2>
  <section>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
  </section>
</div>
<div class="content">
  <h2>二、標(biāo)題二</h2>
  <section>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
  </section>
</div>
<div class="content">
  <h2>三、標(biāo)題三</h2>
  <section>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
  </section>
</div>
<div class="content">
  <h2>四、標(biāo)題四</h2>
  <section>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
  </section>
</div>
<div class="content">
  <h2>五、標(biāo)題五</h2>
  <section>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
  </section>
</div>
<div class="content">
  <h2>六、標(biāo)題六</h2>
  <section>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
  </section>
</div>

然后簡單修飾一下。

body{
  padding: 0 15px;
}
h2{
  margin: 0;
  padding: .8em 0;
  scroll-margin: 20px;
}
nav{
  position: fixed;
  top: 15px;
  right: 15px;
  background: #fff;
  padding: 10px 0;
  border-radius: 4px;
  overflow: hidden;
}
nav>a{
  position: relative;
  display: block;
  line-height: 2;
  padding: 0 15px;
  font-size: 14px;
  color: #191919;
  text-decoration: none;
}
nav>a:hover{
  background-color: #d5d5d54a;
}
section{
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
section span{
  width: 30%;
  height: 100px;
  border-radius: 4px;
  background-color: #E4CCFF;
}

效果如下:

然后我們只需要給a標(biāo)簽添加href屬性,頁面相對應(yīng)的地方指定相同的id,就像這樣。

<nav>
  <a href="#t1">一、標(biāo)題一</a>
  <a href="#t2">二、標(biāo)題二</a>
	...
</nav>
<div class="content">
  <h2 id="t1">一、標(biāo)題一</h2>
  <section>
    ...
  </section>
</div>
<div class="content">
  <h2 id="t2">二、標(biāo)題二</h2>
  <section>
    ...
  </section>
</div>

這樣點(diǎn)擊a標(biāo)簽會自動錨點(diǎn)到對應(yīng)位置,效果如下:

這樣就能跳轉(zhuǎn)了,如果你覺得有點(diǎn)生硬,可以加入滾動動畫。

body{
  /**/
  scroll-behavior: smooth;
}

這樣就平滑多了。

這樣就實(shí)現(xiàn)了滾動錨定效果,還算比較容易。

下面來看如何實(shí)現(xiàn)滾動聯(lián)動效果。

二、CSS 滾動驅(qū)動動畫

我們可以想一下,如果是IntersectionObserver該如何做呢?沒錯,就是監(jiān)聽每一塊區(qū)域的出現(xiàn)時機(jī),然后改變導(dǎo)航的狀態(tài)。

剛好CSS滾動驅(qū)動動畫中的view-timeline可以實(shí)現(xiàn)類似的效果。它可以「監(jiān)測到元素在可視區(qū)」的情況。

不過,單獨(dú)依靠view-timeline還不行,因?yàn)槟J(rèn)情況下,CSS 滾動驅(qū)動作用范圍只能影響到子元素,而我們的dom結(jié)構(gòu)明顯是分離的。

<nav>
  <a href="#t1">一、標(biāo)題一</a>
  <a href="#t2">二、標(biāo)題二</a>
	...
</nav>

<div class="content">
  <h2 id="t1">一、標(biāo)題一</h2>
  <section>
    ...
  </section>
</div>
<div class="content">
  <h2 id="t2">二、標(biāo)題二</h2>
  <section>
    ...
  </section>
</div>

為了解決這個問題,我們需要用到 CSS 時間線范圍,也就是 timeline-scope。

https://developer.mozilla.org/en-US/docs/Web/CSS/timeline-scope

這里簡單介紹一下,假設(shè)有這樣一個結(jié)構(gòu)。

<div class="content">
  <div class="box animation"></div>
</div>

<div class="scroller">
  <div class="long-element"></div>
</div>

這是兩個元素,右邊的是滾動容器,左邊的是一個可以旋轉(zhuǎn)的矩形。

我們想實(shí)現(xiàn)滾動右邊區(qū)域時,左邊矩形跟著旋轉(zhuǎn),如何實(shí)現(xiàn)呢?

可以給他們共同的父級,比如body定義一個timeline-scope。

body{
  timeline-scope: --myScroller;
}

然后,滾動容器的滾動和矩形的動畫就可以通過這個變量關(guān)聯(lián)起來了。

.scroller {
  overflow: scroll;
  scroll-timeline-name: --myScroller;
  background: deeppink;
}
.animation {
  animation: rotate-appear;
  animation-timeline: --myScroller;
}

效果如下:

這樣就實(shí)現(xiàn)任意元素間的滾動聯(lián)動。

回到這里,我們要做的事情其實(shí)很簡單,給父級(body)定義多個timeline-scope,然后給內(nèi)容區(qū)域和導(dǎo)航區(qū)域都綁定一個相同CSS變量,具體做法如下:

<body style="timeline-scope: --t1,--t2,--t3,--t4,--t5,--t6;">
  <nav>
    <a href="#t1" style="--s: --t1">一、標(biāo)題一</a>
    <a href="#t2" style="--s: --t2;">二、標(biāo)題二</a>
    <a href="#t3" style="--s: --t3">三、標(biāo)題三</a>
    <a href="#t4" style="--s: --t4">四、標(biāo)題四</a>
    <a href="#t5" style="--s: --t5">五、標(biāo)題五</a>
    <a href="#t6" style="--s: --t6">六、標(biāo)題六</a>
  </nav>
  <h1>CSS 電梯導(dǎo)航</h1>
  <div class="content" style="--s: --t1">
    <h2 id="t1">一、標(biāo)題一</h2>
    <section>
      ...
    </section>
  </div>
  <div class="content" style="--s: --t2">
    <h2 id="t2">二、標(biāo)題二</h2>
    <section>
      ...
    </section>
  </div>
  <div class="content" style="--s: --t3">
    <h2 id="t3">三、標(biāo)題三</h2>
    <section>
      ...
    </section>
  </div>
  <div class="content" style="--s: --t4">
    <h2 id="t4">四、標(biāo)題四</h2>
    <section>
      ...
    </section>
  </div>
  <div class="content" style="--s: --t5">
    <h2 id="t5">五、標(biāo)題五</h2>
    <section>
      ...
    </section>
  </div>
  <div class="content" style="--s: --t6">
    <h2 id="t6">六、標(biāo)題六</h2>
    <section>
      ...
    </section>
  </div>

然后給內(nèi)容區(qū)域添加view-timeline-name,導(dǎo)航標(biāo)簽添加 animation-timeline,讓這兩者關(guān)聯(lián)起來,也就是內(nèi)容滾動時,導(dǎo)航的動畫跟著執(zhí)行,這里的動畫很簡單,就是改變導(dǎo)航鏈接的文字顏色和邊框顏色,關(guān)鍵實(shí)現(xiàn)如下:

.content{
  view-timeline-name: var(--s);
}
nav>a{
  /**/
  animation: active;
  animation-timeline: var(--s);
}
@keyframes active {
  0%,100% {
    color: #6f00ff;
    border-color: #6f00ff;
  }
}

效果如下:

這樣滾動聯(lián)動效果基本就出來了,不過還是有些小問題,接著優(yōu)化。

三、CSS 滾動視區(qū)范圍

前面的實(shí)現(xiàn)其實(shí)還個小問題,右邊的導(dǎo)航會同時選中多個。

很明顯是因?yàn)樽髠?cè)的內(nèi)容同時出現(xiàn)了這兩部分區(qū)域。

如果每一塊內(nèi)容高度更少,那同時選中的就更多了,就像這樣。

而我們需要的肯定是同一時刻只選中一個導(dǎo)航,你可以自己定義規(guī)則,比如后面的優(yōu)先于前面的。

那CSS該如何實(shí)現(xiàn)這樣的效果呢?

其實(shí),這里需要換一種思維,上面的實(shí)現(xiàn)之所以會同時出現(xiàn)多個選中,是因?yàn)橐晠^(qū)范圍太大,是整個屏幕,所以可以同時匹配到多個內(nèi)容區(qū)域。

因此,我們可以手動的減少視區(qū)范圍,一直減少成一條線,這樣無論怎樣滾動,都只會匹配一個區(qū)域。

在這里,我們可以通過view-timeline-inset來手動改變視區(qū)范圍,默認(rèn)是0。

比如我們希望以滾動區(qū)域中間為分割線,只要滾動到達(dá)這個點(diǎn),就高亮當(dāng)前導(dǎo)航,可以這樣實(shí)現(xiàn)。

.content{
  view-timeline-name: var(--s);
  view-timeline-inset: 50%; /*完整寫法是 50% 50%*/
}

為了方便演示,我在滾動區(qū)域中間加了一條紅色的線,便于觀察。

可以很清楚的發(fā)現(xiàn),只要越過這條線,導(dǎo)航馬上觸發(fā)高亮選中。

當(dāng)然你也可以自己調(diào)整這個臨界線,比如下面的表示在距離滾動區(qū)域底部30%的地方做判斷。

.content{
  view-timeline-name: var(--s);
  view-timeline-inset: 70% 30%; 
}

這樣就實(shí)現(xiàn)了我們想要的效果了,你也可以訪問以下在線鏈接查看實(shí)際效果(chrome 116+)。

  • CSS 電梯導(dǎo)航 (codepen.io)[1]
  • CSS 電梯導(dǎo)航 (juejin.cn)[2]

四、兼容性和總結(jié)

看似這么多,其實(shí)核心代碼就這幾行。

body{
  timeline-scope: --t1,--t2,--t3,--t4,--t5,--t6;
}
.content{
  view-timeline-name: var(--s);
  view-timeline-inset: 50%;
}
nav>a{
  animation: active;
  animation-timeline: var(--s);
}
@keyframes active {
  0%,100% {
    color: #6f00ff;
    border-color: #6f00ff;
  }
}

包括在HTML中的幾行自定義變量,是不是還不到 10 行?相比 JS實(shí)現(xiàn),代碼更簡單,性能也更好,無需初始化,也不用等待 dom 加載,擴(kuò)展性也強(qiáng)。

唯一的缺點(diǎn)可能是兼容性不足,由于依賴timeline-scope,所以必須Chrome 116+,完整兼容性如下:

下面總結(jié)一下

  • 滾動錨定可以借助a標(biāo)簽和#id實(shí)現(xiàn)自動滾動跳轉(zhuǎn)。
  • scroll-behavior: smooth可以實(shí)現(xiàn)平滑滾動。
  • 默認(rèn)情況下,CSS 滾動驅(qū)動作用范圍只能影響到子元素,但是通過timeline-scope,可以讓任意元素都可以受到滾動驅(qū)動的影響。
  • 利用timeline-scope,我們可以將每個內(nèi)容的位置狀態(tài)和每個導(dǎo)航的選中狀態(tài)聯(lián)動起來。
  • 右邊的導(dǎo)航會同時選中多個是因?yàn)樽筮叺臐L動視區(qū)太大了,可以同時包含多個內(nèi)容區(qū)域。
  • 可以用view-timeline-inset來手動改變視區(qū)范圍,縮小成一條線,這樣無論怎樣滾動,都只會匹配一個區(qū)域
  • 兼容性還不足,目前是Chrome 116+。

總的來說,CSS滾動驅(qū)動動畫不愧是2023年度最強(qiáng)特性,可以做的事情太多了,很多 JS才能實(shí)現(xiàn)的交互都可以取代了,而且做的更好,至于兼容性,還是留給時間吧。

[1]CSS 電梯導(dǎo)航 (codepen.io): https://codepen.io/xboxyan/pen/zYVBEWq。

[2]CSS 電梯導(dǎo)航 (juejin.cn): https://code.juejin.cn/pen/7396195867155562508。

責(zé)任編輯:姜華 來源: 前端偵探
相關(guān)推薦

2021-10-19 22:23:47

CSSBeautiful按鈕

2022-02-21 07:02:16

CSSbeautiful按鈕

2020-11-04 13:55:06

CSS密室逃脫前端

2022-08-10 16:08:38

鴻蒙CSS

2013-04-08 14:07:28

CSS

2022-08-29 17:39:53

應(yīng)用開發(fā)css動畫

2021-01-19 12:16:10

CSS前端UI

2017-04-27 14:05:59

CSS動畫前端

2021-01-25 06:37:06

Css前端CSS 特效

2015-04-24 10:05:15

HTML+CSS阿童木頭像

2024-05-09 00:00:00

CSS標(biāo)簽JavaScript

2023-10-23 08:48:04

CSS寬度標(biāo)題

2022-08-04 06:57:54

CSS拼圖游戲

2023-04-17 09:08:27

CSS計時器

2024-07-31 20:38:18

2010-09-13 14:17:42

CSS縱向?qū)Ш讲藛?/a>

2010-09-13 14:32:39

CSS橫向?qū)Ш?/a>

2010-09-06 15:46:08

CSSDIV

2022-03-28 08:44:15

css3水波動畫

2021-08-23 06:25:57

CSS 技巧animation
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號