用 CSS clip-path: polygon() 画一个数学正确的蜂巢网格
文章目录 (8)
为什么用 clip-path,而不是 SVG 或切图
要在一堆方形 <div> 上做「六边形宫格」,常见三条路:
- 切图 / PNG:尺寸一变了就糊,hover 变色、发光都得重做素材;
- SVG /
<polygon>:形状可控,但要给每个格子写一段 path、还得单独处理事件与背景,DOM 一下变重; - CSS
clip-path: polygon():直接给任意元素裁形,背景、渐变、::before全都照常,元素仍是普通盒子,尺寸和位置交给 transform。
我选了第三条。一个元素 + 一行 clip-path,形状、动画、响应式全部用普通 CSS 就能驱动,这是 polygon 相对 SVG 最大的爽点:裁形是「样式」,不是「资源」。
polygon() 的语法:就是给多边形报顶点
.hex {
clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);
}
polygon() 接收一串顶点,从第一个点开始依次连线、首尾自动闭合,框内的部分保留、框外裁掉。坐标是相对元素自身盒子的百分比,(x, y) 里 x 从左往右、y 从上往下。
尖顶(pointy-top)正六边形的六个顶点,就是把盒子当坐标系描一遍:
| 顶点 | 坐标 | 含义 |
|---|---|---|
| 1 | 50% 0% | 上边中点(顶尖) |
| 2 | 100% 25% | 右上角 |
| 3 | 100% 75% | 右下角 |
| 4 | 50% 100% | 下边中点(底尖) |
| 5 | 0% 75% | 左下角 |
| 6 | 0% 25% | 左上角 |
上下各收成一个尖、左右各留一段竖直边——这就是「尖顶六边形」。如果写成 polygon(25% 0%, 75% 0%, 100% 50%, ...),就是平顶(flat-top)版本,只是把整个图形转了 90°。
关键约束:宽高比必须锁死,否则角度会歪
clip-path 的坐标是百分比,会跟着盒子宽高各自拉伸。同样这六个百分比,只有当盒子本身是特定比例时,裁出来的才是「正」六边形。
正六边形(尖顶)的宽 w(两竖边之间)与高 h(两尖之间)满足:
h = w × 2 / √3 ≈ 1.1547 × w
一旦宽高比偏离 1.1547,六个角就不再是 120°,图形会被「压扁」或「拉长」。所以布局里每个六边形的高度都不是随便定的,而是从宽度反推:
const hexW = pitch - GAP;
const hexH = hexW * 2 / Math.sqrt(3); // 锁死正六边形比例
拼成蜂巢:错位半格 + √3/2 的行距
单个六边形裁对了,还只是第一步。要像蜂巢那样「咬合」——下一行正好嵌进上一行的凹槽——行与行、列与列的间距有讲究。
设相邻两列中心的水平距离为 pitch(格距),六边形之间留 GAP 的缝,那么:
- 水平方向:
hexW = pitch − GAP,同行相邻中心距恒等于pitch; - 错位:奇数行整体右移半个格距,
x = col·pitch + (row % 2 ? pitch/2 : 0),才能卡进上一行的 V 形槽; - 行距:上下两行中心的垂直距离不是
pitch,而是rowStep = pitch × √3 / 2 ≈ 0.866 × pitch。
等距自检:为什么缝隙是均匀的
很多人凭感觉取 rowStep,其实 √3/2 这个系数是被「水平相邻」和「斜向相邻」必须等距逼出来的。
斜着挨着的两个六边形,水平差 pitch/2、垂直差 rowStep,它们的中心距是:
√((pitch/2)² + rowStep²)
要让这个斜距等于水平距 pitch,解出 rowStep:
√((p/2)² + (p√3/2)²) = √(p²/4 + 3p²/4) = √(p²) = p ✓
代回 rowStep = p√3/2 恰好成立。所以只有取这个行距,六边形网格每一条缝的宽度才一致——蜂巢看起来「匀」,本质是这条等式在兜底。取错一个系数,缝隙就会一行宽一行窄,一眼就能看出破绽。
响应式:反推 pitch,让比例随容器缩放
容器变窄时不能靠 clip-path 自己缩放(它只会跟着盒子拉伸、破坏 1.1547 比例)。正确做法是重新算 pitch,让宽高一起等比缩,比例恒定:
// 已知可用宽度 W、列数 cols,反推每格中心距
pitch = (W + GAP) / (cols + 0.5);
分母里那个 0.5 就是奇数行右移的半格——最后一行会多出半个 pitch,得从宽度里扣掉,否则右侧会溢出。六边形宽高、字号(fontSize = hexW × 0.38)都由 pitch 派生,于是整套网格在任何宽度下都保持正六边形 + 均匀缝隙。
完整交互演示
下面这个可视化把上面的推导拆成了 6 步动画:单个六边形 → 水平格距 → 错位半格 → 等距咬合验证 → 完整网格 → 响应式缩放。用面板按钮或键盘 ← → 切换,每一步右侧给出对应公式和实时数值。
小结
clip-path: polygon()让裁形变成了纯样式,一个盒子照样能带渐变、伪元素和 transform 动画,这是它相对 SVG/切图的核心优势;- 百分比坐标会跟着盒子拉伸,所以正六边形必须锁
h = w·2/√3的宽高比; - 蜂巢能咬合,靠的是「奇数行错位半格 + 行距
pitch·√3/2」,而这个 √3/2 是被「水平距 = 斜向距」逼出来的,取错缝隙就均匀不了; - 响应式别去缩 clip-path,而是反推
pitch,让派生尺寸整体等比缩放。
形状只是入场券,把 √3 算对才是蜂巢真正的设计难点。
评论
加载评论…