黑底上悬着一团由 93 个技术名词组成的球,绕横轴匀速翻滚,转到背面的标签会自然变小变暗。鼠标移进球体范围内,旋转立即暂停;悬停在某个标签上时,其余标签淡到四分之一透明度,被指的那个单独留亮。球外面还有一圈看不见的扇形分区,点一下就把整团标签转到对应角度。全程纯 CSS,没有一行 JavaScript——球面坐标是 CSS 的三角函数算出来的,暂停和高亮用的是 :has() 选择器。
没有脚本,标签是怎么排到球面上的
每个标签只写一个序号。HTML 里每个 li 带一个 --index,样式用序号和总数算出它在球面上的经纬度,再转成三维坐标,增减标签只需要改一处总数。
分布用的是螺旋取点法。不是简单按行列铺,而是让相邻标签之间的角度按固定步长递增,这样点会像葵花籽一样均匀铺满球面,不会在两极挤成一团。
标签自身反向旋转。球在转,标签内层同时做一次等量的反向旋转,所以文字始终正面朝向读者,不会跟着翻过去变成倒字。
球面坐标是怎么用 CSS 算的
核心就是下面这一行——用反余弦把序号映射成极角,再配合一个由总数开方得到的步长求出方位角:
--_phi: acos(calc(-1 + (2 * var(--index)) / var(--num-elements)));
有了这两个角,用 cos/sin 组合出 x、y、z 三个分量,归一化后乘以球半径,最后交给 translate3d 定位。CSS 能直接写 acos、sqrt、cos、sin 是近两年才普及的能力,这也是这份源码能完全脱离 JavaScript 的前提。
手动转动那部分同样没有脚本:外圈藏着 20 个扇形的 radio 输入,每个扇形对应一个角度值,选中哪个,:has() 就把整体的旋转变量改成对应数字,再由过渡动画平滑转过去。
能改的地方
球的直径、标签字号与色值、自转周期和方向都在 :root 的变量里,调 --tagcloud-animation-duration 就能改快慢,把方向改成 reverse 即可反转。换内容时把 li 整段替换成自己的词条,并同步改外层 ul 上的总数;不需要链接的话,把里面的 a 换成 span 即可。响应式断点已经写好了两档,窄屏会自动缩小球径。
常见问题
标签堆在一起或者不转?
先确认外层 ul 上的总数和实际条目数一致,数量对不上会让坐标算错。另外 CSS 三角函数需要 Chrome、Edge、Safari、Firefox 的较新版本,旧版浏览器解析不了 acos 会导致所有标签叠在中心。
手机上能转吗?
自转正常。但暂停与高亮依赖悬停状态,触摸屏上没有真正的 hover,触摸时的表现会和桌面端不同,做移动端优先的页面时可考虑去掉这两条规则。
标签太多会卡吗?
每个标签都是独立元素并各自运行一条动画,数量上到两三百个后低端设备会开始掉帧。可以减少标签数,或者把字号调小、关闭文字外发光的多层 text-shadow 来减轻绘制压力。
适合用在哪
技术栈展示、博客的标签归档页、个人作品集首页的技能墙,以及活动页里需要「信息量很大」观感的装饰区块。球面坐标推导与 :has() 控制的完整写法都在样式文件里,下载后可查看。