CSS 字体的制作(及其潜在优势)

Avatar of Levi Szekeres
Levi Szekeres

DigitalOcean 为您旅程的每个阶段提供云产品。 立即开始使用 $200 免费积分!

至少不是普通的字体。 每个字符都是一个 HTML 元素,使用 CSS 构建而成。 真正的网络字体!

让我详细解释一下。 这是一种无需使用任何字体即可呈现文本的方法。 随机文本使用 PHP 拆分为单词和字母,然后作为带有类的 HTML 元素呈现。 每个元素都使用 CSS 进行样式设置以创建字符。 这“仅仅”是使用 CSS 控制的 HTML,但它仍然是软件,并且能够传递信息。 它具有传统字体的所有属性,因此我们将它称为字体。 一种没有格式的字体。

免责声明: 我不是 HTML、CSS 或 PHP 方面的专家。 我敢肯定,这里存在实现我所做事情的捷径或更简单的解决方案,但由于我对结果感到满意,因此我将介绍该过程和我的经验。 本介绍不是教程; 它基于我有限技能的实验,应以这种方式对待。

想法

这个项目原本不打算持续五个月,但事实证明确实花了这么久! 一切都始于玩一个 CSS 图标,使用伪元素来制作 形状。 第一个 S 字母完成后,其余字母就相对容易了。 我查看了是否有其他类似的项目,但没有发现太多,因此我更有动力去看看我能做到什么程度。

最初,一个使用 CSS 控制的 SVG 字体似乎是一个好主意。 它会使这项任务变得容易得多(SVG 专门用于绘图),并且可以专注于特定于设计的效果,但它没有原始 HTML 元素的灵活性。 SVG 无法根据上下文进行修改,并且该过程会回退到传统的字体设计,其中每个字符都有一个固定的形状和代码。

工作原理

这是一种网络和字体设计的混合体。 每个字符都像任何网络元素一样构建,并内联使用以像字体一样工作。 度量、权重、OpenType 功能以及所有其他字体属性都是通过 CSS 文件独家控制的。

字体设计基于元素的边框宽度,这使得它非常通用。 除脚本字体外,只需使用相同的形状,通过边框的变化即可产生多种样式和权重。 在更复杂的字符上,使用裁剪路径和背景来创建剪切效果。

::before::after 伪元素不足以形成字符时,会生成嵌套元素。 使用 em 值作为宽度、高度和边框宽度将有助于以后控制字体大小。 这是黄金法则之一。

字符(左侧)像任何 CSS 图标(右侧)一样构建。 它们之间没有重大差异。 有时一个字母很容易构建,就像一个简笔画人一样,基于圆形和线条。 但这就是您真正能够欣赏 border-radius 属性作用的地方。 我个人从来不喜欢圆角边框,但这段经历改变了我的想法。 基本上,半径可以做到的没有限制。

以下是本文中 CSS 字体的两个“真实”示例,其余示例图已转换为 SVG,以便在博客文章中更容易显示。

1. 灰色 - 主要形状
2. 红色 - 伪元素
3. 蓝色 - 额外元素
大多数情况下,您必须坚持要求得到想要的效果,但最终您希望将此图标放在您的钱包里。 图标使用单个形状创建,伪元素仅用于避免主元素旋转,以防它内联使用。

衬线预览呈现了一种更复杂的情况,但通常,无衬线字体将具有更少的元素要处理,从而使文件更小,加载速度更快。 这其实不是什么问题,而且这是合乎逻辑的——CSS 在使用 @font-face 规则嵌入字体之前读取。

挑战

天真的开始,将所有数学和逻辑付诸实践。 如果一个像素决定这样做,那么没有一个值会起作用。 在这种情况下,最终的解决方案是包含第二个父级,它将使“子级”保持整齐。

最难的部分是克服像素比,或者将伪元素与基本形状对齐。 当字符调整大小时,复杂的数学公式会失败。 浏览器会将每个元素单独处理,并将其移到最接近的整数。

一种解决方案是尽可能多地创建伪元素(甚至包括额外的元素),并使用一个参考来引用一对 ::before::after,与主形状无关。 在这种情况下,浏览器将或多或少地将元素渲染到相同的位置。

下面用 S 字母说明了一个没有参考点的字符。 字母的顶部和底部部分是两个伪元素,没有基本形状可以依赖(例如,上面衬线中的灰色区域或这里数字二中的灰色区域)。

