2673 字
13 分钟
计算机科学中最困难的事:居中

原版:英文 翻译:日语 俄语

原文发表于2024年04月16日。

总而言之:我们作为文明的一份子,却忘记了如何居中。

我的意思是,我们知道 居中,这不能更简单了:

display: flex;
justify-content: center; /* Horizontal centering */
align-items: center; /* Vertical centering */

(不要问我为什么需要使用四个单词来解决明明用一个单词 horizontal/vertical 就能够解决的问题,

当然你也可以使用 grid:

display: grid;
justify-items: center; /* Horizontal centering */
align-items: center; /* Vertical centering */

(同样不要问我为什么 justify-content 变成了 justify-items

如果你想深入了解这些,很容易发现:

formula@2x.png

您猜怎么着,甚至 ChatGPT 都知道如何居中:

chatgpt@2x.png

好吧,这也许存在问题,但至少它知道。

我想说的是:所有人都知道如何居中。虽然比较唠叨:如果你不会,尽管去查。

然而,在实际应用中并没有使用以上所述的方法,我们发现:

telegram_date@2x.webp

或者这个:

google_maps_cross@2x.webp

甚至这个:

feedly_beta@2x.webp

因此,在掌握的知识和实际应用中总是差了点什么。

something.png

理论上来说理论应与实际相同,但不幸的是,我们没有生活在理论中。

所以发生了什么?让我们来找找原因。

字体#

字体是最大的“罪魁祸首”之一。在实际中随处可见对齐不良的文本,让我来展示一下:

苹果没做到:

apple_buttons_big_sur@2x.png

微软没做到:

windows@2x.webp

GitHub 没做到:

github@2x.webp

Valve 没做到:

steam@2x.webp

Slack 没做到:

slack_button@2x.webp

Telegram 没做到:

telegram@2x.webp

Google 地图没做到:

google_maps@2x.webp

说真的我能够提供无尽的像这样没有完全对齐的按钮:

buttons@2x.png

我想你已经明白了:大大小小的公司数不胜数,不管是专注于原生应用的公司还是互联网公司,没有一家能幸免于文本居中的问题。

行高#

如果解决了字体的问题,那么完美居中的下一个障碍是行高。

行高是……非常复杂。帮助你了解行高的经典文章是 Vincent De Oliveira 的 Deep dive CSS: font metrics, line-height and vertical-align

让我们来看看实际上怎么样:

Slack:

slack@2x.webp

Notion:

notion@2x.webp

Airbnb:

airbnb@2x.webp

YouTube:

youtube@2x.webp

将不同容器中的两个东西对齐几乎是不可能的:

name@2x.webp

尽管很多人都尝试过:

american_airlines@2x.webp

但成功的人并不多:

addons@2x.webp

CSS 可能会妨碍对齐(不同的控件具有不同的默认值,必须在开始对齐之前重置这些默认值):

controls@2x.webp

没有简单的解决方案,只能因地制宜,撸起袖子加油干。

图标#

图标就像与文字放在一起的小矩形。因此,字体和行高引起的所有问题在这里都会再次出现。将图标与文本对齐是一项出了名的难事。

Atom:

atom@2x.webp

以前大家所熟知的 Twitter:

twitter@2x.webp

iOS:

ios@2x.webp

Mozilla:

mozilla@2x.webp

YouTube:

youtube_likes@2x.webp

有些图标高于文字:

meet@2x.webp

有些图标低于文字:

ical@2x.webp

有些时候两者都没对齐:

name_button@2x.webp

有些图标是最原始的样子:

git_butler@2x.webp

有些却拥有样式:

by_bee@2x.webp

感谢 @bee 提供这张图片
有时,人们会创造性的达到完美的对齐效果:

github_close@2x.webp

但总的来说,这是非常令人绝望的:

apple_id@2x.webp

问题是,CSS 也帮不了我们。vertical-align 有 13 种可能的值,但没有一种能让图标以有意义的方式对齐:

text_align@2x.png

text-align: middle 看起来快成了,但它是按 x 高度对齐,而不是按大写字高对齐,这看起来仍然不平衡:

middle@2x.webp

这就是人们爱死网页前端的原因:无时不刻的接受挑战。

图标字体#

对齐矩形相对容易。对齐文本则很难。已知图标是矩形。那么,如果我们将图标放入字体文件中呢?

现在我们不能对齐任何东西了:

icon_fonts@2x.webp

我们也无法设置图标大小!在上面的示例中,所有图标的字体大小和行高都是一样的。正如你所看到的,所有图标的大小都不一样,填充大小也不一样,而且都没有正确的对齐。

尽管有不少缺点,公司们还是在把图标字体推广到所有地方,这导致了:

calculators@2x.png macOS 10.14 → macOS 10.15

请注意,操作符不再垂直对齐,也变得模糊不清。这都是因为切换到了图标字体。

苹果公司如此执着于图标字体,甚至毁掉了 QuickTime 录制按钮:

quicktime@2x.webp

仔细看看:

quicktime_button@2x.webp

是的,直到现在它还是这个样子。计算器也是如此。

但他们远非唯一。

一:

icon_1@2x.webp

二:

icon_3@2x.webp

三:

icon_4@2x.webp

四:

icon_5@2x.webp

五:

icon_6@2x.webp

六:

icon_7@2x.webp

七:

icon_8@2x.webp

与文本相同,没有完全对齐的图标也是无限的。

技术问题#

不仅程序员会遇到技术问题,设计师也会:

things@2x.webp

当前版本 / 我的修复后的版本

图标的问题在于,有时你必须考虑到图标的形状,这样才能让东西看起来更美观:

apple_logo@2x.webp

不良的居中 / 良好的居中

三角形非常的棘手:

triangle@2x.webp

有时过于偏左:

triangle_left@2x.webp

有时过于偏右:

triangle_right@2x.webp

甚至可能太高(行高问题又出现了):

triangle_up@2x.webp

横向居中#

你也许会认为只有竖向居中很困难。错了!横向一样困难:

apple_sign_in_business@2x.webp

我觉得这只是人们太粗心了:

twitter_horizontal@2x.webp

唉,来就来吧。

android@2x.webp

这会是一个深思熟虑的决定吗?

teams@2x.png

我不知道。图标会受到影响:

drive@2x.webp

当然文本也会:

steam_horizontal@2x.webp

对设计师而言可以采取的方案#

所以,什么 问题?

一切从字体开始。现在,文本块的边界是这样的:

text_bounding_box@2x.png

问题是,它也可以是这样的:

text_bounding_box_2@2x.png

或者这样的:

text_bounding_box_3@2x.png

现在,如果你尝试将文本框居中,那么会发生什么情况呢?

text_bounding_box_4.png

文字会出现偏移!即使文本框完全居中。

但是,尽管字体度量 不平衡,但是这不意味着它们看起来不平衡。到底发生了什么?

实际上, 流行字体的度量都是不平衡的。许多字体 明显:

metrics@2x.png

百分比为大写字高的百分比

10% 并不是一个小数字。在字体大小为 13 的情况下,这可是整整一个像素!如果在两倍 2 倍缩放的情况下,将会是两个像素!这很容易察觉。

基本上,Segoe UI 就是 Windows 上的 Github 看起来像这样的原因:

github@2x.webp

解决方案很简单:使用紧凑的文本框来居中就能解决。

text_bounding_box_5.png

如果你正在使用 Figma,它已经能够做到了(尽管不是默认的):

figma_vertical_trim@2x.png

对字体设计师而言可以采取的方案#

如果你是字体设计师,请将度量值设计为 ascender − cap-height = descender 以方便大家使用:

font_metrics_numbers@2x.png

图示解决方法:

font_metrics@2x.png

重点!你不需要 ascenders/descenders 撑满边界。如图所示,上部远未被充分利用。只需使数值匹配即可。

无论是网页还是本地字体,为了避免麻烦,请选择已经遵循这一规则的字体。SF Pro Text、Inter 和 Martian Mono 似乎已经遵循了这一规则,因此无需额外的努力就能完美居中。

阅读 Font size is useless; let’s fix it 以了解更多。

对网页开发者而言可以采取的方案#

从开发人员的角度来看,这就比较棘手了。

首先要了解的是,你需要知道要使用哪种字体。遗憾的是,如果你打算替换字体,这就行不通了。

我们将使用 IBM Plex Sans 字体,这种字体在本页面上使用过。IBM Plex Sans 具有以下度量:

ibm_plex_sans@2x.png

当你设置 font-size 时,设置的是 UPM(也等于 1em)。但是,文本块实际占用的空间是 ascenderdescender 之间的空间。

ibm_plex_sans_notes@2x.png

通过简单的计算,我们可以加上额外的 padding-bottom: 0.052em

numi@2x.webp

它像这样工作:

ibm_plex_sans_padding@2x.png

在 CSS 中:

Andy

你可以从 https://opentype.js.org/font-inspector.html 获得你所使用的字体的度量(ascender, descender, sCapHeight)。

既然我们已经解决了这个问题,那么对齐图标也就不难了。你可以设置 vertical-align: baseline,然后将它们向下移动 (iconHeight - capHeight) /2

ibm_plex_sans_icon@2x.png

不幸的是,这需要你同时知道字体度量和图标大小。不过,至少它还能用:

Andy

再次选择上面的文字,看看浏览器的边界框与正确位置有多大的差异。

对图标字体可以采取的方案#

使

使用正常的图片格式。有尺寸的那种,是那种有宽度和高度的。

在这里,我为你画了一张图,帮助你做出决定:

diagram@2x.png

看看苹果是多么努力地把复选标记放在矩形内,然后把矩形放在文本标签旁边:

apple_sign_in@2x.webp

然后失败了!

没有比对齐两个矩形更容易的事了。同时,最难的莫过于对齐周围有任意空白空间的文本。

它们不可能做到的。

可用的视觉补偿#

我们,开发人员,只能用数学方法来对齐完美的矩形。因此,对于任何需要手动补偿的图标,请将其包入一个足够大的矩形中,并在视觉上平衡图标内部:

icons_baked@2x.png

所有人都应该做的#

集中注意力并仔细的处理问题。不佳的居中对齐会毁了原本不错的 UI:

win@2x.webp

但正确对齐的文本可以让 UI 熠熠生辉:

win_fix@2x.webp

尽管这很难;尽管工具会带来不便;尽管你必须寻找解决方案。我相信,只要我们戮力同心,就一定能找到办法,把一个长方形放在另一个长方形里,而不弄乱任何东西。

就我而言,我希望生活在一个充满美丽而均衡的 UI 世界里。我相信你们也是如此。

这一切都是值得的。

特别提名#

没有这个老伙计我们的文章是不完美的:

细心!千万不要让东西变成这样!

点击返回主页