首頁 >web前端 >css教學 >用tan(atan2())在CSS中的打字和視口轉換

用tan(atan2())在CSS中的打字和視口轉換

Joseph Gordon-Levitt
Joseph Gordon-Levitt原創
2025-03-07 16:41:09736瀏覽

Typecasting and Viewport Transitions in CSS With tan(atan2())

CSS 已經能夠獲取視口長度了,時間可以追溯到……(查看筆記)……2013年!令人驚訝的是,那已經是十多年前的事了。如今,獲取視口寬度就像編寫 100vw 一樣簡單,但這在像素中又意味著什麼呢?其他屬性呢,比如那些採用百分比、角度或整數的屬性?

考慮一下根據屏幕大小更改元素的不透明度、旋轉它或設置動畫進度。首先需要視口作為整數——這在 CSS 中目前是不可能的,對吧?

我接下來要說的並非什麼突破性的發現,Jane Oriin 在 2023 年就精彩地描述過。簡而言之,我們可以使用一個涉及 tan()atan2() 三角函數的奇特技巧(或特性)來將長度(例如視口)類型轉換為整數。這開啟了許多新的佈局可能性,但我第一次體驗是在編寫 Almanac 條目時,我只是想讓圖像的不透明度具有響應性。

調整 CodePen 大小,隨著屏幕尺寸變小,圖像會變得更透明,當然會有一些邊界,因此它不會變得不可見:

這是我們能做的最簡單的方法,但還有更多。例如,我嘗試組合許多與視口相關的效果所做的這個演示。調整演示大小,頁面就會充滿活力:對象移動、背景變化,文本平滑地換行到位。

我認為這真的很酷,但我不是設計師,所以這是我大腦所能想到的最好的方法。不過,對於這個類型轉換技巧的介紹來說,這可能有點太多了,因此,作為中間地帶,我將只關注標題轉換以展示其所有工作原理:

設置

其背後的想法是使用 atan2()100vw 轉換為弧度(一種編寫角度的方式),然後使用 tan() 返回其原始值,其優點是作為整數出現。應該像這樣實現:

<code>:root {
  --int-width: tan(atan2(100vw, 1px));
}</code>

但是!瀏覽器不太支持這種方法,因此需要更多包裝才能使其在所有瀏覽器中都能工作。以下內容可能看起來像魔法(或無稽之談),所以我建議閱讀 Jane 的文章以更好地理解它,但這樣它就能在所有瀏覽器中工作:

<code>@property --100vw {
  syntax: "<length>";
  initial-value: 0px;
  inherits: false;
}

:root {
  --100vw: 100vw;
  --int-width: calc(10000 * tan(atan2(var(--100vw), 10000px)));
}</length></code>

別太擔心。重要的是我們寶貴的 --int-width 變量,它保存視口大小作為整數!

寬度:一個數字統治所有

現在我們有了視口作為整數,但這只是第一步。這個整數本身並不是非常有用。我們應該接下來將其轉換為其他內容,因為:

  • 不同的屬性具有不同的單位,並且
  • 我們希望每個屬性都從起始值變為結束值。

考慮一下圖像的不透明度從 0 變為 1,對像從 0deg 旋轉到 360deg,或者元素的 offset-distance 從 0% 變為 100%。我們希望隨著 --int-width 變大而在這些值之間進行插值,但現在它只是一個通常在 0 到 1600 之間變化的整數,這是不靈活的,並且不能輕鬆轉換為任何結束值。

最好的解決方案是將 --int-width 轉換為一個從 0 到 1 的數字。因此,隨著屏幕變大,我們可以將其乘以所需的結束值。由於缺乏更好的名稱,我稱這個“0 到 1”的值為 --wideness。如果我們有 --wideness,所有最後的示例都成為可能:

<code>:root {
  --int-width: tan(atan2(100vw, 1px));
}</code>

因此,--wideness 是一個介於 0 到 1 之間的值,表示屏幕的寬度:0 表示屏幕狹窄時,1 表示屏幕寬闊時。但我們仍然必須設置這些值在視口中的含義。例如,我們可能希望 0 為 400px,1 為 1200px,我們的視口轉換將在這些值之間運行。低於和高於的值分別被箝位到 0 和 1。

在 CSS 中,我們可以這樣編寫:

<code>@property --100vw {
  syntax: "<length>";
  initial-value: 0px;
  inherits: false;
}

:root {
  --100vw: 100vw;
  --int-width: calc(10000 * tan(atan2(var(--100vw), 10000px)));
}</length></code>

除了簡單的轉換之外,--wideness 變量還可以讓我們定義轉換應該運行的下限和上限。更好的是,我們可以將轉換區域設置在中間位置,以便用戶可以充分欣賞它。否則,屏幕需要為 0px,以便 --wideness 達到 0,而誰知道要達到 1 需要多寬。

