Skip to content

Conversation

@aojunhao123
Copy link
Contributor

@aojunhao123 aojunhao123 commented Jan 10, 2026

Clipboard-20260110-124613-577

这个bug还挺有意思的,想要触发它得满足两个条件:

  1. 小尺寸屏幕(因为本质上是个精度问题,我用的14寸 macbook可稳定复现)
  2. 鼠标hover在FloatButton边缘(滚动条出现时造成的布局偏移会使得FloatButton离开鼠标位置,然后滚动条消失,FloatButton又回到鼠标hover区域,如此循环往复生生不息...)

Tooltip 有个贴边检测的特性,会动态计算Tooltip自身与可视区域的距离,来决定自身的渲染位置是否要做偏移或者翻转。
而这个bug的根因也来自于这个特性。
简单讲讲bug触发链路:

  1. 计算Tooltip初始位置,得到偏移量
  2. shift检测,发现超出可视区,需要进行调整,二次计算得到新的偏移量
  3. 使用Math.round,四舍五入对浮点数取整得到最终结果,这一步是为了解决某些尺寸的屏幕或浏览器缩放比例带来的精度问题

问题就出在第三步的Math.round上,当偏移量的小数部分>=0.5时,向上取整,得到的结果偏大,造成了Tooltip最终的渲染位置超出容器宽度,出现滚动条,于是布局抖动,不断重复mouseenter -> mouseleave的循环,产生图中疯狂抽风的问题

而Math.round是为了解决这个issue引入的,但其实也没完全解决。精度问题本身组件库层面就无法完全解掉,用户的屏幕尺寸、浏览器缩放比例都是不可控的,我通过触控板放大页面依旧能看到箭头与弹层的缝隙
image

总之我的方案是将round改为floor,向下取整,来避免这个情况。以下是修复后的表现:

Clipboard-20260110-151641-671

Summary by CodeRabbit

  • Bug Fixes
    • 修正弹出框在未缩放时的对齐偏移计算,改为向下取整以提高水平和垂直对齐的一致性。
  • Tests
    • 对应测试已更新,验证在小数精度情况下使用向下取整的对齐结果。

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 10, 2026

Walkthrough

在对齐计算中,当 popup 在水平方向或垂直方向未缩放(scaleX === 1 / scaleY === 1)时,将用于计算偏移的两处数值取整从四舍五入(Math.round)改为向下取整(Math.floor);相应测试断言已更新以验证向下取整行为。

Changes

Cohort / File(s) 变更摘要
取整逻辑调整
src/hooks/useAlign.ts
当 scaleX === 1 / scaleY === 1 时,将用于计算 nextOffsetXoffsetX4RightnextOffsetYoffsetY4BottomMath.round() 改为 Math.floor()(+4/-4),仅调整截断行为。
测试更新
tests/align.test.tsx
测试名称与断言从“round when decimal precision”更新为“floor when decimal precision”,期望值由 56px 改为 55px(+2/-2)。

Sequence Diagram(s)

(此变更为小范围取整行为调整,未引入新的跨组件控制流,故省略序列图。)

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 分钟

Possibly related PRs

Suggested reviewers

  • afc163
  • yoyo837
  • zombieJ

🐰 数字轻跳在角落间,
向下取整换新颜,
垂直水平细微变,
边界安稳心不烦。

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed 标题准确反映了主要变更:从Math.round改为Math.floor以修复精度问题导致的弹出框滚动问题,与代码和测试的实际改动完全一致。
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @aojunhao123, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

此拉取请求旨在解决Ant Design组件库中一个由浮层定位精度问题引起的UI抖动bug。该问题主要影响Tooltip和FloatButton等组件,在特定屏幕尺寸和交互模式下,由于水平偏移量计算不精确,导致容器出现不必要的滚动条,从而造成视觉上的闪烁。通过调整核心对齐逻辑中的舍入方法,确保浮层始终在预期范围内渲染,从而提升了用户体验和组件的稳定性。

