首页 / 文章 / CSS中的行长度、间距比例、深色背景、阴影以及焦点环

CSS中的行长度、间距比例、深色背景、阴影以及焦点环

了解打造精美界面背后的 CSS 基础知识:基于 ch 的行长控制、4px 的间距比例、分层深色背景、多层阴影以及可聚焦的环形高亮效果。

1903 词

一个网页应用即便拥有时尚的渐变效果、透明质感卡片以及流畅的动画,使用几秒钟后仍会给人未完成的感觉。虽然没有任何功能故障,但其视觉呈现更像是周末临时制作的原型,而非像 Linear、Stripe 或 Vercel 那样成熟的产品。造成这种情况的原因往往并非色彩搭配或艺术天赋的缺乏,而是些关于行长、间距、对比度、层次感以及焦点状态的 CSS 设置问题,本文将介绍如何正确处理这些问题。

使用 ch 单位限制行长

在1440像素的显示器上占据整个宽度的文本,是前端设计粗糙的最明显迹象之一。过长的行难以阅读:一旦一行超过大约80个字符,视线就必须一直回到左边缘,而当视线向下移动时,往往会在错误的行上停留。在长页面中,不断重新定位视线会让人感到疲惫。

通常的情况是这样的:一个全宽容器,没有任何元素限制段落内容:

{/* BAD: Unbounded text stretches across the whole viewport */}
<div className="w-full p-8">
  <h1 className="text-3xl font-bold">API Documentation</h1>
  <p className="text-slate-300 mt-4 text-base">
    Our platform enables developers to authenticate and stream webhook events in real-time... (stretches 1200px wide)
  </p>
</div>

解决方案:按字符大小调整文本块

CSS 中有专门解决此问题的单位。ch 的宽度与字体中的“0”字符相同,因此使用 ch 作为尺寸单位时,无论字体大小如何,都能保证每行字符数一致。舒适的阅读体验通常要求每行包含45到75个字符。一个可复用的正文类可以将基于 ch 的字符上限与较大的行高以及稍窄的字母间距结合在一起:

/* Clean readable prose container */
.prose-container {
  max-width: 68ch; /* Optimal line length regardless of font size */
  line-height: 1.65;
  letter-spacing: -0.01em;
}

在 Tailwind 中,max-w-prose 工具类也提供了类似的字符上限(65ch),而 mx-auto 则用于将内容居中:

{/* Enterprise Grade: Beautiful, focused reading experience */}
<div className="max-w-prose mx-auto px-6 py-12">
  <h1 className="text-3xl font-bold tracking-tight text-white">
    API Documentation
  </h1>
  <p className="mt-4 text-slate-300 text-base leading-relaxed">
    Our platform enables developers to authenticate and stream webhook events in real-time...
  </p>
</div>

将文档、博客文章以及说明性设置文本的宽度控制在65到70ch左右,能让这些页面立刻显得协调且富有吸引力。此规则应应用于文本块,而非整个布局。

将所有间距设置为4px/8px的倍数

扫描那些设计粗糙的代码库中的工具类,你经常会发现类似这样的数值:

  • 卡片内边距为 p-[18px]
  • 模态框外边距为 mt-5(20px)
  • 按钮内边距为 px-3.5 py-[7px]
  • 区块间距为 gap-7(28px)

这些数值被选用只是因为它们在某个屏幕上某个时刻看起来还行,但合在一起却破坏了空间节奏。人们即便没有刻意注意,也能感知到一致的间距;而当各间距数值之间毫无关联时,布局就会显得杂乱无章且缺乏连贯性。

应采用的间距比例标准

成熟的设计系统会将间距限制为4或8像素的倍数,并为每个比例赋予名称和用途。一个实用的间距比例标准如下:

  • space-1(4px):微小间距,例如图标与其标签之间的间隙
  • space-2(8px):用于徽章和小型标签的紧凑内边距
  • space-3(12px):表单字段的内部填充间距
  • space-4(16px):标准卡片和按钮的填充间距
  • space-6(24px):卡片之间的间隙
  • space-8(32px):各板块之间的分隔间距
  • space-12(48px):主控制面板区块之间的分隔间距