在创建了几百个字符后,您会意识到一个字符不能支持内联变换(即 skew()rotate() 等),因为它不会与兄弟元素对齐。 在文本选择中,这在视觉上更加明显。 因此,伪元素非常有意义。 我会说它至关重要:第二条黄金法则。

该图形显示了基本构建原理。 当孔径无法简单地使用 {border: 0;} 规则控制时,使用 clip-path
在这种情况下,S 字母需要更小的孔径,因此最终会保留边框,并使用 clip-path 在所需距离处进行裁剪。

CSS 自定义属性

在 CSS 中创建样式似乎比在字体软件中更容易。 您可以选择同时控制多个字符的形状和大小。 在 CSS 中,更多字符在同一个规则集中分组。

CSS 自定义属性在这种情况下非常方便,尤其是在控制边框、宽度和位置方面。 不同的权重是变量更改的结果,之后进行了调整。 微调是不可避免的,因为字符形状和大小会考虑边框宽度,并且可能不会随着不同边框按比例显示,尤其是在非对称形状上。

通过将相同的背景色添加到覆盖元素来创建剪切效果。 使用 mix-blend-mode 结合颜色和效果。

剪切效果是通过将相同的背景色添加到覆盖元素,然后使用 mix-blend-mode 结合颜色和效果来创建的。

CSS 中需要一个全局颜色变量来创建嵌套元素的剪切效果,否则这些元素会遵循父级颜色(覆盖元素与背景匹配)。

background-image 属性不适用于仅使用边框构建的字符,如果元素具有大小或位置变换(缩放、旋转或其他),背景将发生更改。

在无法使用背景的情况下,解决方案是 mix-blend-mode: lighten; 在深色背景上和 mix-blend-mode: darken; 在浅色背景上。

副作用

缺点是,某些效果可能会对具有可变属性的元素产生意外甚至相反的结果。 通常,filter 会将元素读取为完整对象。 为了防止任何冲突,边框和变换效果保留用于字体设计。

字体到文本

字体不会生成文本。 最初的想法是创建一个文本,该文本将与 CSS 一起加载,没有任何依赖项。 为此,最佳选择是 PHP(我的菜鸟观点)。 除了使用内联函数呈现 HTML 外,它几乎可以完成任何可以想象的任务。 没有 PHP,这个项目就不可能实现。

当然,PHP 的第一个任务是拆分随机文本,删除多余的空格,并为每个单词和字母创建匹配组,每个组都有自己的类。 到目前为止一切顺利。 我不会强调顺利完成的部分,这是一个基本函数,使用 split、explode 以及所有其他从视频游戏中借用的词语。

尽管如此,由于我以前从未做过这个,因此我不得不从错误中学习。 没有人告诉我 PHP 将“0”(零)视为 null,因此一天就这样过去了。 我不明白为什么我的零没有显示出来。

对于遇到此问题的任何人来说,也许它会有所帮助。 我没有使用 empty() 函数,而是使用了下面的函数

function is_blank( $value ) {  
  return empty( $value ) && !is_numeric( $value );
}

另一个主要问题是字符范围。 似乎 HTML、.htaccess 文件以及服务器本身中存在太多设置,仅用于识别特殊字符。 该解决方案是在几天后从 PHP 文档 中找到的,由 qeremy [atta] gmail [dotta] com 发布,显然是住在重音符号密集区域的人。

function str_split_unicode( $str, $length = 1 ) {
  $tmp = preg_split( '~~u', $str, -1, PREG_SPLIT_NO_EMPTY );
  if ( $length > 1 ) {
    $chunks = array_chunk( $tmp, $length );
    foreach ( $chunks as $i => $chunk ) {
        $chunks[$i] = join( '', ( array ) $chunk );
    }
    $tmp = $chunks;
  }
  return $tmp;
}

恕我直言,有很多代码块,但这确实像个魔法,解决了所有问题。该函数基本上会忽略语言设置,读取任何字符,即使是非标准字符。如果 PHP 函数包含该字符,则 Unicode 表格中深层的字符也将被识别。

此函数仅提供生成每个输入字符的可能性,无需使用 HTML 实体。此选项不会限制在 HTML 格式中使用文本,但应避免使用内联代码或使用其他方法替换它们。例如,可以使用 `<nobr>` 标签将元素包装起来,而不是使用不换行空格 ( `&nbsp;` )。

