生成 "font-size "CSS规则并创建一个流畅的字体比例(附代码)

307 阅读8分钟

让我们揭开字体大小的神秘面纱。排版既是任何样式表的基础,也是将一个最小的布局从单调乏味提升到精彩纷呈的最快捷方式。如果你正在寻找字体设计理论或如何选择字体,那就超出了本文的范围。今天的目标是给你一个在CSS中开发基本类型样式的基础,以及如果你想深入探索任何主题时可以使用的术语。

本集内容包括:

  • 推荐使用的单位font-size
  • 用Sass生成基于比例的font-size
  • 推荐的属性,以防止长字/名称/URL的溢出
  • 定义视口感知的流体类型比例规则,包括clamp()
  • 处理类型的额外建议

定义 "类型比例"#

简化的定义:网络上的 "类型比例 "是指诸如font-sizeline-height ,以及通常的margin ,这些属性共同在你的设计中创造垂直的节奏。这些可以是任意选择的("它只是看起来不错"),也可以是基于 "模块尺度 "的想法,采用基于比例的大小。

至少,它涉及到在font-sizeline-height 上设置一个基础body ,段落和列表项等元素将默认继承该基础。

然后,在标题元素上设置font-sizeline-height ,特别是在一般使用的h1-h4 水平。

那么,h5h6 呢?

某些情况下,关心第5级和第6级可能会有好处,但重要的是,当真正需要的是一种视觉风格时,不要使用标题标签。过度使用标题标签会造成噪音,或者在其他元素更适合这种情况下,给辅助技术带来不良的信息层次。

font-size#选择一个单位

px,%,rem, 和em, oh my!

第一个升级是在定义排版时忘记px 。它并不理想,因为它不能与用户的默认font-size ,他们可能已经设置为浏览器的偏好,或通过使用缩放来实现比例。

相反,建议你的主要字体比例值用rem

除非用户改变它,或者你在html 规则上用font-size 来定义它,否则默认的rem 值是16px,其优点是可以响应操作系统缩放级别的变化。

此外,无论嵌套多深,rem 的值都不会改变,这在很大程度上使得它成为排版尺寸的首选值。

几年前,你可能已经开始将你的font-size 值切换到em 。让我们学习一下其中的区别。

em 将保持与该元素或最近的祖先的 规则相称。一个 相当于 ,所以默认情况下,这等于 。font-size em font-size 1rem

rem 相比,em 可以从父到子的复合,造成不利的结果。考虑下面这个列表的例子,font-size 被设置在em 中,并为嵌套的列表复合。

em 当相对于元素的间距的行为是所期望的效果时,Espresso就会大放异彩。

一个用例是在按钮上,当图标相对于按钮文本的大小时。如果你有不同的按钮尺寸,使用em 可以使图标与按钮文本成比例,而不需要编写自定义图标尺寸。

百分比的行为几乎等同于em ,但通常在需要相对大小的时候,em 仍然是首选。

计算pxrem#

我的职业生涯是在市场营销和设计系统方面度过的,所以我可以理解你们这些被赋予基于px的设计规格的人的感受 :)

你可以通过假设1rem16px 来进行计算--或者使用在线计算器来为你做这些工作!

基线类型样式#

一个坚实的起点是要定义:

body {
  line-height: 1.5;
}

较早的建议可能会说使用100% ,而本文之前推荐1rem 。然而,body 可以继承的唯一元素是html ,这也是rem 单位取值的地方,所以在这里定义它是多余的。

因此,我们将只添加一条规则,这是为了可访问性。建议至少有1.5个line-height ,以保证可读性。这可能会受到各种因素的影响,特别是使用中的字体,但这是推荐的起始值。

防止文本溢出

我们可以添加一些面向未来的属性,以帮助防止由于长词、名字或URL而导致的溢出布局问题。

这是可选的,你可以选择将这些属性的范围扩大到基于组件的样式,或者创建一个实用类来更有选择地应用这种行为。

我们将把这些范围扩大到标题以及pli 作为我们的基准:

p,
li,
h1,
h2,
h3,
h4 {
  // Help prevent overflow of long words/names/URLs
  overflow-wrap: break-word;

  // Optional, not supported for all languages
  hyphens: auto;
}

在这一集的测试中,word-break: break-word; 似乎已经足够了,而回顾过去几年的文章,似乎推荐更多的属性来达到同样的效果。

