首頁 > web前端 > css教學 > 流體其他一切

流體其他一切

Christopher Nolan
發布: 2025-03-07 16:59:08
原創
209 人瀏覽過

Fluid Everything Else

響應式設計,我們都懂,對吧?我們用媒體查詢。不,現在我們用容器查詢了,不是嗎?有時我們會巧妙地運用flexbox或自動流式網格。如果我們想更大膽一些,還可以嘗試流體排版。

我有點不習慣響應式設計經常被分割成離散的塊,例如“佈局A到這個尺寸,然後是佈局B,直到有足夠的空間容納佈局C”。這沒問題,它有效,並且適合於將屏幕設計為PhotoFigVa中靜態佈局的工作流程(免責聲明,我編造了這個軟件名稱)。但這個過程在我看來是一種妥協。我一直相信,響應式設計應該對用戶幾乎不可見。當他們在排隊購買K-Pop門票時,在移動設備上訪問我的網站,他們不應該注意到它與一小時前坐在他們說服老闆需要的巨大曲面遊戲顯示器上的體驗有什麼不同。

考慮一下這個簡單的英雄橫幅及其移動端等效版本。抱歉設計比較粗糙。圖片是AI生成的,但這是這篇文章中唯一AI生成的部分。

狐獴和文本的位置和大小都不同。實現這一點的傳統方法是使用<del>媒体</del>(抱歉,容器)查詢選擇兩種佈局。每種佈局可能具有一定的靈活性,例如居中內容,以及字體大小上的少量流體排版,但我們將選擇一個點,在此點上我們將佈局切換進出堆疊版本。因此,在斷點附近的寬度處,佈局可能看起來有點空或有點擁擠。

還有其他方法嗎?

事實證明,。我們可以將流體排版的概念應用於幾乎任何東西。這樣,我們可以擁有一個隨其父容器大小而流暢變化的佈局。很少有用戶會看到過渡,但他們都會欣賞結果。說實話,他們會的。

開始設計樣式

第一步,讓我們分別為佈局設置樣式,有點像我們使用寬度查詢和斷點時那樣。事實上,讓我們一起使用容器查詢和斷點,以便我們可以輕鬆地看到需要更改哪些屬性。

這是我們英雄橫幅的標記,它不會改變:

<div>
  <div>
    <h1>LookOut</h1>
    <p>Eagle Defense System</p>
  </div>
</div>
登入後複製
登入後複製
登入後複製

這是寬版本相關的CSS:

#hero {
  container-type: inline-size;
  max-width: 1200px;
  min-width: 360px;

  .details {
    position: absolute;
    z-index: 2;

    top: 220px;
    left: 565px;

    h1 { font-size: 5rem; }

    p { font-size: 2.5rem; }
  }

  &::before {
    content: '';
    position: absolute;
    z-index: 1;

    top: 0; left: 0; right: 0; bottom: 0;

    background-image: url(../meerkat.jpg);
    background-origin: content-box;
    background-repeat: no-repeat;

    background-position-x: 0;
    background-position-y: 0;
    background-size: auto 589px;
  }
}
登入後複製
登入後複製
登入後複製

我將背景圖像附加到一個::before偽元素上,以便我可以在其上使用容器查詢(因為容器不能查詢自身)。我們稍後會保留這一點,以便我們可以使用內聯容器查詢 (cqi) 單位。現在,這是僅顯示我們將要使之流暢的值的容器查詢:

@container (max-width: 800px) {
  #hero {
    .details {
      top: 50px;
      left: 20px;

      h1 { font-size: 3.5rem; }

      p { font-size: 2rem; }
    }

    &::before {
      background-position-x: -310px;
      background-position-y: -25px;
      background-size: auto 710px;
    }
  }
}
登入後複製
登入後複製

您可以在實時演示中看到代碼運行——它完全是靜態的,以顯示典型方法的局限性。

讓我們變得流暢

現在我們可以獲取文本和背景的大小和位置的起始點和結束點,並使其流暢。文本大小以您已經熟悉的方式使用流體排版。這是結果——在您查看代碼後,我將解釋這些表達式。

首先是文本位置和大小的更改:

<div>
  <div>
    <h1>LookOut</h1>
    <p>Eagle Defense System</p>
  </div>
</div>
登入後複製
登入後複製
登入後複製

這是狐獴圖像的背景位置和大小:

#hero {
  container-type: inline-size;
  max-width: 1200px;
  min-width: 360px;

  .details {
    position: absolute;
    z-index: 2;

    top: 220px;
    left: 565px;

    h1 { font-size: 5rem; }

    p { font-size: 2.5rem; }
  }

  &::before {
    content: '';
    position: absolute;
    z-index: 1;

    top: 0; left: 0; right: 0; bottom: 0;

    background-image: url(../meerkat.jpg);
    background-origin: content-box;
    background-repeat: no-repeat;

    background-position-x: 0;
    background-position-y: 0;
    background-size: auto 589px;
  }
}
登入後複製
登入後複製
登入後複製

