目录
步骤 4
如果用户更改根字体大小怎么办?
对于那些不介意极端情况的人
如何避免文本重新调整
容器内的非重新调整文本
总结
首页 web前端 css教程 基于视口的CSS夹具线性缩放字体大小

基于视口的CSS夹具线性缩放字体大小

Apr 02, 2025 am 04:21 AM

Linearly Scale font-size with CSS clamp() Based on the Viewport

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

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

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

AI Clothes Remover

AI Clothes Remover

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

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

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

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

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

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

VUE 3 VUE 3 Apr 02, 2025 pm 06:32 PM

它的出局!恭喜Vue团队完成了完成,我知道这是一项巨大的努力,而且很长时间。所有新文档也是如此。

您可以从浏览器获得有效的CSS属性值吗? 您可以从浏览器获得有效的CSS属性值吗? Apr 02, 2025 pm 06:17 PM

我有人写了这个非常合法的问题。 Lea只是在博客上介绍了如何从浏览器中获得有效的CSS属性。那样的是这样。

在CI/CD上有点 在CI/CD上有点 Apr 02, 2025 pm 06:21 PM

我说的“网站”比“移动应用程序”更合适,但我喜欢Max Lynch的框架:

带有粘性定位的堆叠卡和一点点的杂物 带有粘性定位的堆叠卡和一点点的杂物 Apr 03, 2025 am 10:30 AM

前几天,我发现了科里·金尼文(Corey Ginnivan)网站上的这一点,当您滚动时,彼此之间的卡片堆放集。

在WordPress块编辑器中使用Markdown和本地化 在WordPress块编辑器中使用Markdown和本地化 Apr 02, 2025 am 04:27 AM

如果我们需要直接在WordPress编辑器中向用户显示文档,那么最佳方法是什么?

比较浏览器的响应式设计 比较浏览器的响应式设计 Apr 02, 2025 pm 06:25 PM

这些桌面应用程序中有许多目标是同时在不同的维度上显示您的网站。因此,例如,您可以写作

如何将CSS网格用于粘头和页脚 如何将CSS网格用于粘头和页脚 Apr 02, 2025 pm 06:29 PM

CSS网格是一系列属性的集合,旨在使布局比以往任何时候都容易。像任何东西一样,那里有一点学习曲线,但是网格是

Google字体可变字体 Google字体可变字体 Apr 09, 2025 am 10:42 AM

我看到Google字体推出了新设计(Tweet)。与上一次大型重新设计相比,这感觉更加迭代。我几乎无法分辨出区别

See all articles