Bug 261463 - Line height rounding compounds in element height
Summary: Line height rounding compounds in element height
Status: NEW
Alias: None
Product: WebKit
Classification: Unclassified
Component: Text (show other bugs)
Version: Safari 16
Hardware: Mac (Intel) macOS 13
: P2 Normal
Assignee: Nobody
URL:
Keywords: BrowserCompat, InRadar
Depends on:
Blocks:
 
Reported: 2023-09-12 09:00 PDT by Matias Szylkowski
Modified: 2023-11-22 16:21 PST (History)
7 users (show)

See Also:


Attachments
rendering in Safari, firefox, chrome (197.12 KB, image/png)
2023-09-14 01:44 PDT, Karl Dubost
no flags Details
testcase (803 bytes, text/html)
2023-09-14 01:45 PDT, Karl Dubost
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Matias Szylkowski 2023-09-12 09:00:46 PDT
On multiline text elements with a non-integer line height, the line-height flooring compounds the errors onto the element height. For instance, if `line-height: 9.9px` for a text with 10 lines, the height of the element will be `90px` in Safari (tested in 16 and 17-TP) whereas other browsers (tested in Chrome and Firefox) compute the element height as `99px`. This is reflected in the rendering of each line of text, that in Safari renders each line on the `floor(lineHeight) * lineNumber` pixel (note how the flooring happens before multiplying), whereas on other browsers the lines render on the `round(lineHeight * lineNumber)` pixel (where it computes the correct Y value without rounding/flooring the lineHeight).

This has a lot of repercussions in Safari only:
- `line-height` cannot animate smoothly in Safari.
- Websites cannot rely on `line-height` to control the size of their text elements in Safari.
  - Eg: If I want a text element to span 100px vertically with 8 lines of text, I can't use `line-height: 12.5px` in Safari. The element would be `12px * 8 = 96px` height.

The ways of fixing this (for web developers) are very cumbersome and less performant:
- Setting the font-size and line-height of the text element to a large multiple of the desired size (so Safari has a higher precision), and using transforms to scale it down.
- Manually calculate the Y positions of each line of text, and set the line-height per line in a separate container to achieve that (eg: to span 25px in two lines, use `<div style="line-height="12px">Hello</div><div style="line-height="13px">World</div>`).
- Setting the line-height to an integer and use `transform: scaleY()` to compensate.
- Use images to draw text accurately.

---

Below is a minimal demo. 

https://codepen.io/mszylkowski/pen/xxmgdXb

Setup: Height of box should theoretically be 24.9*10=249

Safari (16 and 17-TP): Computed height is { clientHeight: 240, boundingClientRect.height: 240 }
Firefox: Computed height is { clientHeight: 249, boundingClientRect.height: 249 }
Chrome: Computed height is { clientHeight: 249, boundingClientRect.height: 248.984375 }

Note: this might be a good candidate for improving the interop of Webkit: https://webkit.org/blog/13706/interop-2023/

Found a few similar/related bugs:
- https://bugs.webkit.org/show_bug.cgi?id=225695 (maybe this is a regression?)
- https://bugs.webkit.org/show_bug.cgi?id=216601 (the computed value was fixed)
Comment 1 Karl Dubost 2023-09-14 01:44:33 PDT
Created attachment 467678 [details]
rendering in Safari, firefox, chrome
Comment 2 Karl Dubost 2023-09-14 01:45:17 PDT
Created attachment 467679 [details]
testcase
Comment 3 Karl Dubost 2023-09-14 01:46:53 PDT
Safari:  90px
Firefox: 99px
Chrome:  98.90625px
Comment 4 Radar WebKit Bug Importer 2023-09-19 09:01:14 PDT
<rdar://problem/115729143>
Comment 5 Ahmad Saleem 2023-10-31 14:32:26 PDT
I think Alan was looking into going 'fractional' route for IFC in bug 261212 and I added all possible 'fractional' related issues as 'See Also' in it.