在过去六年左右的时间里,我一直在我的网页设计工作中使用这些我称为“类型模式”的东西,它们对我来说效果很好。 我将深入探讨它们是什么以及它们如何进入 CSS,也许这个想法也会让你有所启发,并帮助你解决日常排版需求。
如果您使用过诸如 QuarkXPress、Adobe InDesign 或 CorelDraw 之类的印刷设计桌面软件,那么想象一下这个想法是“段落样式”的 HTML/CSS 翻译。
在设计一本书(跨越数百页)时,您可能想要更改整本书(动态地)的标题排版。 您将定义在一个中心位置如何使某一特定排版表现,以便将其应用于整个项目(在我们的示例中为一本书)。 您需要对模式进行控制。
大多数程序使用这种命名风格,但它们的用户界面略有不同。



当您拉起窗格时,通常会存在一个“基本”段落样式,所有默认文本都属于它。 从那里,您可以创建任意数量的样式。 段落样式适用于“块”级元素,字符样式适用于“内联”级元素,例如粗体或唯一的跨度。


用户界面细节无关紧要 - 但是您可以看到,有很多控件可以定义文本在视觉上的表现方式。 在幕后,它只是键:值对,就像 CSS 属性:值对一样。
h1 {
font-family: "Helvetica Neue", sans-serif;
font-size: 20px;
font-weight: bold;
color: fuchsia;
}
定义后,样式可以应用于任何文本。 在这种情况下,小+
(在下面的段落样式名称旁边)表示样式定义已更改。

如果您想将这些更改应用于具有该段落样式的所有内容,那么您可以“重新定义”样式,它将应用于整个项目。

当我这样说时,它可能会让你想到:这就是 CSS 类。
但对于网站来说,情况要复杂一些。 您永远不知道您的网站将以什么大小显示(它可能很小,比如在移动设备上,或者很大,比如在台式机显示器上,甚至在单色平板电脑上,谁知道呢),所以我们需要根据这些类的上下文来调整它们,并让它们根据上下文更改。

排版控制的最低限度
在您成为开发人员的早期,您可能已经了解了语义 HTML,如下所示
<h1>Here's some HTML stuff. I'm a heading level 1</h1>
<p>And some more. I'm a paragraph.</p>
<h2>This is a heading level 2</h2>
<p>And some more pragraph stuff.</p>
并且它与针对这些元素并应用样式的 CSS 配合使用,如下所示
h1 {
font-size: 50px; /* key: value pairs */
color: #ff0066;
}
h2 {
font-size: 32px;
color: rgba(0,0,0,.8);
}
p {
font-size: 16px;
color: deepskyblue;
line-height: 1.5;
}
这有效!
您可以编写规则来定位标题并以降序对其进行样式化,以便它们最大>大>中,依此类推。
由于用户代理样式(即浏览器本身应用于 HTML 的默认样式),标题也有一些我们认为是正常的样式。 它们旨在有用。 它们会向标题添加诸如font-weight
和margin
之类的东西,以及合并边距。 这样 - 根本不需要任何 CSS - 我们可以放心,至少会有一些基本样式到位,以建立层次结构。 这是对初学者友好的,对回退友好的……而且是好事!
随着您构建更复杂的网站,事情变得更加复杂
您添加了更多页面。 更多模块。 更多组件。 事情开始变得更复杂。 您可能一开始会为每个小东西添加独特的类和样式,但这会追赶上您。
首先,您开始为特殊情况添加类
<h1 class="page-title">
Be <span class='super-ultra-magic-rainbow'>excellent</span> to each other
</h1>
<p class="special-mantra">Party on, <em>dudes</em>.</p>
<p>And yeah. I'm just a regular paragraph.</p>
然后,您开始在所有地方添加类(大多数 CSS 方法甚至鼓励这样做)
<header class="site-header">
<h1 class="page-title">
Be <span class='ultra-magic-rainbow'>excellent</span> to each other
</h1>
</header>
<main class="page-content">
<section class="welcome">
<h2 class="special-mantra">Party on <em>dudes</em></h2>
<p class="regular-paragraph">And yeah. I'm just regular</p>
</section>
</main>
新手会尝试绕过默认的字体大小和合并边距,如果他们没有信心“重置” 它们。
这就是人们开始尝试margin-top: -20px
的地方……然后事情变得古怪。 当您继续编写更多规则来控制事物时,您会感觉自己是在“修复”事情,而不是声明您实际希望它们的工作方式。 当您不知道浏览器的用户代理样式时,您会很快感觉自己是在与 CSS 级联“作斗争”。
一个真实的例子
想象一下,您在您的真实工作岗位上,您的老板(或视觉设计师)为您提供了这份“像素级完美”的 Adobe Photoshop 文档。 有很多颜色、布局和排版。