我們得到了 --wideness。接下來是什麼?

首先,標題的標記被分成 span,因為沒有 CSS 方法可以選擇句子中的特定單詞:

<code>/* 如果 `--wideness` 为 0.5 */

.element {
  opacity: var(--wideness); /* 为 0.5 */
  translate: rotate(calc(wideness(400px, 1200px) * 360deg)); /* 为 180deg */
  offset-distance: calc(var(--wideness) * 100%); /* 为 50% */
}</code>

由於我們將自己進行換行,因此取消設置一些默認值非常重要:

<code>:root {
  /* 两个边界都是无单位的 */
  --lower-bound: 400;
  --upper-bound: 1200;

  --wideness: calc(
    (clamp(var(--lower-bound), var(--int-width), var(--upper-bound)) - var(--lower-bound)) / (var(--upper-bound) - var(--lower-bound))
  );
}</code>

轉換應該可以在沒有基本樣式的情況下工作,但它看起來太普通了。如果您想將它們複製到您的樣式表中,它們如下所示:

最後,我們的當前技巧如下所示:

<code><h1>Resize and enjoy!</h1></code>

好了,設置就到這裡。現在是時候使用我們的新值並進行視口轉換了。我們首先必須確定標題應該如何重新排列以適應較小的屏幕:正如您在初始演示中看到的,第一個 span 向上和向右移動,而第二個 span 向相反的方向移動,向下和向左移動。因此,兩個 span 的最終位置轉換為以下值:

<code>h1 {
  position: absolute; /* 保持文本居中 */
  white-space: nowrap; /* 禁用换行 */
}</code>

在繼續之前,這兩個公式基本上相同,但符號不同。我們可以通過引入一個新變量 --direction 來一次重寫它們。它將是 1 或 -1,並定義運行轉換的方向:

<code>:root {
  --int-width: tan(atan2(100vw, 1px));
}</code>

下一步是將 --wideness 引入公式中,以便隨著屏幕大小調整而更改值。但是,我們不能只將所有內容乘以 --wideness。為什麼?讓我們看看如果我們這樣做會發生什麼:

<code>@property --100vw {
  syntax: "<length>";
  initial-value: 0px;
  inherits: false;
}

:root {
  --100vw: 100vw;
  --int-width: calc(10000 * tan(atan2(var(--100vw), 10000px)));
}</length></code>

正如您將看到的,一切都反過來了!當屏幕太寬時,單詞會換行,當屏幕太窄時,單詞會取消換行:

與我們的第一個示例不同,在第一個示例中,轉換隨著 --wideness 從 0 增加到 1 而結束,我們希望隨著 --wideness 從 1 減少到 0 而完成轉換,即隨著屏幕變小,屬性需要達到其最終值。這沒什麼大不了的,因為我們可以將我們的公式重寫為減法,其中減數隨著 --wideness 的增加而增加:

<code>/* 如果 `--wideness` 为 0.5 */

.element {
  opacity: var(--wideness); /* 为 0.5 */
  translate: rotate(calc(wideness(400px, 1200px) * 360deg)); /* 为 180deg */
  offset-distance: calc(var(--wideness) * 100%); /* 为 50% */
}</code>

現在,調整屏幕大小時,所有內容都將朝正確的方向移動!

但是,您會注意到單詞如何直線移動,以及調整大小時某些單詞如何重疊。我們不允許這樣做,因為具有特定屏幕尺寸的用戶可能會在轉換中的這一點上卡住。視口轉換很酷,但不以破壞某些屏幕尺寸的體驗為代價。

單詞不應直線移動,而應曲線移動,以便它們繞過中心單詞。別擔心,在這裡製作曲線比看起來容易:只需在 x 軸上使 span 的移動速度是 y 軸的兩倍即可。這可以通過將 --wideness 乘以 2 來實現,儘管我們必須將其限制為 1,這樣它就不會超過最終值。

<code>:root {
  /* 两个边界都是无单位的 */
  --lower-bound: 400;
  --upper-bound: 1200;

  --wideness: calc(
    (clamp(var(--lower-bound), var(--int-width), var(--upper-bound)) - var(--lower-bound)) / (var(--upper-bound) - var(--lower-bound))
  );
}</code>

看看那美麗的曲線,正好避開了中心文本:

這僅僅是個開始!

令人驚訝的是,將視口作為整數可以有多強大,更瘋狂的是,最後一個示例是您可以使用此類型轉換技巧進行的最基本轉換之一。一旦您完成了初始設置,我可以想像還有更多可能的轉換,而 --wideness 非常有用,就像現在擁有一個新的 CSS 功能一樣。

我希望將來能看到更多關於“視口轉換”的內容,因為它們確實使網站比自適應網站感覺更“生動”。

以上是用tan(atan2())在CSS中的打字和視口轉換的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn