You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何CSS calc()计算鼠标位置比例无法得到预期值1?

问题:为何CSS计算无法得到预期的比例值1?

我创建了一个宽度为100%的div元素,通过两种方式计算鼠标在该元素内的位置比例(最左侧对应0,最右侧对应1,即偏移量与宽度的比值)。JavaScript计算结果符合预期,但CSS计算结果完全不符,最左侧能得到0,但最右侧的结果随窗口大小变化,始终无法得到1。

代码示例

<html>
  <head>
    <style>
      @property --x-offset {
        syntax: '<number>';
        inherits: true;
        initial-value: 0;
      }
      @property --cssVal {
        syntax: '<number>';
        inherits: true;
        initial-value: 0;
      }

      body {
        margin: 0;
        padding: 0;
      }
      div {
        width: 100%;
        height: 100vh;

        --cssVal: calc(var(--x-offset) * 1px / 100%);
      }
    </style>
  </head>
  <body>
    <div></div>
    <script type="module">
      const div = document.querySelector('div')

      div.addEventListener('mousemove', (evt) => {
        const width = window
          .getComputedStyle(div)
          .getPropertyValue('width')
          .slice(0, -2)
        const offset = evt.offsetX
        const jsVal = offset / width

        div.style.setProperty('--x-offset', `${offset}`)
        const cssVal = window.getComputedStyle(div).getPropertyValue('--cssVal')

        // expected to be equal, but are very different
        console.log(cssVal, jsVal)
      })
    </script>
  </body>
</html>

原因分析

问题出在对CSS中100%的使用逻辑误解:

  1. 你试图用100%代表div的实际像素宽度,但CSS中100%是相对值,仅表示“包含块宽度的100%”,无法直接等同于div计算后的实际像素宽度。
  2. 即使div设置了width:100%,理论上宽度等于包含块宽度,但CSS在处理px / %的单位运算时,会因渲染精度、滚动条占用宽度等因素,导致计算结果与实际的“偏移量/宽度”比值出现偏差。
  3. 核心问题:CSS没有原生方法直接引用元素自身的计算后像素宽度,必须通过JavaScript将该值传入CSS变量,才能进行精确的比值计算。

解决方案

修改代码,通过JS将div的实际宽度传入CSS变量,让CSS计算逻辑与JS保持一致:

<html>
  <head>
    <style>
      @property --x-offset {
        syntax: '<number>';
        inherits: true;
        initial-value: 0;
      }
      @property --div-width {
        syntax: '<number>';
        inherits: true;
        initial-value: 0;
      }
      @property --cssVal {
        syntax: '<number>';
        inherits: true;
        initial-value: 0;
      }

      body {
        margin: 0;
        padding: 0;
      }
      div {
        width: 100%;
        height: 100vh;

        --cssVal: calc(var(--x-offset) / var(--div-width));
      }
    </style>
  </head>
  <body>
    <div></div>
    <script type="module">
      const div = document.querySelector('div')

      function updateDivWidth() {
        const width = parseFloat(window.getComputedStyle(div).getPropertyValue('width'))
        div.style.setProperty('--div-width', width)
      }

      updateDivWidth()
      window.addEventListener('resize', updateDivWidth)

      div.addEventListener('mousemove', (evt) => {
        const offset = evt.offsetX
        const jsVal = offset / parseFloat(window.getComputedStyle(div).getPropertyValue('width'))

        div.style.setProperty('--x-offset', offset)
        const cssVal = window.getComputedStyle(div).getPropertyValue('--cssVal')

        console.log(cssVal, jsVal)
      })
    </script>
  </body>
</html>

说明

  • 新增--div-width变量存储div的实际像素宽度,通过JS在初始化和窗口 resize 时更新该值。
  • CSS中直接使用calc(var(--x-offset) / var(--div-width))计算,逻辑与JS的offset / width完全一致,确保结果精确匹配。

内容的提问来源于stack exchange,提问作者Vincent

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.01 16:47:26