环形菜单坐标计算必须用 Math.sin 和 Math.cos,因为其本质是极坐标转直角坐标:cos 得 x 偏移,sin 得 y 偏移(CSS 中需取负以匹配逆时针视觉);JS 三角函数只接受弧度,角度须转为 Math.PI/180 倍数;圆心基于父容器 center 定位,子项用 absolute + left/top 计算;起始角如 12 点方向为 -Math.PI/2;纯 CSS 无法运算,需 JS 计算后通过 CSS 自定义属性传参并配合 calc 使用;transform rotate+translate 易错位,推荐绝对定位;响应式需动态适配半径与圆心,确保触摸区域≥44px。
环形菜单坐标计算为什么必须用
和
因为环形布局本质是极坐标转直角坐标:每个菜单项在圆周上的位置由角度 θ 决定,而
给出 x 偏移,
给出 y 偏移(注意:CSS y 轴向下为正,所以实际要用
才符合视觉上“逆时针展开”的直觉)。
常见错误是直接用角度值当像素偏移,或混淆弧度/角度单位——JavaScript 三角函数只认弧度,
度得写成
,不是
。
圆心设为父容器
中心点(如
),所有子项用
定位
每个子项的
=
,
=
角度等分要从起始偏移考虑:比如想第一个菜单在正上方(12点钟方向),对应角度是
,不是
用 CSS 自定义属性配合 JS 动态生成坐标的实操方式
纯 CSS 无法运行三角函数,必须用 JS 计算坐标后注入 style 或 CSS 变量。推荐用 CSS 自定义属性传参,让动画和布局分离:
给菜单容器加
JS 读取这些变量:
循环计算每个项的角度(弧度):
用
等设置变量,CSS 里用
这样动画可完全用 CSS 过渡
/
,JS 只负责初始化坐标,不参与每一帧渲染。
立即学习
“
前端免费学习笔记(深入)
”;
使用HTML,CSS,JavaScript开发Android应用程序 英文文字pdf版附源文件
如果你了解HTML,CSS和JavaScript,您已经拥有所需的工具开发Android应用程序。本动手本书展示了如何使用这些开源web标准设计和建造,可适应任何Android设备的应用程序 - 无需使用Java。您将学习如何创建一个在您选择的平台的Android友好的网络应用程序,然后转换与自由PhoneGap框架到一个原生的Android应用程序。了解为什么设备无关的移动应用是未来的潮流,并开始构建应用程序,提供更
下载
和绝对定位坐标的区别与选型
有人尝试用
+
实现环形,但要注意:旋转中心默认是元素自身中心,叠加多次 transform 容易错位;而绝对定位坐标是直接锚定到父容器,更可控、调试更直观。
如果菜单项尺寸统一且需旋转文字朝向切线方向,才考虑
配合
—— 此时需额外计算文字旋转角度:
若只是展开收起动效,用
和
配合已算好的
/
更稳定
避免在
中同时过渡
和
,会触发 layout,优先全用
(即改用
/
)
响应式环形菜单容易被忽略的三个坑
环形菜单在 resize 或移动端常崩,核心问题不在三角函数,而在坐标基准没随视口变化:
半径
不能写死像素值,建议用
单位或 JS 监听
重算(尤其 iPad 分屏时)
圆心坐标依赖父容器宽高,若父容器用
或
布局,确保其
不为
,否则
计算失效
手机端触摸区域小,每个菜单项至少保证
可点击区,可用
扩展 hit area,但不要影响
位置
真正麻烦的从来不是 sin/cos 公式本身,而是把数学结果稳稳落到不同尺寸、不同缩放、不同设备的像素网格上。
Math.sinMath.cosMath.cos(θ)Math.sin(θ)-Math.sin(θ)30Math.PI / 630transform-origin50% 50%position: absoluteleftcenterX + radius * Math.cos(angleRad)topcenterY - radius * Math.sin(angleRad)-Math.PI / 20style="--item-count: 5; --radius: 120px; --start-angle: -90;"const count = parseInt(getComputedStyle(el).getPropertyValue('--item-count'))const rad = (startDeg + i * 360 / count) * Math.PI / 180el.style.setProperty('--x', (radius * Math.cos(rad)).toFixed(2) + 'px')left: calc(50% + var(--x))lefttoptransform: rotate()transform: rotate()translate()rotate()translateangleRad + Math.PI / 2opacityscalelefttoptransitiontransformleft/toptransformtranslateXtranslateY--radiusvminresizeflexgridheightauto50%44px × 44pxpaddingtransform-origin