CSS 深入探索 - 矩陣完美的自訂捲軸

自訂捲軸極少出現,主要原因是 捲軸是網路上的其餘部分 無法設定 (我正在看日期挑選器)。 您也可以使用 JavaScript 建立自己的專屬程式碼,但這麼做的費用高昂 擬真度,可能會發生延遲本文將運用一些 不符合慣例的 CSS 矩陣,讓您建構完全不需要自訂捲動器 捲動頁面時只產生一些設定程式碼

TL;DR

你不是在乎小事嗎?您只需查看 Nyan cat 示範 取得程式庫呢?您可以在 GitHub 存放區

LAM;WRA (長篇和數學;無論如何都會讀)

前一陣子我們建立了視差捲動器 (您知道嗎? 該文章? 非常值得一試!)使用 CSS 3D 將元素推送回原始狀態 轉換時,元素移動的速度比實際捲動速度

重點回顧

我們先來回顧視差捲軸的運作方式。

如動畫所示,我們推進元素,實現視差效果 沿著 Z 軸指向 3D 空間。捲動文件實際上是 然後沿著 Y 軸平移假設我們將「向下捲動」設為 100px 元素會向上轉譯 100 像素。這項設定適用於「所有」元素、 甚至是「更後面」的那些但「因為」距離太遠 攝影機在螢幕上的觀察移動範圍將小於 100 像素,因而產生 所需的視差效果

當然,將元素移回空間也會使該元素看起來更小 只要向上縮放元素 即可進行修正我們用了精確的算式 我們建構的 視差捲動器 所以我不會重複所有細節

步驟 0:我們想要做什麼?

捲軸。這就是我們要建構的工具但您是否曾想過 他們的業務內容呢?我當然不是。捲軸是 目前可觀看內容的比例,以及進度 可以很清楚地反映讀者的想法當您向下捲動畫面時 表示您已達成目標。如果所有內容都符合 捲軸通常隱藏起來。 如果內容高度為可視區域的 2 倍, 捲軸填滿可視區域高度的 1⁄2。內容高度相當於 3 倍高度的 3 倍 可視區域會將捲軸調整為可視區域的 1⁄3 等,然後即可看到模式。 您也可以透過點選並拖曳捲軸的方式,不需捲動畫面 加快網站速度這有點令人意想不到的行為 建立這類元素我們逐一戰鬥。

步驟 1:反向排序

好,使用 CSS 3D 時,元素移動速度會比捲動速度慢 轉換功能。也可以反向操作 如何理解方向?事實證明,我們建立的內容 自訂捲軸為了瞭解運作方式 請思考一些 CSS 3D 基本知識

如果想以數學意義投影單一角度 最終使用 同質座標。 我不會詳細說明這些產品和用途 例如 3D 座標,再加上另一個第四個座標,稱為「w」。這個 座標應為 1,除非您想讓視角扭曲。三 不用擔心 w 的細節,我們不會使用任何 大於 1 的值因此,所有點現在都是以 4D 向量為準 [x、y、z、w=1] 和矩陣因此需要 設為 4x4

有時候,CSS 會在 可讓您使用 matrix3d() 函式。matrix3d 會使用 16 個引數 (因為矩陣是 4x4),並且依序指定另一個資料欄。我們可以使用這個函式 手動指定旋轉角度和翻譯等 就是那個 w 座標的混亂!

我們需要 3D 情境,才能運用 matrix3d(),因為沒有 3D 情境不會扭曲失真 同質座標如要建立 3D 情境,我們需要一個包含 perspective 和其中一些元素,可在新的 已建立 3D Space適用對象 範例

一段 CSS 程式碼,運用 CSS 的
    從觀點擷取屬性

透視容器內的元素會由 CSS 引擎處理 如下所示:

  • 將元素的每個邊角 (頂點) 轉換為同質座標 [x,y,z,w],相對於透視容器。
  • 右到左,套用所有元素的轉換做為矩陣。
  • 如果透視元素可捲動,請套用捲動矩陣。
  • 運用透視矩陣。

捲動矩陣是指沿著 Y 軸的平移,當我們向下捲動 400 像素,所有元素都必須向上移動 400 像素。透視矩陣是一種 「拉動」指向更靠近 3D 深遠點的矩陣 讓人員瞭解如此一來,就可以同時縮小相片的 距離較遠,而且翻譯時也「放慢速度」。 因此,如果元素被推送,翻譯 400 像素就會導致 或是在畫面上移動 300 像素

