基於視口的CSS夾具線性縮放字體大小
響應式排版過去嘗試過多種方法,例如媒體查詢和CSS calc()。
本文將探討一種不同的方法,即隨著視口寬度增加,在最小和最大尺寸之間線性縮放文本,目的是使其在不同屏幕尺寸下的行為更可預測——所有這些都只需一行CSS 代碼,這要歸功於clamp()
。
CSS 函數clamp()
功能強大。它對各種用途都有效,但對於排版尤其有用。其工作原理如下:它接受三個值:
<code>clamp(minimum, preferred, maximum);</code>
它返回的值將是首選值,直到該首選值低於最小值(此時將返回最小值)或高於最大值(此時將返回最大值)。
那麼,假設您沒有設置奇怪的值並在最小值和最大值之間設置它,它難道總是首選值嗎?嗯,您應該使用首選值的公式,例如:
<code>.banner { width: clamp(200px, 50% 20px, 800px); /* 是的,您可以在clamp() 中进行数学运算!*/ }</code>
假設您希望在視口寬度為360px 或以下時將元素的最小字體大小設置為1rem,並在視口寬度為840px 或以上時將最大字體大小設置為3.5rem。
換句話說:
<code>1rem = 360px 及以下缩放= 361px - 839px 3.5rem = 840px 及以上</code>
任何介於361 像素和839 像素之間的視口寬度都需要一個在1rem 和3.5rem 之間線性縮放的字體大小。使用clamp()
實際上非常容易!例如,在視口寬度為600 像素(介於360 像素和840 像素之間)的情況下,我們將獲得1rem 和3.5rem 之間的中間值,即2.25rem。
我們嘗試使用clamp()
實現的目標稱為線性插值:獲取兩個數據點之間的中間信息。
以下是執行此操作的四個步驟:
步驟1
選擇最小和最大字體大小,以及最小和最大視口寬度。在我們的示例中,字體大小為1rem 和3.5rem,寬度為360px 和840px。
步驟2
將寬度轉換為rem。由於大多數瀏覽器上的1rem 默認情況下為16px(稍後會詳細介紹),因此我們將使用它。因此,最小和最大視口寬度將分別為22.5rem 和52.5rem。
步驟3
在這裡,我們將稍微偏向數學方面。當組合在一起時,視口寬度和字體大小在X 和Y 坐標系上形成兩點,而這些點構成一條線。
我們需要這條線——更具體地說,我們需要它的斜率及其與Y 軸的交點。以下是計算方法:
<code>slope = (maxFontSize - minFontSize) / (maxWidth - minWidth) yAxisIntersection = -minWidth * slope minFontSize</code>
這使我們得到斜率值為0.0833,Y 軸交點值為-0.875。
步驟4
現在我們構建clamp()
函數。首選值的公式為:
<code>preferredValue = yAxisIntersection[rem] (slope * 100)[vw]</code>
因此,該函數最終如下所示:
<code>.header { font-size: clamp(1rem, -0.875rem 8.333vw, 3.5rem); }</code>
您可以在以下演示中可視化結果:
繼續操作並試用它。如您所見,當視口寬度為840px 時,字體大小停止增長,當視口寬度為360px 時,字體大小停止減小。介於兩者之間的所有內容都以線性方式變化。
如果用戶更改根字體大小怎麼辦?
您可能已經註意到這種方法的一個小缺陷:它只有在根字體大小是您認為的大小(在前面的示例中為16px)並且從不更改時才有效。
我們通過將其除以16 來將寬度360px 和840px 轉換為rem 單位,因為我們假設這是根字體大小。如果用戶將其首選項設置為另一個根字體大小,例如18px 而不是默認的16px,則該計算將出錯,並且文本不會按我們預期的那樣調整大小。
我們這裡只有一種方法可以使用,那就是(1) 在頁面加載時在代碼中進行必要的計算,(2) 偵聽根字體大小的變化,以及(3) 如果發生任何變化,則重新計算所有內容。
這是一個有用的JavaScript 函數來進行計算:
// 獲取以像素為單位的視口寬度和以rem 為單位的字體大小function clampBuilder(minWidthPx, maxWidthPx, minFontSize, maxFontSize) { const root = document.querySelector("html"); const pixelsPerRem = Number(getComputedStyle(root).fontSize.slice(0, -2)); const minWidth = minWidthPx / pixelsPerRem; const maxWidth = maxWidthPx / pixelsPerRem; const slope = (maxFontSize - minFontSize) / (maxWidth - minWidth); const yAxisIntersection = -minWidth * slope minFontSize; return `clamp(${minFontSize}rem, ${yAxisIntersection}rem ${slope * 100}vw, ${maxFontSize}rem)`; } // clampBuilder(360, 840, 1, 3.5) -> "clamp(1rem, -0.875rem 8.333vw, 3.5rem)"
我故意省略了如何將返回的字符串注入CSS 中,因為根據您的需求以及您是否使用的是原生CSS、CSS-in-JS 庫或其他內容,有很多方法可以做到這一點。此外,沒有針對字體大小更改的原生事件,因此我們必須手動檢查。我們可以使用setInterval
每秒檢查一次,但這可能會影響性能。
這更像是一個極端情況。很少有人更改其瀏覽器的字體大小,甚至更少的人會在訪問您的網站時更改它。但是,如果您希望您的網站盡可能具有響應能力,那麼這就是最佳方法。
對於那些不介意極端情況的人
更新:自從本文首次發表以來,此處共享的資源已停止工作。如果您正在尋找計算器來幫助確定各種視口下的字體大小,請考慮使用Fluid Type Generator,它利用現代流體排版技術。
如何避免文本重新調整
對排版尺寸進行如此細緻的控制使我們能夠做其他很酷的事情——例如阻止文本在不同的視口寬度下重新調整。
這就是文本的正常行為。
但是現在,有了我們的控制,我們可以使文本保持相同的行數,始終在同一個單詞處換行,無論我們使用什麼視口寬度。
那麼我們該如何做到這一點呢?首先,字體大小和視口寬度之間的比率必須保持不變。在此示例中,我們從320px 處的1rem 變為960px 處的3rem。
<code>320 / 1 = 320 960 / 3 = 320</code>
如果我們使用前面編寫的clampBuilder()
函數,則會變成:
const text = document.querySelector("p"); text.style.fontSize = clampBuilder(320, 960, 1, 3);
它保持相同的寬度與字體比率。我們這樣做的原因是,我們需要確保文本在每個寬度下都具有正確的大小,以便能夠保持相同的行數。它仍然會在不同的寬度下重新調整,但這對於我們接下來要做的工作是必要的。
現在我們必須從CSS 字符(ch) 單位獲得一些幫助,因為僅具有正確的字體大小是不夠的。一個ch 單位相當於元素字體中字形“0”的寬度。我們希望使文本主體與視口一樣寬,不是通過設置width: 100%
,而是使用width: Xch
,其中X 是水平填充視口所需的ch 單位(或0)的數量。
要查找X,我們必須將最小視口寬度320px 除以元素在視口寬度為320px 時的字體大小處的ch 大小。在這種情況下為1rem。
別擔心,這裡有一個代碼片段來計算元素的ch 大小:
// 返回元素在所需字體大小下的“0”字形的寬度(以像素為單位) function calculateCh(element, fontSize) { const zero = document.createElement("span"); zero.innerText = "0"; zero.style.position = "absolute"; zero.style.fontSize = fontSize; element.appendChild(zero); const chPixels = zero.getBoundingClientRect().width; element.removeChild(zero); return chPixels; }
現在我們可以繼續設置文本的寬度:
function calculateCh(element, fontSize) { ... } const text = document.querySelector("p"); text.style.fontSize = clampBuilder(320, 960, 1, 3); text.style.width = `${320 / calculateCh(text, "1rem")}ch`;
哇,等等。發生了一些不好的事情。有一個水平滾動條弄亂了事情!
當我們談論320px 時,我們談論的是視口的寬度,包括垂直滾動條。因此,文本的寬度設置為可見區域的寬度加上滾動條的寬度,這使其水平溢出。
那麼為什麼不使用不包含垂直滾動條寬度的度量呢?我們不能,這是因為CSS vw 單位。請記住,我們正在使用clamp()
中的vw 來控製字體大小。您會看到,vw 包括垂直滾動條的寬度,這使得字體會隨著包括滾動條在內的視口寬度一起縮放。如果我們想要避免任何重新調整,則寬度必須與視口寬度成比例,包括滾動條。
那麼我們該怎麼做呢?當我們這樣做時:
text.style.width = `${320 / calculateCh(text, "1rem")}ch`;
……我們可以通過將其乘以小於1 的數字來縮小結果。 0.9 可以解決問題。這意味著文本的寬度將是視口寬度的90%,這將足以彌補滾動條佔用的小空間。我們可以通過使用更小的數字(例如0.6)來使其更窄。
function calculateCh(element, fontSize) { ... } const text = document.querySelector("p"); text.style.fontSize = clampBuilder(20, 960, 1, 3); text.style.width = `${320 / calculateCh(text, "1rem") * 0.9}ch`;
您可能會傾向於簡單地從320 中減去幾個像素以忽略滾動條,如下所示:
text.style.width = `${(320 - 30) / calculateCh(text, "1rem")}ch`;
這樣做的問題是它會使重新調整問題恢復!這是因為從320 中減去會破壞視口與字體的比率。
文本的寬度必須始終是視口寬度的百分比。另一件需要注意的事情是,我們需要確保我們在使用該網站的每台設備上都加載相同的字體。這聽起來很明顯,不是嗎?嗯,這裡有一個小細節可能會使您的文本偏離。執行諸如font-family: sans-serif
之類的事情並不能保證在每個瀏覽器中都使用相同的字體。 sans-serif
將在Windows 版Chrome 上設置Arial,但在Android 版Chrome 上設置Roboto。此外,某些字體的幾何形狀可能會導致重新調整,即使您做對了所有事情也是如此。等寬字體往往會產生最佳結果。因此,請務必確保您的字體準確無誤。
在以下演示中查看此非重新調整示例:
容器內的非重新調整文本
我們現在要做的就是將字體大小和寬度應用於容器,而不是直接應用於文本元素。其中的文本只需要設置為width: 100%
。對於段落和標題,這並不是必需的,因為它們本身就是塊級元素,並且會自動填充容器的寬度。
在父容器中應用此方法的一個優點是,其子元素將自動響應和調整大小,而無需逐個設置其字體大小和寬度。此外,如果我們需要更改單個元素的字體大小而不影響其他元素,我們只需將其字體大小更改為任何em 值,它就會自然地相對於容器的字體大小。
非重新調整文本很挑剔,但它是一種微妙的效果,可以為設計帶來不錯的效果!
總結
為了總結,我整理了一個關於所有這些如何在現實場景中看起來的小演示。
在此最終示例中,您還可以更改根字體大小,並且clamp()
函數將自動重新計算,以便文本在任何情況下都能具有正確的大小。
儘管本文的目標是將clamp()
與字體大小一起使用,但此相同的技術可用於接收長度單位的任何CSS 屬性。現在,我並不是說您應該在任何地方都使用它。很多時候,一個好的font-size: 1rem
就足夠了。我只是想向您展示需要時您可以擁有多少控制權。
就我個人而言,我相信clamp()
是CSS 中最好的東西之一,我迫不及待地想看看隨著它的越來越廣泛使用,人們會想出哪些其他用法!
以上是基於視口的CSS夾具線性縮放字體大小的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

您是否曾經在項目上需要一個倒計時計時器?對於這樣的東西,可以自然訪問插件,但實際上更多

在元素個數不固定的情況下如何通過CSS選擇第一個指定類名的子元素在處理HTML結構時,常常會遇到元素個數不�...

關於Flex佈局中紫色斜線區域的疑問在使用Flex佈局時,你可能會遇到一些令人困惑的現象,比如在開發者工具(d...

格子呢是一塊圖案布,通常與蘇格蘭有關,尤其是他們時尚的蘇格蘭語。在Tartanify.com上,我們收集了5,000多個格子呢