hyphens 属性仍然缺乏支持,特别是当你可能要处理多语言内容时。然而,在这种情况下,它可以优雅地退回到根本没有连字符的状态,word-break ,仍然有帮助。对于某些类型的内容,如科学/医学内容,可能需要进行更多的测试,因为这些内容的长词是常态。

如果你发现这两个属性不能满足你的要求,那么这篇CSS-Tricks文章将深入介绍其他属性。

基于比率的类型标度

虽然我在介绍这一集时说我们不会涉及类型设计理论,但我们将使用 "类型尺度 "的概念来有效地生成font-size

基于比率的另一个术语是 "模块化",这里有一篇由A List Apart网站的Tim Brown撰写的介绍这个术语的好文章。

有一些命名的比率可用,我们的Codepen例子为它们创建了一个Sass地图,以方便参考:

$type-ratios: (
  "minorSecond": 1.067,
  "majorSecond": 1.125,
  "minorThird": 1.2,
  "majorThird": 1.25,
  "perfectFourth": 1.333,
  "augmentedFourth": 1.414,
  "perfectFifth": 1.5,
  "goldenRatio": 1.618,
);

使用选定的比率生成font-size

请听我说--我也不太喜欢数学。

好消息是,我们可以用Sass来做数学题,并根据任何提供的比例动态地输出样式🙌。

我们将定义两个变量来开始工作:

// Recommended starting point
$type-base-size: 1rem;

// Select by key of map, or use a custom value
$type-size-ratio: type-ratio("perfectFourth");

$type-size-ratio 是从前面预览的地图中选择perfectFourth 的比例,它等于1.333

CodePen演示了如何创建type-ratio() 自定义的Sass函数来按键检索比率值。对于在单个项目中使用,你可以完全跳过添加地图,直接将你选择的比率十进制值分配给 $type-size-ratio

接下来,我们定义标题级别,以建立我们的类型比例。如前所述,我们将关注h1-h4

我们创建一个变量来保存这些级别的列表,这样我们就可以在下一个步骤中循环浏览它们:

// List in descending order to prevent extra sort function
$type-levels: 4, 3, 2, 1;

这些列表从4 开始,因为h4 应该是最小的--也是最接近主体尺寸的--标题层。

是时候开始我们的循环并添加数学运算了。

首先,我们创建一个变量,我们将在循环的每个迭代中进行更新。首先,它使用$type-base-size 的值:

$level-size: $type-base-size;

如果你熟悉Javascript,我们创建的这个变量本质上是一个let 范围内的变量。

接下来,我们打开我们的@each 循环,遍历每一个$type-levels 。我们计算font-size 的值/重新分配$level-size 的变量。这就使$level-size ,以便随着每个标题级别的增加而扩大,然后乘以比率,得到最终的font-size

@each $level in $type-levels {
  $level-size: $level-size * $type-size-ratio;

  // Output heading styles
  // Assign to element and create utility class
  h#{$level} {
    font-size: $level-size;
}

考虑到perfectFourth 的比例,这导致了以下font-size 的值:

h4: 1.333rem
h3: 1.776889rem
h2: 2.368593037rem
h1: 3.1573345183rem

preview of 'perfectFourth' type sizes

line-height 和垂直间隔

至少,建议在这个循环中包含一个line-height 更新。预览图已经包括了这个定义,因为如果没有这个定义,大字体一般不会很好地继承1.5 规则。

从我们的用例来看,Jesús Ricarte最近发表的一篇文章非常及时,它提出了以下巧妙的计算方法。

line-height: calc(2px + 2ex + 2px);

ex 单位旨在等同于字体的x 高度。Jesús测试了一些解决方案,并设计了2px 缓冲区,以进一步接近一个能够缩放的适当的line-height 。它甚至可以与流体--又称 "响应式 "类型--一起缩放,我们接下来将创建这种类型。

至于垂直间距,如果你使用的是CSS重置,它可能包括为你清除排版元素上的所有或一个方向的空白。

通过检查器查看你的字体是否仍然从浏览器继承了边距样式。如果是的话,重新审视我们处理溢出的规则,并添加margin-top: 0

然后,在我们的标题循环中,我的建议是添加。

margin-bottom: 0.65em;

正如我们所学到的,em 是相对于font-size 的,所以通过使用它作为margin-bottom 的单位,我们将获得基本上是font-size 的 65% 的空间。你可以根据你的口味来试验这个数字,或者在大量的文章中探索关于字体系统中垂直节奏的更重的理论,找到你喜欢的理想。

