响应式排版过去尝试过多种方法,例如媒体查询和 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中文网其他相关文章!

文章讨论了CSS FlexBox,这是一种布局方法,用于有效地对齐和分布响应设计中的空间。它说明了FlexBox用法,将其与CSS网格进行了比较,并详细浏览了浏览器支持。

本文讨论了使用CSS创建响应网站的技术,包括视口元标签,灵活的网格,流体媒体,媒体查询和相对单元。它还涵盖了使用CSS网格和Flexbox一起使用,并推荐CSS框架

本文讨论了CSS盒装属性,该属性控制了元素维度的计算方式。它解释了诸如Content-Box,Border-Box和Padding-Box之类的值,以及它们对布局设计和形式对齐的影响。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

ZendStudio 13.5.1 Mac
功能强大的PHP集成开发环境

mPDF
mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

SecLists
SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。

适用于 Eclipse 的 SAP NetWeaver 服务器适配器
将Eclipse与SAP NetWeaver应用服务器集成。

MinGW - 适用于 Windows 的极简 GNU
这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。