用 CSS clip-path: polygon() 画一个数学正确的蜂巢网格

约 7 分钟CSSclip-path前端布局
文章目录 (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)正六边形的六个顶点,就是把盒子当坐标系描一遍:

顶点坐标含义
150% 0%上边中点(顶尖)
2100% 25%右上角
3100% 75%右下角
450% 100%下边中点(底尖)
50% 75%左下角
60% 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 算对才是蜂巢真正的设计难点。

评论

纯文本,不支持链接/图片

加载评论…