MouseEvent.hitClientRect as alternative to non-interoperable MouseEvent.offsetX

MouseEvent.offsetX/Y is in an unfortunate state, especially for inline elements. Blink/WebKit calculate it from the target element’s offsetParent, and Gecko calculates it from the target element (as per spec). This makes it impossible to get reliable offset-from-target measurements without calling getClientRects() or another form of synchronous measurement.

This causes several issues:

  • Synchronous measurements, depending on the point in which they’re done, can cause undesired additional layouts (layout thrashing)
  • The client rect at the time of measurement might be different from the client-rect in the time of hit-testing, as the layout/scroll-position may have already changed by the time the event was handled.
  • getClientRects is especially costly, as it has to account for inilne elements in split rows, transforms etc and is generally not cached by the user agent.

Proposing the following:

  • The MouseEvents (and perhaps other pointer events) will come with a ready hitClientRect property. It would be equivalent to calling getClientRects at the time of the pointer hit-test, and picking the rectangle that contains the hit point (clientX, clientY). In this case, offsetX is roughly equivalent to clientX - hitClientRect.left, but in an interoperable way.

Out of curiosity, is there a known blocker against fixing the offsetX/Y behavior?

Since this is an old issue, there are currently many websites who rely on the current status-quo, e.g. by checking the user-agent and using different measurements for Firefox/IE vs. the rest.

I wonder if there’s no path for conversion there. Do you have specific examples of sites that rely on the current divergent behavior?

I personally do not. This was the opinion I’ve received both from discussion on WebKit Slack and from the relevant Chromium bug (

I also believe that we can convert it with an addEventListener flag, e.g.

element.addEventListener('mouseover', handler, {offsetDimensions:'strict'})