任何超出该范围的值,比如margin-top: 19px,都应视为缺陷而非风格选择。Tailwind的默认间距单位已经是4px的倍数,因此实际操作中应避免使用随意设定的数值。

深色模式中避免纯黑色背景

在设计深色 SaaS 界面时,常见的初步尝试是将页面设置为纯黑色背景搭配纯白色文字:

/* The Harsh Dark Mode Trap */
body {
  background-color: #000000;
  color: #ffffff;
}

白色在黑色背景上能产生 21:1 的最高对比度,这轻松满足无障碍设计的最低标准。但如此极端的亮色文字在背景上可能会出现光晕现象,许多读者,尤其是有散光问题的人,会觉得这很刺眼,尤其是在 OLED 和高对比度屏幕上。

更大的问题是深度感。距离观看者或光源较近的界面自然会显得更亮一些。如果底层颜色已经是 #000000,那就无法再区分卡片、下拉菜单和模态框了,因为黑色已无法再变得更暗。

构建分层视觉层次

应使用深色且略带色调的暗色系,随着元素位置升高逐渐增加亮度。该标记集的前半部分定义了四个表面层级,从页面画布到模态框和工具提示等叠加元素:

:root {
  /* Slate / Charcoal Depth Stack */
  --bg-canvas: #090d16;   /* Deepest background */
  --bg-surface: #0f172a;  /* Cards, tables, sidebar */
  --bg-elevated: #1e293b; /* Dropdowns, popovers, active tabs */
  --bg-overlay: #334155;  /* Modals, tooltips */

同一 :root 块的其余部分则定义了两种半透明边框强度以及三种文本层级,从标题到时间戳及非活动图标依次排列。需要注意的是,在所示代码片段中,--border-active--text-primary 的声明被写在同一行;虽然这是有效的 CSS 语法,但建议重新格式化。另外 #f8fafc 只是接近白色的颜色,并非透明度为 95% 的纯白色:

  --border-subtle: rgba(255, 255, 255, 0.08);
  --border-active: rgba(255, 255, 255, 0.16);  --text-primary: #f8fafc;   /* 95% opacity white for headings */
  --text-secondary: #94a3b8; /* Muted slate for body text */
  --text-tertiary: #64748b;  /* Inactive icons, timestamps */
}

应用到标记结构后,画布位于最底层,卡片则使用带有细微边框的表面颜色,而标题和正文内容则分别使用主文本和次级文本样式:

{/* Clean, layered elevation */}
<div className="bg-[var(--bg-canvas)] min-h-screen p-8">
  <div className="bg-[var(--bg-surface)] border border-[var(--border-subtle)] rounded-xl p-6 shadow-sm">
    <h2 className="text-[var(--text-primary)] font-semibold">
      Workspace Overview
    </h2>
    <p className="text-[var(--text-secondary)] text-sm mt-1">
      Manage team roles and API keys.
    </p>
  </div>
</div>

现在的层次结构仅依据亮度来呈现,无需使用浓重的阴影。

用多个浅色阴影替代一个浓重阴影

业余级的界面设计往往只使用一个黑暗且模糊的阴影:

/* BAD: One thick, dark, muddy shadow */
.card-bad {
  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.5);
}

这样的效果看起来像过时的照片编辑技巧。真实物体不会投下均匀模糊的阴影。物理上的阴影由两个部分组成:

  • 由主光源在物体旁边产生的、对比度高的紧密阴影
  • 逐渐融入周围环境的宽阔柔和阴影,即环境光遮蔽效果

使用低透明度值叠加阴影

box-shadow支持用逗号分隔的多个值,因此你可以叠加两三个透明度较低的阴影。这里1px的阴影用于固定元素位置,中等模糊度增加环境深度感,而宽阔且非常柔和的阴影则用于扩散整体效果:

/* Polished Enterprise Shadow */
.card-elevation-high {
  box-shadow:
    0 1px 2px rgba(0, 0, 0, 0.06),   /* Crisp grounding line */
    0 8px 16px rgba(0, 0, 0, 0.08),  /* Middle ambient blur */
    0 24px 48px rgba(0, 0, 0, 0.12); /* Soft dispersed glow */
}