流畅的字体--又称响应式排版

如果你选择了一个比例,导致相当大的font-size ,你很可能会在小的视口上遇到溢出问题,尽管我们之前尝试过预防。

这就是 "流体类型 "技术出现的原因之一。

流动类型是指以一种响应视口尺寸的方式来定义font-size ,从而导致尺寸的 "流动 "减少,特别是对于大字体。

有一个单一的现代CSS属性可以很好地处理这个问题:clamp

clamp() 函数需要三个值。使用它,我们可以设置一个最小允许的字体大小值、一个缩放值和一个最大允许值。这有效地为每个font-size ,并在其间过渡,而且由于视口单位的原因,它将发挥作用。

我们将保留我们现有的循环,因为我们仍然想要计算出的比率值。而且,我们设置的font-size 将成为尚未理解clamp() 的浏览器的后备方案。

但是--我们必须要做更多的数学运算😊

为了正确地进行数学运算,我们需要做一点黑客的工作(谢谢,CSS-Tricks的Kitty!),把单位从我们的$level-size

// Remove unit for calculations
$level-unitless: $level-size / ($level-size * 0 + 1);

接下来,我们需要计算出字体缩小到什么程度才是可以接受的:

// Set minimum size to a percentage less than $level-size
// Reduction is greater for large font sizes (> 4rem) to help
// prevent overflow due to font-size on mobile devices
$fluid-reduction: if($level-size > 4, 0.5, 0.33);
$fluid-min: $level-unitless - ($fluid-reduction * $level-unitless);

你可以根据自己的喜好来调整$fluid-reduction 这个变量的if/else值,但是这个定义是:对于$level-size 大于4rem ,我们将允许缩小到0.5 (50%)--而更小的尺寸则允许缩小到0.33 (33%)。

在伪数学中,这里是使用perfectFourth 的比例对h4 的情况。

$fluid-min: 1.33rem - (33% of 1.33) = 0.89311;

其结果是允许从基本的$level-size 值中减少33%。

伪数学实际上暴露了一个问题:这意味着h4 可能会缩减到$type-base-size 以下(提醒:这是基本的body 字体大小)。

让我们再添加一个护栏来防止这个问题。我们将仔细检查$fluid-min 的结果,如果它要低于1 --1rem 的无单位形式--我们就把它设置为1 (如果你有一个不同的$type-base-size ,就调整这个值)。

// Prevent dropping lower than 1rem (body font-size)
$fluid-min: if($fluid-min > 1, $fluid-min, 1);

我们缺少一个值,我称之为 "缩放器"--即导致流体缩放发生的值。它需要一个本质上会改变的值,以触发我们的最小和最大值之间的过渡。

因此,我们将采用视口单位--特别是vw ,或 "视口宽度"。当视口宽度改变时,这个值也将更新它的计算值。当它接近我们的最小值时,它将不会进一步缩小,而对于我们的最大值来说,情况正好相反。这就产生了 "流体 "类型的尺寸效果。

为了通过缩放保留可访问的尺寸,我们还将在我们的vw 值旁边添加1rem 。这有助于减轻(但不完全排除)仅使用视口单位的副作用。这是因为正如前面提到的,rem 单位将随着用户通过操作系统浏览器内缩放设置的缩放级别而缩放。为了满足WCAG成功标准1.4.4:调整文本大小,用户必须能够将字体大小增加到200%。

让我们来创建我们的缩放器值:

$fluid-scaler: ($level-unitless - $fluid-min) + 4vw;

这里应用的逻辑是得到上下限之间的差值,并将该值添加到所选择的视口单位中,在这里是4vw 。4或5的值似乎是流体排版建议中常见的,针对$type-ratios 的测试似乎显示4vw ,因为在整个缩放过程中,标题级别之间保持最清晰的定义。如果你有更多公式化的方法来得出视口值,请联系我们。

总的来说,我们的流体类型font-size 规则成为:

font-size: clamp(
        #{$fluid-min}rem,
        #{$fluid-scaler} + 1rem,
        #{$level-size}
      );

结束语...#

如果你真的读完了这一集,非常感谢你的坚持。我期待着你的反馈,请在DEVTwitter上联系我。排版有很多角度,"正确的方式 "是非常依赖于项目的。它可能是拥有最多利益相关者和对任何特定布局影响最大的一组属性。