您打开 Photoshop 并开始四处查看,但是有这么多页面和这么多不同的类型样式,您需要盘点并收集哪些样式可以组合使用或组合使用。

完成视觉布局并移交它感觉很好。 然而,我无法告诉您我花了多少整天试图弄清楚 Photoshop 文档中到底发生了什么。 例如,有时根本不考虑小屏幕; 而且当它们被考虑进去时,您发现的模式并不总是由每个组共享,因为它们会针对不同的屏幕类型而更改。 一些字体从 16px 开始,一直到 18px,而另一些则一直到 19px 并变成斜体。 您如何在静态模型中发现上下文更改?
有时这是有目的的; 其他时候,视觉设计师只是根据感觉行事,并且很乐意将事物四舍五入以创建可重用的模式。 您需要与他们谈谈。 但是本文主张我们在流程的更早阶段谈论它。
您可能会获得一个样式指南以供参考。 但即使那样可能也不足以识别上下文。

让我们放大其中一个指南

您甚至可能会获得一个正式但通用的样式指南,其中根本没有像素大小或关于不同屏幕尺寸的说明!


别误会我的意思:这类事情绝对是一个很好的想法,甚至可能对其他人有用,例如在一些客户会议上。 但是,就前端开发而言,它更令人困惑而不是有帮助。 我收到了非常详细的样式指南,看起来很漂亮,并为诸如字体大小之类的方面提供了很多优秀的指南,但与附带的 Photoshop 文档完全不匹配。 在另一个极端,有一些样式指南对您可以想象的每种标题类型和组合都包含大量详细信息 - 以及更多。
即使有最好的意图,也很难解析这些内容!
在您开发生涯的早期,您可能会认为您的工作是“弄清楚”并开始工作,记下所有像素并尽力理解它。 去抓他们!
但是,当您开始对所有细节进行编码时,由于重复的数量,事情可能会变得有点难以处理。 只需看看这里重复的属性
.blog article p {
font-family: 'Georgia', serif;
font-size: 17px;
line-height: 1.4;
letter-spacing: 0.02em;
margin-bottom: 10px;
}
.welcome .main-message {
font-family: 'Georgia', serif;
font-size: 17px;
line-height: 1.4;
letter-spacing: 0.02em;
margin-bottom: 20px;
}
@media (min-width; 700px) {
.welcome .main-message {
font-size: 18px;
}
}
.welcome .other-thing {
font-family: 'Georgia', serif;
font-size: 17px;
line-height: 1.4;
letter-spacing: 0.02em;
margin-bottom: 20px;
}
.site-footer .link list a {
font-family: 'Georgia', serif;
font-size: 17px;
line-height: 1.4;
letter-spacing: 0.02em;
margin-bottom: 20px;
}
您可能会将通用声明应用于主体。 在较小的项目中,这甚至可能是一种不错的做法。 有一些方法可以利用级联来发挥您的优势,还有一些方法似乎将太多事物绑定在一起。 就像在面向对象编程语言中一样,您不希望所有东西都继承所有东西。
body {
font-family: 'Georgia', serif;
font-size: 17px;
line-height: 1.4;
letter-spacing: 0.02em;
}
事情会好起来的。 大多数网络都是这样构建的。 我们只是在寻找更好的东西。
处理设计修订
总有一天,会有一个会议。 在会议上,您会发现客户和视觉设计师决定更改很多排版。 现在您需要返回并在 CSS 文件中的 293 个位置更改它。 如果您按小时计酬,这可能很棒!
当您开始调整规则时,事情会开始冲突。 对两件事有效的规则现在只对其中一件有效。 或者您会注意到可以比以前在更多地方使用的模式。 您甚至可能很想完全删除 CSS 并重新开始! 哎呀!
我不会在这里写出来,但您会尝试很多不同的方法,而且人们通常会得出这样的结论,您可以创建一个类 - 并将其添加到元素中,而不是为每个元素复制规则/声明。 您会更进一步,尝试从视觉设计师的文档中提取模式。 (您甚至可以将一些 19px 舍入到 18px,而无需告诉他们……)
.standard-text { /* or something */
font-family: serif;
font-size: 16px; /* px: up for debate */
line-height: 1.4; /* no unit: so it's relative to the font-size */
letter-spacing: 0.02em; /* em: so it's relative to the font-size */
}
.heading-1 {
font-family: sans-Serif;
font-size: 30px;
line-height: 1.5;
letter-spacing: 0.03em;
}
.medium-heading {
font-family: sans-Serif;
font-size: 24px;
line-height: 1.3;
letter-spacing: 0.04em;
}
然后,您将类应用于任何需要它的东西。
<header class="site-header">
<h1 class="page-title heading-1">
Be <mark>excellent</mark> to each other
</h1>
</header>
<main class="page-content">
<section class="welcome">
<h2 class="medium-heading">Party on <em>dudes</em></h2>
<p class="standard-text">And yeah. I'm just regular</p>
</section>
</main>
这种做法对于拥有不同技能水平的人员更改 HTML 的团队来说非常有用。 您可以使用这些 CSS 类进行即插即用,以获得您想要的样式,即使您是新来的实习生。
将“布局”元素(结构/父级)和“模块”或“组件”的概念分开非常有帮助。 这样,我们就把文本片段视为更低级的组件。
关键是要将排版与布局分开。你不希望所有.medium-heading
元素都具有相同的边距或颜色。它将取决于它们的位置。这样,你就可以根据上下文进行样式设置。你并不一定在“使用”级联,但你也没有与之抗争,因为你将这些技术分开。
.site-header {
padding: 20px 0;
}
.welcome .medium-heading { /* the context — not the type-pattern */
margin-bottom: 10px;
}
这样可以保持事物的合理性和整洁。这种技术在整个网络中广泛使用。
使用 CMS
很好,但是如果在无法更改 HTML 的情况下呢?
你可能只是快速编写一个 CodePen 或名片网站。在这种情况下,这些问题似乎过分了。另一方面,你可能正在使用一个 CMS,而你无法确定会发生什么。你可能需要为可能出现的任何和所有情况做好准备。在这种情况下,你无法简单地为单个元素添加类。你可能会从某个模板语言获得 HTML 转储。
<?php echo getContent()?>
<?=getContent()?>
${data.content}
{{model.cmsContent}}
因此,如果你无法使用 HTML,那么你能做什么?
<article class="post cms-blog-dump">
<h1>Talking type-patterns on CSS-tricks</h1>
<p>Intoduction paragraph - and we'd like to style this with a slightly different size font then the next (normal) paragraphs</p>
<h2>Some headings</h2>
<h2>And maybe someone accidentally puts 2 headings in a row</h2>
<ol>
<li>and some <strong>list</strong></li>
<li>and here</li>
</ol>
<p>Or if a blog post is too boring - then think of a list of bands on an event site. You never know how many there will be or which ones are headlining, so you have to write rules that will handle whatever happens.
</article>
你无法控制此标记,因此无法添加类,这意味着你创建的那些很酷的即插即用类将无法使用!你可能只是将它们复制粘贴到某个更大的.article { }
类中,该类定义了厨房水槽的规则。这可能有效。
还有哪些工具可以玩?
Mixin
如果你可以使用 Sass 创建一个可重用的“类型模式”概念,那么你可以以类似于类的方式应用它们。
@mixin my-useful-rule { /* define the mixin */
background-color: blue;
color: lime;
}
.thing {
@include my-useful-rule(); /* employ the mixin */
}
/* This compiles to: */
.thing {
background-color: blue;
color: lime;
}
/* (just so that we're on the same page) */
Less、Sass、Stylus和其他 CSS 预处理器都有自己的语法。我将在这些示例中使用 Sass/SCSS,因为它在撰写本文时是最常见的。
@mixin standard-type() { /* define the mixin */
font-family: Serif;
font-size: 16px;
line-height: 1.4;
letter-spacing: 0.02em;
}
.context .thing {
@include standard-type(); /* employ it in context */
}
你可以使用heading-1()
和heading-2()
,许多知名样式指南都这样做。但如果你想在不是“标题”的东西上使用这些类型样式怎么办?我个人最终没有将标题与“大小”联系起来,并且在各种不同的地方使用这些模式。有时我的标题很“强势”和“粗壮”。它们可以是带有与段落文本相同 x 高度的穿透红色和全部大写。
相反,我根据我希望内容的“声音”呈现的方式来定义视觉样式。这也帮助团队跨学科讨论“语气”和其他内容策略方面。
例如,在 Jason Santa Maria 的书On Web Typography中,他谈论了“瞬间类型”和“持续类型”。有类型可以吸引你的注意并打断页面,然后是那些让人静下心来的段落。我一直在享受根据声音组织样式的想法,而不是.standard-text
或.normal-font
。这是用户应该花时间阅读的所有内容。这是我可能在大多数段落和列表中使用的内容,并且我不会将其设置为正文。
@mixin calm-voice() { /* define the mixin */
font-family: Serif;
font-size: 16px;
line-height: 1.4;
letter-spacing: 0.02em;
}
@mixin loud-voice() {
font-family: Sans-Serif;
font-size: 30px;
line-height: 1.5;
letter-spacing: 0.03em;
}
@mixin attention-voice() {
font-family: Sans-Serif;
font-size: 24px;
line-height: 1.3;
letter-spacing: 0.04em;
}
这种“声音”的想法有助于我保持事物的意义,因为它要求你根据上下文对事物进行命名。例如,名称heading-1b
无法帮助我将内容与任何类型的叙事或团队中的其他人联系起来。
现在对神秘文章进行样式设置。我将在此处使用 SCSS 语法
article {
padding: 20px 0;
h1 {
@include loud-voice();
margin-bottom: 20px;
}
h2 {
@include attention-voice();
margin-bottom: 20px;
}
p {
@include calm-voice();
margin-bottom: 10px;
}
}
漂亮,对吧?
但这并不容易,对吧?不。这有点复杂,因为你不知道什么可能在彼此之上或之下——或者什么可能被省略,因为文章并不总是结构相同或组织相同。那些 CMS 作者可以在那里放置任何他们想要的内容!连续三个<h3>
元素?你必须为许多可能的结果做好准备。
/* Styles */
article {
padding: 20px 0;
h1 {
@include loud-voice();
}
h2 {
@include attention-voice();
}
p {
@include calm-voice();
&:first-of-type {
background: lightgreen;
padding: 1em;
}
}
ol {
@include styled-ordered-list();
}
* + * {
margin-top: 1em
}
}
要查看常规 CSS,你始终可以在 CodePen 中“查看已编译内容”。
有些人对切除的猫头鹰方法(* + *
)非常满意,但我通常最终会为“在段落之后出现的任何<h2>
”编写明确的规则,并变得非常详细。毕竟,这是书面内容,每个人都希望阅读……而且我只需要在一个地方一次对其进行微调。
/* Slightly more filled out pattern */
@mixin calm-voice() {
font-family: serif;
font-size: 16px;
line-height: 1.4;
letter-spacing: 0.02em;
max-width: 80ch;
strong {
font-weight: 700;
}
em {
font-style: italic;
}
mark {
background-color: wheat;
}
sup {
/* maybe? */
}
a {
text-decoration: underline;
color: $highlight;
}
@media (min-width: 600px) {
font-size: 17px;
}
}
Stylus
思考“理想”的工作流程很有意思。浏览器可以实施什么来让它变得有趣并与它们的未来系统配合良好?
以下是一个最简化的预处理器语法的示例
calm-voice()
font-family: serif
font-size: 16px
line-height: 1.4
letter-spacing: 0.02em
article
h1
loud-voice()
h2
attention-voice()
p
calm-voice()
说实话……我喜欢Stylus。我喜欢编写它,也喜欢用它来举例。它让大家保持警觉。它在 CodePen 中输入起来非常快!如果你已经有了自己的样式框架像这样,那么构建 UI 的速度会快得令人难以置信。但!工具已经落后了,在这一点上,我无法推荐任何人使用它。
我之所以在这里添加它,是因为梦想很重要。我们拥有我们拥有的东西,但如果你能发明一种新的编写方式呢?这也是对话中至关重要的一部分。如果你无法描述你想要什么,你就不会得到它。
我们在这里:类型模式
你能看到这一切将走向何方吗?
你可以使用这些“模式”或“mixin”或你想称之为的“任何东西”并即插即用。这很有趣。你也可以将它与实用程序类理念结合在一起(如果你必须这样做)。
.calm-voice {
@include calm-voice();
}
<p class="calm-voice">Welcome to this code snippet!</p>
样式指南
如果你可以开始共享一种通用语言并打破“创意人员”和“编码人员”之间的障碍,那么每个人都可以从一开始就牢记这些类型模式。
有时你可以简单地将样式指南发布为“品牌”子域或直接发布在网站上,例如在/style-guide
处。网上有许多此类指南。重点是,有些样式指南是独立的,而另一些则内置在网站本身中。无论它们在哪里,它们都被认为是“动态的”,并且它们允许你在一个地方开发影响全局的事物,并将指南本身用作一种工件。
通过使用类型模式作为核心和共享概念构建动态样式指南,每个人都将获得更多乐趣并节省时间来尝试弄清楚彼此的意思。这也不仅仅适用于大型公司。
查看其他组织的样式指南时要小心。 样式指南根据使用它们的人和使用方式服务于不同的目的,因此简单地深入研究他人的工作实际上可能会导致更多混乱。
已知未知数
有时你不知道内容是什么。这意味着 CMS 内容,但也包括逻辑。如果你有一个乐队和活动的列表,并且正在构建一个包含条件组件的模块怎么办?可能有一个乐队……或者五个……或者两个联合领衔主演。活动可能被取消了!
当我试图为 Ticketfly 确定一些模板理念时,我将布局和类型模式的关注点分开。
可变大小的字体模式
有些模式在不同的断点处会改变大小。
@mixin attention-voice() {
font-family: Serif;
font-size: 20px;
line-height: 1.4;
letter-spacing: 0.02em;
@media (min-width: 700px) {
font-size: 24px;
}
@media (min-width: 1100px) {
font-size: 30px;
}
}
我过去会做一些类似的事情,这会产生一些令人讨厌的副作用。例如,如果你根据断点即插即用,并且存在冲突或遗漏的大小怎么办?
@mixin attention-voice() {
font-family: Serif;
font-size: clamp(18px, 10vmin, 100px);
line-height: 1.4;
letter-spacing: 0.02em;
}
现在,理论上,你甚至可以在模式之间无缝切换。
.context {
@include calm-voice();
@media (min-width: 840px) {
@include some-other-voice();
}
}
但现在你必须确保它们都具有相同的属性,并且它们不会与其他模式冲突或渗透到其他模式中!还要考虑新的可变字体选项。有时你希望你的标题在较小的屏幕上不那么重,或者更高一点才能与空间配合。
你不会在所有地方重复样式规则吗?
哎呀!你抓到我了。我更关心让创作和维护过程变得愉快,而不是关心 CSS 字节大小。不过我也有点矛盾。我明白。但我认为解决方案应该出现在流程中的其他地方。我们不手工编写机器代码是有原因的。
有时你必须仔细检查一种编程模式,并真正地探究它,尝试在所有可能的地方使用它,以证明它的实用性。请容忍我一下,看看你如何使用这种类型模式和其他 mixin 来设计一个常见的“卡片”界面。
从某种意义上说,类型模式就像 Bootstrap 或 Tailwind 的实用类风格。但这些是人类可读的。这些模式是在 CSS 中添加的,而不是在 HTML 中。概念是一样的。我喜欢这样想:任何人都可以查看实时样式指南,然后直接进入组件并对其进行样式设置。你怎么看?
它确实会生成更多的 CSS。那些 KB 在不断累积。但我认为我们应该朝着理想的方向努力,而不是仅仅追求“可能性”。我们可能可以构建一些在构建时解决这个问题的东西。我需要学习更多关于CSSOM的知识,并且管道中有很多新事物可能可以让这成为可能,而无需预处理器。
这不仅仅是 CSS。这是关于人的。
在你的项目中拥有一套类型模式,可以让视觉设计师专注于他们的魔法。我们越来越多地是在浏览器中快速构建。视觉设计师专注于感觉、排版和颜色,使用简单的框架,例如Style Tiles。然后开发人员可以组织数据、资源结构和布局,每个人都可以同时工作。我们可以拥有更清晰的沟通和对整个流程的共同理解。我们都是 UX 设计师。
当实时样式指南由团队共同创建时,就少了很多需要“像素级”调整的需求。视觉设计师实际上可以花更多时间思考和尝试原型中的想法,而花更少的时间来模拟不必要的生产艺术。这使你能够将品牌作为一个整体来处理,并拥有一个唯一的真相来源。即使对于非常小的网站,它也有帮助,例如这个。