在深色背景上,阴影很难被看到,因此需要更高的不透明度,而细的光边则能有效起到分隔元素的作用。负的扩散值可防止深色阴影溢出到边缘之外:

/* In dark mode, pair subtle shadow with a crisp top border */
.card-dark-elevation {
  box-shadow:
    0 20px 25px -5px rgba(0, 0, 0, 0.5),
    0 8px 10px -6px rgba(0, 0, 0, 0.5);
  border: 1px solid rgba(255, 255, 255, 0.08);
}

该元素并非像剪纸一样置于黑色背景上,而是仿佛悬浮在画布之上。

切勿在没有替代方案的情况下移除焦点轮廓

在前端样式表中,有这样一行代码带来的危害比其他任何代码都要严重:

/* DO NOT DO THIS */
*:focus {
  outline: none;
}

团队会添加它,是因为浏览器默认的焦点环会与自定义样式的控件产生冲突。如果不提供替代方案就移除它,键盘用户将无法知道哪个元素处于焦点状态,这会使界面对他们而言实际上无法使用,同时也违背了无障碍访问的要求。

请改用 :focus-visible

现代浏览器支持 :focus-visible,该选择器仅在浏览器认为需要焦点指示器时才会生效,通常是在键盘导航期间,而非鼠标点击之后。这样就可以为鼠标用户省略焦点环,而为键盘用户保留它。第一步是移除按钮的默认轮廓:

/* Remove ugly mouse clicks, preserve crystal-clear keyboard rings */
button:focus {
  outline: none;
}

第二步是为键盘焦点定义一个清晰的自定义焦点环:

button:focus-visible {
  outline: 2px solid #6366f1; /* Crisp indigo ring */
  outline-offset: 2px;
  border-radius: 6px;
}

有两点改进值得了解。首先,第一条规则更安全的形式是 button:focus:not(:focus-visible),它仅在不需要可见指示器时才会移除轮廓线,这样不支持 :focus-visible 的浏览器仍会保留其默认的轮廓。其次,聚焦状态规则中的 border-radius 会改变按钮在聚焦时的形状;如果按钮本身已经具有圆角,则无需添加该属性,因为现代浏览器会根据元素的半径来绘制轮廓线。

在 Tailwind 中,同样的理念通过 focus-visible: 变体来实现,这些变体会添加轮廓线、偏移量以及与深色背景匹配的偏移颜色:

<button className="px-4 py-2 bg-indigo-600 hover:bg-indigo-500 rounded-lg text-white font-medium focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-400 focus-visible:ring-offset-2 focus-visible:ring-offset-slate-900 transition-all">
  Save Changes
</button>

Tailwind的outline-none属性在不同主要版本间有所变化(新版本增加了outline-hidden),请检查您使用的版本。无论哪种情况,鼠标操作的用户都能看到清晰的控件,而使用Tab键的用户始终能知道焦点所在位置。

合并代码前的优化检查清单

在发布前端更改之前,请逐一检查以下事项:

  1. 文本宽度:文本块的宽度是否控制在大约50到75ch之间?
  2. 间距:所有的内边距、外边距和间隙是否都遵循4px/8px的严格比例?
  3. 深色模式色调:界面元素的颜色是否由分层处理的炭灰或石板色调构成,而非纯#000000颜色?
  4. 阴影效果:阴影是否为柔和、分层且分布均匀的,而非单一的深色模糊效果?
  • 焦点状态:是否可以通过 Tab 键操作整个屏幕,并始终知道焦点所在位置?
  • 总结

    优秀的界面设计更多源于一致的约束而非艺术直觉:基于 ch 单位的行长度、固定的间距比例、深色主题中以明度表现深度的效果、模拟真实光线的阴影,以及始终可见的焦点环。这些都是易于审核的小规则,因此可以通过令牌、代码检查规则和清单来强制执行,而无需在每次拉取请求时都依赖个人审美。

    相关阅读

  • 九种深色模式实现方式对比:从滤镜技巧到服务器Cookie —— 对比将深色模式应用于网页应用的九种方法,包括滤镜反转、令牌机制、light-dark()函数以及服务器Cookie,并了解每种方法会悄然引入哪些漏洞。