CSS lengths in Gecko are limited to 17,895,697 pixels (2010)
bugzilla.mozilla.org
bugzilla.mozilla.org
Blink and WebKit are less sexy and use tetrasexagesimal a.k.a. 1/64 (https://trac.webkit.org/wiki/LayoutUnit). 1/60 was tried originally, but it was switched to 1/64 for performance and to avoid precision loss. The reason it's faster is interesting: floating point values are also stored as number with a base-2 exponent, so to convert to/from floats, you can use shifts instead of needing division. The differences between 1/60 and 1/64 were important 10 years ago but are pretty minor now.
If you're interested, the code is at https://github.com/mozilla/gecko-dev/blob/d36cf98aa85f24ceef... and https://source.chromium.org/chromium/chromium/src/+/main:thi...
Thanks for that. I was very confused as to why the value was about 7% larger than 16,777,216 (2²⁴), and not exactly that.
But assuming a binary representation (!) having the subdivisions be slightly fewer than a power of 2 (60 being slighly less than 64) means that the whole number limit will be slightly over a power of two, meaning that 60 × 17,895,697 should be a power of 2 (give or take a bit of rounding).
And if you do the multiplication, it's 1,073,741,820, which is... huh. 2³⁰ (- 4).
Why not 2³¹ or 2³²? Looks like they could at least double the CSS length limit there, even while continuing to allow negative lengths.
Edit: As we can see from the parent-linked source on line 36, there is:
# define nscoord_MAX nscoord((1 << 30) - 1)
which confirms the limit, but doesn't say why 30 is used instead of 31.Edit2: Info in the commit message at https://github.com/mozilla/gecko-dev/commit/e632c1393ebedfda...
nscoord_MAX is (1<<30) so that we can check for overflow *after* adding two nscoords.
Makes sense.Say you have a display that will show all items in a database, each row is 20px high, this limits the maximum number of items you can show to 894,784. That may seem absurd, but if you have a UI that allows you to jump to a specific item in the scrolling list, you would expect to be able to do it.
0: https://blog.logrocket.com/virtual-scrolling-core-principles...
So I understand why this would allow you to skip this "hack", but at the same time I kinda feel like absurdly large dimensions are not something reasonable to expect a browser to support, because the browser has to implement a limit at some point. So it definitely feels reasonable to set a limit somewhere moderately beyond wherever you think the longest infinite-scroll-search-results page would produce from somebody actually scrolling for a couple of hours. E.g. maybe a kilometer long, but not 100 or 10,000 kilometers long. (By my calculations, 17,895,697 px at 96 ppi = 4.73 km, which seems pretty decent.)
Moving things, even with "transform: translate()", during an "onscroll" event has really bad performance and will always show some level of lag.
Using the massively optimised bowser scrolling gives a much smoother user experience. What you do with the virtualised scrolling is limit the number of DOM nodes, and where possible recycle them during the scroll. But they are "absolutely" positioned within the scrolling area.
So yes, you could potentially go taller by manually moving elements within an arbitrarily large scroll view, the ux will be frankly quite crap.
To put it another way, if the total height of all items is greater than the height of scroll view, as you scroll from top to bottom the items need to move through the scroll view faster than than the scrolling element. To do that the items need to be moved on each "onscroll" event, even if you only drawing the small fraction of them that are currently visible.
Also if you're just scrolling by tiny amounts (with trackpad or scroll wheel) then the virtualization doesn't matter, you just add new rows as needed while leaving everything in place. It won't precisely line up with the scroll bar position but the difference will be infinitesimally small, and then you can fix it once scrolling ends.
Not a daily WTF at all
A few years back, while I worked at Fastmail, we had a ticket come in from an IE user that they could suddenly only access the first few messages in their mailbox. Trouble was they’d gone over IE’s limit, and IE just ignored the entire height declaration in that case, and so you ended up with only the initially-rendered list items available.
The limits I found:
• Firefox: ignores declarations that resolve to a value higher than 17,895,697 pixels (which is a bit more than 2²⁴).
• IE: ignores declarations that resolve to a value equal to or higher than 10,737,418.23 pixels (2³⁰ − 1 hundredth pixels).
• WebKit: clamps values somewhere around 2²⁵ (~33,554,432) pixels; clamping means you don’t need to worry about it so much, since that was the best workaround in other browsers anyway.
And so we ended up with the workaround code at https://github.com/fastmail/overture/blob/41cdf36f3e7c8f0dd1... (the Firefox check was of much older vintage, I just added the IE case). (Nowadays, the IE part is gone again because IE is gone, hooray!)
So yeah, it actually only took about 200,000 messages in the list to hit this limit and fall over, or subsequently just make the bottom of the mailbox inaccessible. 200,000 messages in one mailbox is uncommon, but not at all unrealistic, especially in an “All mail” sort of mailbox.
For those in this thread saying “why would you ever want to do that?”: this is why. Real scrolling is extremely useful in small cases, and still absolutely useful on occasion as things grow even extraordinarily large. This is not a degenerate case: this is very sane. And pagination of any form would be horrible. Like pagination basically just makes old emails inaccessible except by precise search in Gmail. Fastmail’s approach is very, very strongly desirable here. Pagination is the clumsy hack, not progressive loading of a list (though I will admit that you need list items to be of consistent heights to do a good job of this style of progressive loading).
With a 30px record size, it's only ~600k records, which really doesn't seem that unreasonable to me
Obviously I have feature requests for supporting both larger and smaller time scales so I'll have to figure something else to do. My initial inclination is to virtualize the scrolling, so the element has a minimum and maximum width, and when the user zooms in and out (beyond/close to the min/max) I reset the view and the scroll position. You definitely have to hide the scroll bar in this scenario as it would be jumping all over the place.
[0]: https://github.com/mark-when/markwhen/blob/9823e44d0445d3bf1...
[1]: https://github.com/mark-when/markwhen/blob/main/src/Views/Ti...