HTML 实体不会被解码,从我的角度来看,这是一个优势。
左侧是默认系统字体,右侧是未经任何修改的 CSS 文本呈现。

结构

解决了这个问题之后,下一步是为每个字符创建特定的结构。HTML 元素的类和嵌套元素的位置取决于与一个或多个类相对应的长字符列表。一些最基本的字符也不包含在此列表中(例如,小写字母“a”需要一个收笔,这意味着需要一个额外的元素/类)。

为了便于理解,基本结构如下所示...

'Ć' => 'Cacute C acute'

...它将呈现三个元素:父级 Cacute、字母 C 和锐音符。结果如下所示,其中红色正方形代表父级元素,包含另外两个预设元素。

Cacute — 一个基本的字母和一个重音符的经典组合。

该技术非常类似于字形软件中基于配对构建变音符号(有时是连字)的方式。当一个组件元素发生改变时,其他所有元素都会进行调整。

由于任何元素都可以有多种应用,因此避免使用 ID,只使用类。

OpenType 特性

PHP 函数被设置为根据上下文表现出不同的行为。字符识别被设置为替换配对并在呈现 CSS 文本时创建连字。

CSS 文本中的上下文连字不是独立字符,没有特定的类。与传统的 OpenType 特性不同,字符的样式被重新设计,而不是被替换。通过对第二个元素进行样式设置来控制交互,以合并或形成一个新字符。

这些特性通过向父容器添加一个特定的类来激活。无论字符是否注册,在任何情况下都会呈现替代项,在任何浏览器中,无论是否有字体特性支持。

序数指示符特性的示例,通过 ` .ordn ` 类激活。字符的样式是内联的,根据类和之前的同级元素改变外观。同样的方法也适用于样式替换 ( ` salt ` )、旧式数字 ( ` onum ` )、斜线零 ( ` slsh ` )、上标 ( ` sups ` )、下标 ( ` subs ` ) 和分数 ( ` frac ` )。
具有类似于 OpenType 功能的类以 Microsoft/Adobe 的 注册特性 命名。

HTML 语法

任何 HTML 元素都可以包含 CSS 字体,只要它在字体权重旁边具有 ` .css ` 类。要选择权重,请使用 ` .thin `、` .light `、` .regular ` 或 ` .bold ` 类,例如 ` <pre class="regular css"> `(` <pre> ` 标签仅仅是一个安全措施,以避免任何样式干扰)。

可用的权重:细体、细斜体、常规体和粗体。

文本可以具有 HTML 格式。纯文本不是必需的。

如果括号 ( ` < ` ) 具有相应的结束符号,则 PHP 会忽略它,这意味着文本中的每个 HTML 标签都将保持活动状态,只有文本内容被呈现为 CSS 字体。浏览器以相同的方式编码标签中找到的 URL、文件路径或其他附加信息。如果在 CSS 中设置了这些标签,则它们可以为字母组或整个句子设置样式。

此外,根据布局首选项,特定的标签(例如 ` <a> `、` <u> `、` <ins> ` 和 ` <del> `)可以被视为对象,以模拟和自定义其原生外观和行为。

设置

CSS 文本是一组带有边框的对象,可以进行大小和颜色处理。将颜色视为 ` border-color `,反之亦然。使用 ` :first-child ` 而不是 ` :first-letter `。

在 CSS 文件中设置 ` font-size `,与其他字体相同,使用视窗、百分比、像素、em 或 rem 单位。以像素为单位的值可以使用小数。

` text-align ` 和 ` text-indent ` 属性默认情况下可用。即使没有文本内容,文本也会对齐到任何设置。

放置在文本内的块级元素(例如 ` <div> `、` <p> `、` <ol> `)会导致换行,就像通常情况下那样。` <br> ` 标签按预期工作。

除了文本格式化元素(例如 ` <h1> `–` <h6> `、` <strong> `、` <em> `、` <small> `、` <sup> `、` <sub> ` 等),它们需要新的规则才能对文本产生正确的影响,大多数语义元素(例如 ` <form> `、` <ol> `、` <li> `)使用其自定义设置。

字体

为了在动态内容中测试字体,PHP 函数的一部分在 JavaScript 中被复制,包括粘贴、鼠标事件、光标位置和文本选择。现在,只需按一下键就可以实现所有这些功能。