Highlights

  • 修复浮层容器滚动问题: 解决了在特定条件下(如小尺寸屏幕、鼠标悬停在FloatButton边缘)浮层(如Tooltip)因精度问题导致容器出现滚动条,进而引发布局抖动和无限循环mouseenter/mouseleave的bug。
  • 问题根源:Math.round的精度处理: 该bug的根本原因在于Tooltip位置计算中使用了Math.round进行四舍五入取整。当偏移量的小数部分大于等于0.5时,Math.round会向上取整,可能导致Tooltip最终渲染位置超出容器宽度,从而出现滚动条。
  • 解决方案:将Math.round改为Math.floor: 通过将计算水平偏移量(nextOffsetX和offsetX4Right)时使用的Math.round函数替换为Math.floor,确保向下取整,避免了因向上取整导致浮层超出容器宽度的问题。

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

你好,感谢你的贡献。这个 PR 旨在修复一个由于浮点数精度问题导致的弹窗容器出现滚动条,进而引发无限循环抖动的 bug。你通过将 Math.round 修改为 Math.floor 来处理 X 轴上的偏移量,确保计算结果不会因为向上取整而超出容器宽度,这是一个很直接且有效的解决方案。

我在代码中发现,Y 轴方向的偏移量计算仍然在使用 Math.round,这可能会在特定情况下导致类似的高度溢出问题。我在具体的代码行上留下了评论,建议为了逻辑一致性和健壮性,将 Y 轴也统一使用 Math.floor 处理。

总体来说,这是一个高质量的修复,很好地解决了描述中的问题。合并前请考虑一下我提出的建议。

Comment on lines -701 to +702
nextOffsetX = Math.round(nextOffsetX);
offsetX4Right = Math.round(offsetX4Right);
nextOffsetX = Math.floor(nextOffsetX);
offsetX4Right = Math.floor(offsetX4Right);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

round改为floor我理解没什么副作用,唯一的弊端可能就是精度差异会变大,原来最多0.5px的差异,现在最大精度差可能为0.99px,但用户真能感知到吗(

@codecov
Copy link

codecov bot commented Jan 10, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.26%. Comparing base (edea4d2) to head (d80e240).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #602   +/-   ##
=======================================
  Coverage   97.26%   97.26%           
=======================================
  Files          17       17           
  Lines         949      949           
  Branches      278      278           
=======================================
  Hits          923      923           
  Misses         26       26           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/hooks/useAlign.ts (1)

694-708: Math.floor 可能在负偏移场景引入额外 1px 偏移;建议改为“向 0 截断”并对 scaleX 用 epsilon 判断

Math.floor 能避免正数偏移“进位”导致的越界(你们要修的点),但在 nextOffsetX/offsetX4Right 为负数时会把 -0.2 变成 -1,相比之前 Math.round 可能产生额外 1px 的反向位移/间隙,极端情况下也可能把溢出问题从右侧挪到左侧(取决于 placement/RTL/容器 overflow)。另外 scaleX === 1 过于严格,某些缩放/精度下可能得到 0.999/1.001 从而绕过该分支。

建议改法(示例)
-      if (scaleX === 1) {
-        nextOffsetX = Math.floor(nextOffsetX);
-        offsetX4Right = Math.floor(offsetX4Right);
-      }
+      const isScaleXOne = Math.abs(scaleX - 1) < 1e-3;
+      if (isScaleXOne) {
+        // 向 0 截断:正数用 floor,负数用 ceil,避免负数被额外“放大”
+        nextOffsetX = nextOffsetX > 0 ? Math.floor(nextOffsetX) : Math.ceil(nextOffsetX);
+        offsetX4Right =
+          offsetX4Right > 0 ? Math.floor(offsetX4Right) : Math.ceil(offsetX4Right);
+      }

建议至少回归验证:RTL、nextOffsetX < 0 的 placement、不同浏览器缩放(例如 90%/110%)、以及容器 overflow: auto 下是否仍会出现横向滚动条/hover 抖动。

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between edea4d2 and 343f433.

📒 Files selected for processing (1)
  • src/hooks/useAlign.ts

@zombieJ zombieJ merged commit 32d8430 into react-component:master Jan 12, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

官网 FloatButton with tooltip 例子鼠标移入出现滚动条并无限抖动

2 participants