双语营销站背后的 13 个排版决定
我们刚刚把 ByteSpike 营销站的 brand v2 完整发出来 —— 新 wordmark、新渐变、新 sparkle motif。看得见的那部分一周就交付了。排版细节做得更久 —— 而你本应该完全察觉不到。下面是真正改了什么,以及为什么。
双语营销站背后藏着几十个排版决定,错一个之前你都察觉不到。行距没问题,直到切到中文,正文一下子像憋着喘气。字距没问题,直到分辨率过了 1440px,标题开始飘。Sparkle 的脉冲没问题,直到你看了两遍页面,意识到它在和正文抢你的注意力。
我们刚刚在 bytespike.ai 完整跑完一轮 brand v2 迁移 —— 新 wordmark、新渐变(mint → teal-bright → cobalt 替代旧的 deep-blue / cyan / teal)、新的 sparkle motif(直接从 wordmark 的 K 字母里抠出来)。看得见的那部分 —— 换 logo + favicon —— 几个小时搞定。陪着它一起做的排版工作,占了后面整整一周。很多都是微决定;合在一起,就是「读起来专业」和「读起来差一点」之间那条线。
没人讨论的行距问题
Geist 默认正文 1.5 行距,拉丁文没问题,中文不行。汉字字形比拉丁字形占 em-box 占得更满,同样数值的 line-height 看起来就是会更挤 —— 正文容易读出窒息感。所以我们把营销站默认保留 1.5,对 `:lang(zh) p` 和 `:lang(zh) li` 单独覆盖到 1.7。这是 Apple、Notion、Linear 在做 CJK 本地化营销文案时统一用的行距。标题通过自己显式的 leading-* class 保留紧凑;只让长流式正文吃这个差。
为什么标题在小屏要松、在大屏要紧
标题默认 tracking 是 -0.025em,1024–1280px 范围里看着正常。过了 1440px,同一个值就开始读出松散感:每 em 占的像素更多,负 tracking 收的距离反而比例上变小了。我们补了 `lg:tracking-[-0.028em] xl:tracking-[-0.03em]`,让标题在视口变宽时同步收紧 —— 即使字号 scale 上去了,视觉节奏也保持一致。字号那一头早就用 clamp 处理流式缩放;这一头处理的是流式间距。
动效什么时候得给阅读让路
Hero 顶部那个 sparkle 原本是无限循环脉冲。盯了三个不同时段的页面之后,结论每次都一样:每 3.6 秒它都在跟标题抢注意力。所以我们把它改成了入场单次脉冲 —— 1100ms、ease-out、迭代一次、backwards fill —— 进站时跑一遍,结束后停在静态光晕上。再把它延迟 500ms 触发,让它在标题 + 副标题 + CTA 这条 bs-reveal cascade 跑完(300ms 收尾)之后才入场。眼睛是在文字读完之后才落到 sparkle 上,而不是被它先拽过去。
完整的 13 个决定
- 1. CJK 正文 line-height = 1.7(用 `:lang(zh)` 覆盖);拉丁文保留 1.5。
- 2. 标题字距阶梯:base -0.025em / lg -0.028em / xl -0.03em。
- 3. Hero 字号 = `clamp(2.4rem, 5.6vw, 4.5rem)` —— 跨视口流式,不堆 media query 台阶。
- 4. 标题 leading = 1.04(紧凑、编辑感);正文 leading 宽松(1.5 / 1.7)—— 永远不同值。
- 5. Sparkle 脉冲:迭代一次,1100ms,ease-out,backwards fill —— 营销面绝不上无限循环。
- 6. Sparkle 入场 delayMs = 500ms —— 落在 bs-reveal 文本 cascade 收尾之后。
- 7. Sparkle motif 按尺寸分工:K 字形(品牌 SVG)用在 ≥48px 装饰;lucide 4-point Sparkles 用在 12–16px 内联点缀(K 在小尺寸读不出来)。
- 8. ::selection 背景 = brand teal-bright,不是 cobalt —— cobalt 配白字对比度太硬,不适合做选中态。
- 9. 价格表的 hover 过渡用品牌 cubic-bezier(0.32, 0.72, 0.4, 1),不是 Tailwind 默认的 cubic-bezier(0, 0, 0.2, 1)。同样 200ms,曲线起手更柔。
- 10. Wordmark 高度:Nav 里 22px,Footer 里 20px —— 2px 的差肉眼看不出来,但默默说出「这一行是主导航」。
- 11. 字体栈按字符集分链:拉丁文用 Geist(sans + mono),中文用 Noto Sans SC 走 `var(--font-zh)`,回退到 PingFang SC / Microsoft YaHei —— 绝不让一条 fallback 链同时管两个字符集。
- 12. 圆角走 4-point scale(6 / 8 / 12 / 16 / 20px)。没有 7px,没有 10px,没有「设计师拍脑袋」的圆角。这个纪律比具体数值更重要。
- 13. 缓动只有两条曲线:`ease-out` 用在入场和 hover;`ease-in-out` 用在状态循环。不上 spring overshoot,不上回弹。克制就是品牌的声音。
刻意不调的部分
做品牌的时候有一种诱惑:把所有粗糙的边都磨掉 —— 让选中色精确匹配标题渐变、把所有阴影都柔化到「精致」为止。我们没这么做。body 大背景的 radial-gradient 保留原本偏 teal 的色调,而不是去贴新的 cobalt;K sparkle 的饱和度比 wordmark 文字略高一档。这些小小的不和谐,是让页面不至于读起来像死透了的关键 —— 它留下了指纹。
排版是品牌工作里最慢的那部分。你没办法从 Figma 导出生成它,你没办法在一次 PR review 里把它推完,而且做得对的话大半都是隐形的。但读者每一次落到页面上都会感受到它。所以你就磨。