CSS的tan()三角函数到底能整啥活儿,手把手教你用数学做出多边形菜单

1,960字
8–12 分钟
in

搞前端的应该都听说过,CSS的三角函数在去年被评为了“最让人头秃”的特性。这玩意儿真有那么难用吗?其实吧,只要弄明白tan()到底是啥,就会发现它简直是为做多边形形状量身定制的神器。

目录

tan()是个啥玩意儿

从数学课本上讲,tan()就是一个角度的正切值,等于这个角度的对边长度除以邻边长度。放到一个直角三角形里头,假如选了个锐角,那么tan()就等于对面的那条边长度除以旁边的那个边长度。这玩意儿在CSS里最大的用处,就是帮咱们算出那些看起来特别规整的多边形切片到底该有多大。

从零开始造个多边形菜单

搭个架子

先整一个无序列表,里头放上咱们需要的菜单项。每个菜单项都得有个独立的编号,方便后面计算。

<ul style="--total: 6">
  <li style="--i: 1">🍕</li>
  <li style="--i: 2">🍔</li>
  <li style="--i: 3">🍟</li>
  <li style="--i: 4">🌭</li>
  <li style="--i: 5">🥗</li>
  <li style="--i: 6">🍦</li>
</ul>

这里用--total记录了总共有几个菜单项,--i记录了每个项目自己的序号。写HTML的时候可以手动把这些变量塞进去,等以后浏览器支持了sibling-index,就能自动识别了,但现在先这么干着。

计算旋转角度

每个菜单项都得绕着中心点转一定的角度,这样才能形成一个完整的圆环。这个角度很好算,一圈360度除以总个数,再乘上当前项目的序号。

li {
  --angle: calc(360deg / var(--total) * var(--i));
  transform: rotate(var(--angle));
}

直接这么一转,所有元素都堆在一块儿了,因为它们的旋转中心都在各自的正中间。这时候得把transform-origin改成left center,让它们都往左偏一点。

定位三角形

先把每个元素挪到正确的位置上,再旋转。注意顺序不能搞反,得先平移再转。

li {
  --radius: 35vmin;
  width: var(--radius);
  transform: translateX(calc(var(--radius) / 2)) rotate(var(--angle));
  transform-origin: left center;
}

这样摆出来之后,每个元素就像风扇叶子一样向外辐射开了。但是它们都还是长方形,得用clip-path切成三角形。

li {
  clip-path: polygon(100% 0, 0 50%, 100% 100%);
}

切完以后,看起来就像是披萨被切了一刀,但是每块之间都有缝隙,没完全接上。这是因为每个三角形的高度不对,需要重新算。

用tan()算完美高度

想象一下,把每个三角形从中间劈开,就变成了两个直角三角形。这两个直角三角形的角度,正好等于一圈360度除以总个数的两倍。知道了角度,又知道了三角形的宽度(就是--radius),就能用tan()算出对边的高度了。

li {
  --theta: calc(360deg / 2 / var(--total));
  height: calc(2 * var(--radius) * tan(var(--theta)));
}

这个公式算出来的高度,能让三角形的尖尖刚好挨在一起,形成一个严丝合缝的多边形。如果总共有6个菜单项,算出来就是一个六边形;如果是8个,就是个八边形。可以随便改--total的值,形状自动适配。

玩转transform-origin还能整出不一样的效果。如果把旋转中心从left center换成center center,就能做出从中心往外辐射的效果,看起来像是那种可以展开收缩的圆形菜单。

搞个高能版圆形选人盘

把上面做的多边形外面再套一层圆形裁剪,立马就能变成游戏里那种选角色的转盘。

ul {
  clip-path: circle(50% at 50% 50%);
}

每个菜单项还是三角形的尖角,但是外层容器被裁成圆了,看起来就像是每个菜单项都是圆形的一部分。这招在做那种角色选择、颜色切换、或者类似游戏手柄的轮盘菜单时特别管用。

把菜单项摆成多边形相册

一样的原理,把每个三角形换成图片,就能整出多边形相册墙。每个图片都被裁剪成三角形,拼在一起就成了一个完整的正多边形。鼠标滑上去还能给每个三角形单独加特效,交互感直接拉满。

这背后全靠tan()撑腰,它让每个三角形的高度能根据角度自动算出来。要是没有它,就得每个角度都手动调高度,换一次菜单项数量就得重新算一次,头都能大。

tan()在CSS里最大的本事,就是解决那些“知道角度、知道一条边、想求另一条边”的问题。只要遇到这种直角三角形的场景,直接上tan()准没错。以后再也不用对着那些奇奇怪怪的多边形形状挠头了,数学公式一摆,代码一敲,完美形状就出来了。