現在我們可以完全刪除容器查詢了。

讓我們解釋一下這些clamp()表達式。我們將從top屬性的表達式開始。

@container (max-width: 800px) {
  #hero {
    .details {
      top: 50px;
      left: 20px;

      h1 { font-size: 3.5rem; }

      p { font-size: 2rem; }
    }

    &::before {
      background-position-x: -310px;
      background-position-y: -25px;
      background-size: auto 710px;
    }
  }
}
登入後複製
登入後複製

您會注意到那裡有一個註釋。這些表達式很好地說明了為什麼幻數是不好的。但我們在這裡無法避免它們,因為它們是一些聯立方程的解——CSS無法做到這一點!

傳遞給clamp() 的上限和下限足夠清楚,但中間的表達式來自這些聯立方程:

/* 行更改
 * -12,27 +12,32
 */

.details {
  /* ... 行 14-16 未更改 */
  /* 对 360px 宽的容器计算结果为 50px,对 1200px 宽的容器计算结果为 220px */
  top: clamp(50px, 20.238cqi - 22.857px, 220px);

  /* 对 360px 宽的容器计算结果为 20px,对 1200px 宽的容器计算结果为 565px */
  left: clamp(20px, 64.881cqi - 213.571px, 565px);

  /* ... 行 20-25 未更改 */
  h1 {
    /* 对 360px 宽的容器计算结果为 3.5rem,对 1200px 宽的容器计算结果为 5rem */
    font-size: clamp(3.5rem, 2.857rem + 2.857cqi, 5rem);
    /* ... 字体粗细未更改 */

  }

  p {
    /* 对 360px 宽的容器计算结果为 2rem,对 1200px 宽的容器计算结果为 2.5rem */
    font-size: clamp(2rem, 1.786rem + 0.952cqi, 2.5rem);
  }
}
登入後複製

……其中f是固定大小長度單位(即px)的數量,v是可變大小單位 (cqi)。在第一個方程中,我們說當1cqi等於12px時,我們希望表達式計算結果為220px。在第二個方程中,我們說當1cqi為3.6px時,我們想要50px,這解為:

/* 行更改
 * -50,3 +55,8
 */

/* 对 360px 宽的容器计算结果为 -310px,对 1200px 宽的容器计算结果为 0px */
background-position-x: clamp(-310px, 36.905cqi - 442.857px, 0px);
/* 对 360px 宽的容器计算结果为 -25px,对 1200px 宽的容器计算结果为 0px */
background-position-y: clamp(-25px, 2.976cqi);
/* 对 360px 宽的容器计算结果为 710px,对 1200px 宽的容器计算结果为 589px */
background-size: auto clamp(589px, 761.857px - 14.405cqi, 710px);
登入後複製

……這整理成一個計算友好的表達式:20.238cqi – 22.857px

當固定單位不同時,我們必須相應地更改可變單位的大小。因此,對於<h1></h1>元素的字體大小,我們有;

/* 对 360px 宽的容器计算结果为 50px,对 1200px 宽的容器计算结果为 220px */
top: clamp(50px, 20.238cqi - 22.857px, 220px);
登入後複製

======================================================================================================================================================================

這是在解決這些方程,因為在容器寬度為 1200px 時,1cqi 與 0.75rem 相同(我的 rem 相對於默認 UA 樣式表,16px),而在 360px 寬時,1cqi 為 0.225rem。

<code>f + 12v = 220
f + 3.6v = 50</code>
登入後複製

需要注意的是:根據您目標的單位,方程是不同的。

老實說,每次都做這個枯燥的數學運算很無聊,所以我做了一個你可以使用的計算器。它不僅可以為你解決方程(精確到小數點後三位,以保持你的CSS整潔),還可以提供有用的註釋與表達式一起使用,這樣你就可以看到它們的來源並避免幻數。隨意使用它。是的,那裡有很多類似的計算器,但它們專注於排版,因此(正確地)專注於rem單位。如果你使用CSS預處理器,你可能可以移植JavaScript。

clamp()函數此時並非嚴格必要。在每種情況下,clamp() 的邊界都設置為容器寬度為 360px 或 1200px 時的值。由於容器本身被限制在這些限制內——通過設置min-widthmax-width值——clamp()表達式永遠不應該調用任何邊界。但是,如果我們改變主意(我們即將這樣做),我更喜歡保留clamp(),因為像這樣的隱式邊界很難發現和維護。

避免傷害