CSS 字体和补充图标。这正是整个事情的开始!

评论!优点 (+) vs. 缺点 (-)

即时加载

在没有实际文本的情况下,浏览器不会等待字体和脚本呈现页面。CSS 文件以及 HTML 元素会被缓存,这意味着更快的加载速度。

通用性

每个浏览器和服务器都识别 CSS。减少对找到在每个浏览器中都具有相同效果的正确格式的担忧。服务器不会检查特定格式以允许访问。

无依赖性

CSS 字体不需要备用字体或系统字体来显示文本。与页面样式相同的 CSS 可以包含字体。浏览器不会显示默认字体,无论是在页面加载之前还是之后。字体不依赖于第三方和脚本,设计在禁用脚本的浏览器中也不会不同。

无嵌入

CSS 字体完全集成到网页中,并在加载时适应布局,而不会替换其他元素。每个页面属性都自动适用于文本,并将按预期显示,没有任何后遗症或功能问题。

选择性使用

字体可以减少到有限数量的字符。例如,如果布局只有一个单词或一个符号,则不需要完整版本。

完全安全

实际文本不存在于页面上,这意味着可以轻松显示敏感信息,而无需担心垃圾邮件或网络钓鱼。

SEO 友好

可以使用标签属性包含重要信息,就像 alt 属性对图像的作用一样。

可定制

为了构建复杂的字符或功能,字体对任何 HTML 元素开放。无需脚本即可获取特定详细信息,因为每个单词和字母都有自己的实体,可以单独设置样式。

上下文

字体设计不限于预定义的字符,因此样式可以根据上下文更改,而无需创建新字符。

一致

为了弥补字体软件中缺乏自动化,在 CSS 中,设计可以同时控制多个元素。此论点是有效的,因为字体软件使用现有内容,而 CSS 使用属性,为所有现有或未来元素创建模板。

公开

任何人都可以创建自己的字体。简短的文本可以手动渲染,PHP 函数不是必需的。

基础

可以使用任何文本编辑器或开发人员工具访问设计。使用边框宽度、边框半径、形状和尺寸的基本技能足以重新设计任何字符。

实时

每个调整结果都是即时的。转换、导出、上传或其他激活字体的步骤已从流程中消除。

适度使用

如果为扩展文本生成 CSS 字体,页面速度可能会受到影响。因此,此技术仅推荐用于标题、标题、摘录和简短段落。

常见

CSS 字体不会受益于特殊处理,因为对于浏览器来说,这只是一个普通的 HTML 元素。因此,没有优化或字距调整支持。像素难以共享细线,并且在小尺寸下,字体可能会显示不正常。

硬编码

默认情况下,您通常的字体设置不可用,并且样式标签(例如<strong><em>等)无效。必须在 CSS 文件中设置函数,并且需要不同的方法,使用 HTML 元素而不是字体。

独家

这是一个网络字体,因此它仅限于使用 CSS 控制的数字媒体。除了某些位图效果,字体只能通过将文档打印为 PDF 进行离线转换,这将把 CSS 转换为矢量格式。

抽象

如果没有独立文件,字体很难识别、测试或传输。它就像 HTML 颜色:在生成之前是不可见的。

不可选

如果没有额外的脚本,文本就无法在输入框和文本区域中被选中或使用。对于动态内容,该函数需要在 PHP 中找到的完整字符识别。

非交互式

最常见的显示功能,例如sortfilter,必须与类一起使用,而不是与文本内容一起使用。

不可打印

在线打印仅支持基本 CSS 规则,有时会忽略图形,而选择文本。打印质量将严格依赖于浏览器的功能。

无辅助功能

CSS 字体会根据页面缩放进行调整,但字体大小和语言无法通过浏览器更改。
自定义浏览器功能(例如查找、阅读器)无法访问文本内容,因为没有文本内容。

设计有限

没有多种样式可供选择,设计仅限于 CSS 的功能。CSS 规则对不同的浏览器可能具有不同的含义,导致不一致。CSS 字体是书写的,而不是绘制的,因此完全消除了“手工制作”的概念。

多任务

您需要了解 CSS 才能对字体进行调整,反之亦然。设计过程不是自动化的,一些原本由机器生成的属性必须手动设置。

无保护

设计代码对任何人都可见,与任何在线元素一样。设计无法真正防止未经授权的复制和使用。


感谢您的阅读!这是字体的首页。