CSS 与布局 / 圆角三部曲:一个角的二十年 / border-radius 之前:圆角是图片 待审核 1 / 5
legacy · 圆角前传

border-radius 之前:圆角是图片

border-radius 进入浏览器之前,CSS 里没有任何属性能画一条弧线。无前缀的 border-radius 最早随 Chrome 4(2010-01)、Opera 10.5(2010-03)、Safari 5(2010-06)落地,Firefox 4 与 IE9 到 2011-03 才跟上 [1]。在那之前,设计稿上一个 4px 的圆角落到实现就是一道工序:先画一张带圆角的图,再想办法把它贴到宽高可变的盒子上——图片尺寸固定,而内容会伸缩。本页回顾那套切图工程:烘焙圆角图滑动门四角拼贴与角对象

1 · 圆角图的烘焙

圆角图最简便的画法是 SVG 的 <rect>rx / ry,矢量且参数化。但当年 IE6 至 IE8 不认 SVG 背景,且为求像素精确(各引擎抗锯齿不一),工作流是把 SVG 用栅格化工具烘焙成定尺 PNG 再上线。本页这些 PNG 是用命令行工具 resvg 从同一份 SVG 生成的真实文件,命令形如 resvg -w 220 -h 130 box.svg box-r36.png

图 1-1 · 同一份 SVG 与烘焙出的 PNG 并排。可切到 PNG 档观察「没有 border-radius 时纯靠一张位图得到圆角」是什么状态。

注 · 烘焙的代价是每个半径都成了一张单独的图。assets/ 里只有 box-r0box-r12box-r24box-r36box-r48box-r60 六张 PNG,所以图 1-1 的滑块会吸附到最近的一档——想要 37px 就得重跑一次 resvg 再上传。圆角的样式被固化进了二进制资产。

2 · 滑动门

圆角图有了,新问题是按钮与标签的宽度由文字决定,而图片宽度固定。Douglas Bowman 2003 年在 A List Apart 提出的滑动门(sliding doors)解法是:把两张图分别钉在盒子的左右两端,左边那扇门露出左圆角,右边那扇露出右圆角,中间是两张图重叠的纯色平直段。文字一多盒子变宽,两扇门向两侧滑开,中间平直段自然延长,圆角始终贴着两端 [2]。

图 2-1 · 两扇门随文字宽度滑开的过程。可切到「露出边界」看两张图的交接线,并改文字长度观察圆角是否始终贴边。

注 · 两扇门各管一个圆角:外层盒子用窄窄的 door-right.png(只含右圆角)钉在右端,内层用够宽的 door-left.png(左圆角加向右延伸的纯色身体)钉在左端,并在右侧留出宽度让右门露出。两张图的圆角处都是透明的,且背后不能有不透明色块——若像早期常见写法那样给盒子补一层 background-color 填底,透明圆角会被填成方角。本页的 _shared.css 因此没给这两层任何 background-color

3 · 四角拼贴与 OOCSS 的角对象

滑动门只管水平伸缩。要让盒子宽高都能变,就把四个圆角各做一张小图分别钉在四个角,中间用可平铺的纯色或渐变填满,这是九宫格(9-slice)的雏形。Nicole Sullivan 的 OOCSS(Object-Oriented CSS,2009)把这套结构封装成可复用对象:一组与内容无关的嵌套 div 加角图,套到任意盒子上都能长出圆角,不必改内容的 HTML 语义。

图 3-1 · 四张角图钉在四角、中间平铺的结构。可改盒子的宽与高,观察四角图片如何各自留在原位。

注 · OOCSS 的两条原则正好对上圆角这件事。分离结构与皮肤:圆角属于皮肤,可独立成一个 .box-rounded 对象,与盒子的尺寸和定位无关。分离容器与内容:角对象不关心里面装的是表单还是文章,任何内容塞进去都能获得同一套圆角。这种可复用、与内容解耦的思路是后来组件化 CSS 的先声。

3.1 · border-radius 之前的几种方案

共同的根本痛点是圆角成了资产而非样式:不能继承、不能动画、不随主题色与字号变化。
方案 怎么做 代价
纯图片 整块背景就是一张带圆角的 PNG 宽高写死,内容一变就破图;改半径要重新出图
滑动门 左右两张图随文字宽度滑动,中段平直延伸 只解决水平伸缩;需要嵌套元素与精确背景定位
四角 / 九宫格 四角图加可平铺的边与中心,宽高皆可变 最多要 4~9 个额外 div,HTML 被皮肤污染
OOCSS 角对象 把四角结构封装成可复用对象,套任意内容 仍是图片加多层 div;无法响应文字色与主题色变化
1px 阶梯 hack 用几条高度递减的 div 模拟锯齿状伪圆角 只在纯色背景下凑效,放大即露馅,不抗锯齿

警示 · 标准化之前各引擎先用私有前缀抢跑,Gecko 是 -moz-border-radius(Firefox 1,2004-11 起)、WebKit 是 -webkit-border-radius(Safari 3,2007-10 起),而早期 -moz- 的逐角 longhand 命名与标准并不一致,写作 -moz-border-radius-topleft 而非 -moz-border-top-left-radius [1]。那几年的写法常是三行叠一个圆角,-webkit--moz- 与标准各写一遍,这也是 Autoprefixer 一类工具诞生的土壤。

切图、滑动门、角对象都是在「图片固定、内容可变」这对矛盾里打转。border-radius 一页接着讲它如何用一行声明把圆角变成渲染时计算的矢量弧,彻底取消这道工序。

4 · 参考文献

  1. MDN Web Docs. border-radius 浏览器兼容性数据(BCD). Mozilla.(含 -moz- / -webkit- 前缀期的版本与 longhand 命名差异,核对于 2026-08)
  2. Bowman, D. (2003). Sliding doors of CSS. A List Apart, 160.
  3. Sullivan, N. (2009). Object Oriented CSS.