如要查看「所有」詳細資料,則應該閱讀 spec 的 但為了本文所述,我簡化了 演算法。

我們的包裝盒位於透視容器內,perspective 的值為 p 屬性,並且假設容器可捲動 n 像素。

透視矩陣時間捲動矩陣:元素轉換矩陣
  第四列含有減去 P 的識別矩陣
  第三欄乘以四和四身分矩陣,第二欄的值是減號 n
  第四個資料欄乘以元素轉換矩陣。

第一個矩陣是透視矩陣,第二個矩陣是捲軸 矩陣重點回顧:捲動矩陣的工作是將元素「向上移動」 向下捲動,因此是負號。

然而,我們希望在捲軸上相反,我們希望元素 向下移動向下。以下提供幾個訣竅: 反轉方塊邊角的 w 座標。如果 w 座標為 -1,所有翻譯都會反向生效。那我們要 那樣?CSS 引擎會負責將我們方塊的邊角轉換成 同質座標,並將 w 設為 1。是時候matrix3d()展現耀眼風采了!

.box {
  transform:
    matrix3d(
      1, 0, 0, 0,
      0, 1, 0, 0,
      0, 0, 1, 0,
      0, 0, 0, -1
    );
}

這個矩陣只會執行否定 w 以外的動作。當 CSS 引擎 將每個邊角都轉換成 [x,y,z,1] 格式的向量,矩陣會 並轉換為 [x,y,z,-1]

四 x 四個身分矩陣,第四列含有減一號和 P
  第三欄乘以四和四身分矩陣,第二欄的值是減號 n
  第四欄乘以四和四身分矩陣,
  第四列第四欄乘以四維向量 x、y、z、1 等於四
  四個識別矩陣,第 1 列的第 1 列是負 1,
  在第二列的第四欄減去 n,第四列減 1
  第四欄等於四維向量 x、y 加 n、z、減去 Z
  p 減號 1。

我列出了一個中間步驟,用來示範元素轉換的效果 矩陣如果不接受矩陣數學,也沒關係。尤里卡 就是在最後一行加入捲動偏移值 n 為 y 而不是減去該座標。該元素會向下轉譯 向下捲動到「向下」

但如果我們只在 example、 元素就不會顯示。這是因為 CSS 規格規定 w < 頂點0 會阻止系統轉譯元素。自我們執行 座標為 0,p 為 1,w 為 -1。

幸好我們可以選擇 z 的值!為確保最終結果 w=1, 即可設定 z = -2。

.box {
  transform:
    matrix3d(
      1, 0, 0, 0,
      0, 1, 0, 0,
      0, 0, 1, 0,
      0, 0, 0, -1
    )
    translateZ(-2px);
}

親愛的,我們的 包裝盒回來了

步驟 2:進行遷移

方塊就在這裡,而且看起來 轉換。視角容器目前無法捲動,因此無法捲動 但我們知道元素會在其他方向觸發 已捲動。我們要讓容器捲動畫面嗎?只需在網址中加入 佔用空間的空格元素:

<div class="container">
    <div class="box"></div>
    <span class="spacer"></span>
</div>

<style>
/* … all the styles from the previous example … */
.container {
    overflow: scroll;
}
.spacer {
    display: block;
    height: 500px;
}
</style>

現在 捲動方塊! 紅色方塊向下移動。

步驟 3:指定大小

頁面會在頁面向下捲動時向下移動。這很難 事實上現在我們要設定樣式 使它看起來像捲軸 增添一點互動性

捲軸通常由「指標」和「軌道」組成, 。拇指的高度與 內容。

<script>
    const scroller = document.querySelector('.container');
    const thumb = document.querySelector('.box');
    const scrollerHeight = scroller.getBoundingClientRect().height;
    thumb.style.height = /* ??? */;
</script>

scrollerHeight 是可捲動元素的高度,而 scroller.scrollHeight 是可捲動內容的總高度。 scrollerHeight/scroller.scrollHeight 是內容片段 顯示。拇指覆蓋的垂直空間比例應等於 可見內容比例:

ScrollerHeight 超過捲動器高度的 thumb 點樣式點高度等於捲動高度
  是否在捲軸捲動高度 (僅限 thumb 點樣式點高度時)
  與捲軸捲動比較的捲軸高度乘以捲軸高度
  。