我們可以認為我們的工作完成了,但我們還沒有。佈局仍然不太好用。文本直接覆蓋在狐獴的頭上。雖然我得到保證這不會對狐獴造成傷害,但我不喜歡它的外觀。因此,讓我們進行一些更改,以使文本避免碰到狐獴。

第一個很簡單。我們將狐獴更快地向左移動,以便它讓路。最簡單的方法是將插值的較低端更改為更寬的容器。我們將設置它,以便狐獴在 450px 處完全向左移動,而不是下降到 360px。沒有理由我們所有流體表達式的起始點和結束點需要與相同的寬度對齊,因此我們可以將其他表達式流暢地降低到 360px。

使用我可靠的計算器,我們只需要更改背景位置屬性的clamp()表達式:

<div>
  <div>
    <h1>LookOut</h1>
    <p>Eagle Defense System</p>
  </div>
</div>
登入後複製
登入後複製
登入後複製

這改善了情況,但並非完全改善。我不想更快地移動它,所以接下來我們將看看文本的路徑。目前它沿直線移動,如下所示:

但是我們可以彎曲它嗎?是的,我們可以。

路徑中的彎曲

我們可以做到這一點的一種方法是為頂部坐標定義兩個不同的插值,將直線放置在不同的角度,然後選擇最小的一個。這樣,它允許更陡峭的直線在更大的容器寬度處“獲勝”,而較淺的直線在容器寬度小於約 780px 時成為獲勝的值。結果是一條帶有彎曲的直線,它錯過了狐獴。

我們只更改top值,但我們必須首先計算兩個中間值:

#hero {
  container-type: inline-size;
  max-width: 1200px;
  min-width: 360px;

  .details {
    position: absolute;
    z-index: 2;

    top: 220px;
    left: 565px;

    h1 { font-size: 5rem; }

    p { font-size: 2.5rem; }
  }

  &::before {
    content: '';
    position: absolute;
    z-index: 1;

    top: 0; left: 0; right: 0; bottom: 0;

    background-image: url(../meerkat.jpg);
    background-origin: content-box;
    background-repeat: no-repeat;

    background-position-x: 0;
    background-position-y: 0;
    background-size: auto 589px;
  }
}
登入後複製
登入後複製
登入後複製

對於這些值,我並沒有使用精心選擇的中間點正式計算它們,而是嘗試了端點,直到得到我想要的結果。實驗與計算一樣有效,可以達到您需要的效果。在這種情況下,我從自定義變量中重複插值開始。我本可以使用容器查詢將路徑拆分為顯式部分,但這不會減少數學開銷,並且使用min()函數在我的眼中更簡潔。此外,這篇文章並非嚴格關於容器查詢,對吧?

現在文本沿此路徑移動。打開實時演示以查看其運行情況。

CSS 無法做到一切

最後關於計算的一點說明是,就我們能做什麼和不能做什麼而言,存在限制。第一個,我們已經稍微減輕了,那就是這些插值是線性的。這意味著不可能進行淡入淡出或其他復雜的行為。

另一個主要限制是CSS只能以這種方式生成長度值,因此無法在純CSS中應用例如基於容器或視口大小的流體不透明度或旋轉角度。預處理器也無法在這裡幫助我們,因為限制在於calc()在瀏覽器中的工作方式。

如果您準備依賴少量JavaScript,則可以解除這兩個限制。幾行代碼來觀察容器的寬度並設置一個無單位的CSS自定義屬性就足夠了。我將用它來使文本遵循二次貝塞爾曲線,如下所示:

這裡代碼太多,無法列出,數學解釋貝塞爾曲線也太多,但請在實時演示中查看其運行情況。

如果像calc(1vw / 1px)這樣的表達式在CSS中沒有失敗,我們甚至不需要JavaScript。它們沒有失敗的理由,因為它們表示兩個長度之間的比率。就像1英寸中有2.54厘米一樣,當視口寬度為800px時,1vw中有8px,因此calc(1vw / 1px)應該計算為無單位的8值。

但它們確實失敗了,所以我們所能做的就是陳述我們的觀點然後繼續前進。

流體一切並不能解決所有佈局

當然,總有一些佈局需要大小查詢;有些設計只需要在固定的斷點處進行更改。如果合適,沒有理由避免這樣做。也沒有理由避免混合兩者,例如,通過流暢地調整背景大小和位置,同時使用查詢在文本放置的網格定義之間切換。我的狐獴示例故意設計得很簡單,是為了演示的目的。

我要補充一點的是,我對使用新的錨點定位API進行流體定位的可能性感到非常興奮。有可能使用錨點定位來定義兩個元素如何一起在屏幕上流動,但這留待以後再討論。

以上是流體其他一切的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板