InDesign 和 Illustrator 一直都有“段落样式”和“字符样式”,原因就在于此,但它们没有考虑到可变屏幕尺寸。

添加一些填充类型尺寸/比例、一些颜色和一些线宽。它不需要真正达到“像素完美”,而更像是一组协同工作的模式。将颜色作为变量,以及一些$thick
、$thin
或 $pad*2
类型的约定可以帮助简化设计模式。
你可以在图形程序中找到你的灵感,然后直接跳转到实时样式指南。来自不同背景的人可以开始在 CodePen 中玩弄这些样式,并在不同的设备上进行调整。
最终,你将共同作为一个团队,在真实的设备上决定细节。
非常感谢 Chris 和 Geoff 细致的编辑。
我正在考虑制作一个关于这个想法的视频。请告诉我你们对这些东西的看法——以及视频是否有帮助。:)
读得非常愉快!我完全感同身受,看到现实世界的解决方案很好。另外,感谢你提供指向 CodePen 的链接,供那些想要查看普通 CSS 的人使用。
感谢你提出的轻声、大声的想法。我以后一定会在我的 CSS 中实现它。
太棒了!付出的努力非常值得。任何可以照亮类型模式的黑暗世界的灯光都是值得的。
我写这篇文章已经一年多了。在那段时间里,我开始了一所学校。我不想让学生承担 CSS 预处理器的额外负担,除非我绝对必须这样做。所以,我开始编写课程和构建课程的所有项目,使用
--custom-properties
而不是 SCSS/Stylus 变量。我不能使用 mixin,所以我使用.calm-voice
类型的实用类,在需要的地方使用。然后,对于像文章这样的更大的内容块,我最终只是使用这样的选择器列表来编写规则嗯,好吧,我对结果感到惊讶。我没有像预期的那样想念嵌套。我的意思是,我已经使用预处理器快把我整个职业生涯了。而且现在没有预处理器也一切都很棒。没有 mixin 我也能接受。而且它也创建了更少的代码。
我不是说构建工具不是超级棒且有用。它们确实有用。我经常将它们用于很多事情。我只是回来分享这个故事的一部分。你不需要预处理器就能以不同的方式思考类型。
我仍然有 40 多个 CSS @import——这行不通。所以,在http2(它似乎更喜欢更多文件而不是更大的文件?也许)之前,我想我仍然必须使用预处理器来进行连接。或者我可以使用 PHP 或其他自定义的东西将它们粘合在一起。
关于这篇文章,我还想指出,我在示例中使用了
px
。我不想让人们关注这些单位,但在所有不是更大的显示类型的案例中(我认为那里仍然存在有效的争论),我会使用并测试rem
。我也可能使用em
用于 @media 规则。所以,如果你将来看到这篇文章:这篇文章只关注语义和样式的分离/缩小排版/让整个团队就一个共享系统达成一致。:)