<script>
    // …
    thumb.style.height =
    scrollerHeight * scrollerHeight / scroller.scrollHeight + 'px';
    // Accommodate for native scrollbars
    thumb.style.right =
    (scroller.clientWidth - scroller.getBoundingClientRect().width) + 'px';
</script>

拇指大小是 但移動得太快這時可以從這裡擷取技術 視差捲動器而定只要將元素移回上一個位置,速度就會變慢 以及使用文字。我們可以向上放大,以修正尺寸錯誤。但我們應該針對 結果該怎麼辦?來試試看吧,你也猜到,就是數學!這是最後一次 承諾。

資訊重點在於,我們希望拇指底部邊緣 捲動畫面時,可捲動元素的底部邊緣對齊 下降。也就是說 scroller.scrollHeight - scroller.height 像素,我們希望縮圖是 翻譯文字:scroller.height - thumb.height。對於捲動器的每個像素 希望我們的大拇指移動 1 像素的像素:

係數等於捲軸的捲軸高度減去拇指點高度
  圓點捲動高度減去捲軸的圓點高度

這就是縮放比例。現在我們必須將縮放比例係數轉換為 我們在視差捲動螢幕時,已經在 z 軸上進行翻譯 文章。根據 規格中的相關部分: 縮放比例係數等於 p/(p - z)。我們可以解開這個方程式 算出我們需要多少拇指沿著 Z 軸轉譯。但 注意,基於我們的 W 協調作業 ,我們必須翻譯 還有 z 軸的額外-2px。另請注意,系統會套用元素的轉換 也就是這個特殊矩陣之前的所有翻譯 反過來,在我們這個特殊矩陣後的所有翻譯都可以!我們來 做成程式碼!

<script>
    // ... code from above...
    const factor =
    (scrollerHeight - thumbHeight)/(scroller.scrollHeight - scrollerHeight);
    thumb.style.transform = `
    matrix3d(
        1, 0, 0, 0,
        0, 1, 0, 0,
        0, 0, 1, 0,
        0, 0, 0, -1
    )
    scale(${1/factor})
    translateZ(${1 - 1/factor}px)
    translateZ(-2px)
    `;
</script>

我們有 捲軸! 這是可以任意設定樣式的 DOM 元素。還有一點是 無障礙設計的重要一環 使用上下拖曳的方式,就能讓更多使用者習慣與捲軸互動。 為了避免延長這篇網誌文章的篇幅, 該部分的詳細資料查看 程式庫程式碼 一文。

iOS 呢?

啊,我的老朋友 iOS Safari。就像捲動視差捲動一樣 問題。由於我們要捲動某個元素 所以需要指定 -webkit-overflow-scrolling: touch,但這會造成 3D 壓平 捲動效果會停止運作我們在視差捲動器中解決了這個問題 偵測 iOS Safari,並依靠 position: sticky 解決這個問題。 我們做一樣查看 視差文章 讓回憶集錦重新顯示

那瀏覽器捲軸呢?

在某些系統上,我們必須處理一個固定的原生捲軸。 過去,捲軸無法隱藏 (只有 非標準虛擬選取器)。 所以要隱藏這些資訊,我們得反對某些 (無數學) 駭客。我們準備了 使用 overflow-x: hidden 設定容器中的捲動元素 捲動元素的寬度。瀏覽器的原生捲軸是

金融服務業

總而言之,我們現在可以打造完美影格速率畫面了 這就像在 Nyan cat 示範

如果您看不到 Nyan cat 的地方,代表著 發現並提交錯誤 並在製作此示範時按一下拇指,讓 Nyan 貓出現。 Chrome 擅長避免不必要的作業 像是畫或動畫的畫面外但好消息是 駭客駭客任務讓 Chrome 認為 Nyan cat GIF 實際上不在畫面上顯示。 希望很快就能解決這個問題。

就是這樣工作量相當多。為你讀完完整內容,我深感榮幸 事物這是一些 這麼做可達到這個目標,這可能很少值得 但如果自訂捲軸是體驗不可或缺的一環但 很高興知道這是有可能的,不是嗎?事實上,很難完成 自訂捲軸會顯示需要處理 CSS 端的流程但別擔心! 日後 HoudiniAnimationWorklet 部署至不同部分 讓影格與捲動連結的效果 簡單得這麼容易