[HN Gopher] Infinite Pixels
___________________________________________________________________
Infinite Pixels
Author : OuterVale
Score : 206 points
Date : 2025-08-07 13:12 UTC (9 hours ago)
(HTM) web link (meyerweb.com)
(TXT) w3m dump (meyerweb.com)
| RoryH wrote:
| This article triggered flashbacks to 20 years ago and using all
| sorts of crazy CSS to hack the browser to do what you needed it
| to. Nowadays CSS is (usually) a remarkable land of sanity in
| comparison.
| Brajeshwar wrote:
| It was also a fun time to interview. Can you write a CSS
| snippet that will make a box red in IE5, Blue in IE6+, and is
| Yellow in Firefox but black in Netscape? CSS these days is no
| longer an adventure -- they just tend to work.
| ge96 wrote:
| I always grab the CSS reset Also the purple story
| maxloh wrote:
| Blink, Chrome's rendering engine, was forked from WebKit (Safari)
| in 2013.
|
| Since WebKit already supported the infinity value at the time of
| the fork [0], it's highly probable that they share the same
| underlying code. This would explain their similar behavior.
|
| [0]: https://caniuse.com/?search=infinity
| chrismorgan wrote:
| You're confusing the JavaScript keyword Infinity, which has
| been around forever, with the CSS keyword infinity, which has
| only been around for 2-3 years <https://caniuse.com/mdn-
| css_types_calc-keyword_infinity>.
|
| And actually I'd be quite surprised if the infinity keyword is
| even relevant here; I would expect the same results if you
| changed each calc(infinity * 1px) to 9999999999999999px.
| Firefox (and, if you go far enough back, IE) will still ignore
| overly large height declarations, and WebKit-heritage browsers
| will clamp it.
| maxloh wrote:
| Thanks for the clarification. However, the number is likely
| encoded in binary format, which is why you're seeing 225 in
| the article.
| breckognize wrote:
| Kinda related - our product, rowzero.io, is a browser-based
| spreadsheet with a 2 billion row limit. We initially built the
| client as anyone would, using a div per cell. We tried to use an
| off-screen div to take advantage of the browser's native
| scrollbars but ran into document height limits. Firefox's was 6M
| pixels iirc. The solution was to do rendering in canvas and draw
| the scrollbars ourselves.
| mmastrac wrote:
| Do you even need to have one scroll pixel == one screen pixel
| (or even one scroll pixel == one spreadsheet row)? At the point
| of 2 billion rows, the scrollbar really falls apart and just
| jumping to an approximation of the correct location in the
| document is all anyone can hope for.
| zwnow wrote:
| Is it completely client side? Why does it have a 2 billion row
| limit? Where are the limitations coming from?
| chrismorgan wrote:
| Firefox's limit is 17,895,697 pixels. Others have a limit less
| than twice as high, so given you're aiming for a value way
| higher than that, it's not a browser-specific issue, except
| insofar as Firefox ignores rather than clamping, so you have to
| detect Firefox and clamp it manually.
|
| In Fastmail's case (see my top-level comment), making the end
| of a ridiculously large mailbox inaccessible was considered
| acceptable. In a spreadsheet, that's probably not so, so you
| need to do _something_ different. But frankly I think you
| needed to use a custom scrollbar anyway, as a linear scrollbar
| will be useless for almost all documents for anything except
| returning to the top.
|
| Rendering the _content_ , however, to a canvas is not
| particularly _necessary_ : make a 4 million pixel square area,
| hide its scrollbars, render the outermost million pixels of all
| edges at their edge, and where you're anywhere in the middle
| (e.g. 1.7 billion rows in), render starting at 2 million
| pixels, and if the user scrolls a million pixels in any
| direction, recentre (potentially disrupting scrolling inertia,
| but that's about it). That's basically perfect, allowing native
| rendering and scrolling interaction, meaning better behaviour
| and lower latency.
| echelon wrote:
| > came across a toot
|
| > For the sake of my aching skullmeats
|
| > My skullmeats did not thank me for this
|
| > I hear you asking.
|
| > Maybe if I give my whimpering neurons a rest
|
| > I'd be much happier if someone just explained it to me; bonus
| points if their name is Clarissa.
|
| > my gray matter needs a rest and possibly a pressure washing
|
| There is a software engineering equivalent of the "theater kids"
| meme, and this is it. There's an abundance of exuberance in this
| writing.
|
| I'm glad we have such diversity in perspective. It's a nice
| change from the usual terseness, though I'm not sure I could read
| in this style for an extended period.
| baggy_trough wrote:
| "skullmeats" definitely made me wince.
| nine_k wrote:
| The interaural nerve node.
| allears wrote:
| Totally refreshing to me. Imagine -- a techie who doesn't take
| himself too seriously!
| Pxtl wrote:
| It works for this context, which is about an experiment that is
| fundamentally a bit silly. 10 years ago this would've been all
| memes, and 20 years ago it would've been performatively
| elaborate insults. I'll definitely take it over those.
|
| btw "toot" is the de-facto standard jargon for "post" on
| Mastodon-based social media, so that sentence isn't actually an
| example of this silliness.
| calibas wrote:
| What's the actual use case for "infinity" in CSS?
| jdauriemma wrote:
| Final boss of z-index
| Rendello wrote:
| What about `infinity + 1`? ;)
| dole wrote:
| z-index = i_love_you;
| mceachen wrote:
| pow(infinity, infinity) is aliased to no_i_love_you_more
| in CSS5
| elteto wrote:
| That's the z-index of your nose.
| PaulDavisThe1st wrote:
| Cantor has entered the chat.
| azangru wrote:
| Isn't the final boss of z-index the top layer?
| adamwathan wrote:
| We use it in Tailwind CSS v4 for pill-shaped borders:
| .rounded-full { border-radius: calc(1px * infinity);
| }
|
| ...as opposed to what everyone has done historically, which is
| pick some arbitrary huge value like: .rounded-
| full { border-radius: 9999px; }
|
| No real practical benefit, just satisfyingly more "correct".
| szatkus wrote:
| According to the spec:
|
| These constants are defined mostly to make serialization of
| infinite/NaN values simpler and more obvious, but can be used
| to indicate a "largest possible value", since an infinite value
| gets clamped to the allowed range. It's rare for this to be
| reasonable, but when it is, using infinity is clearer in its
| intent than just putting an enormous number in one's
| stylesheet.
| stronglikedan wrote:
| Selling pixels at a dollar each to make an Infinity Dollar
| Website(tm).
| chrismorgan wrote:
| Firefox simply ignores height declarations that resolve to a
| value greater than exactly 17895697px. What's this value? Just a
| smidgeon under 230 _sixtieths of a pixel_ , which is Firefox's
| layout unit. (It's the last integer before 230 sixtieths, which
| is 17,895,697.06 pixels, 4/60 more.) I presume Firefox is using a
| 32-bit signed integer, and reserving another bit for something
| else, maybe overflow control.
|
| Five years ago, Firefox would ignore any CSS declarations
| resolving like that, but somewhere along the way it changed so
| that most things now clamp instead, matching WebKit-heritage
| behaviour. But height is not acting like that, to my surprise (I
| though it was).
|
| WebKit-heritage browsers use a 1/64 pixel layout unit instead.
| Viewed in that light, the 225 - 1 pixels is actually 231 - 1
| layout units, a less-surprising number.
|
| IE had the same behaviour as Firefox used to, but with a much
| lower limit, 10,737,418.23 pixels (230 - 1 hundredth pixels),
| which was low enough to realistically cause problems for
| Fastmail, all you needed was about 200,000 messages in a mailbox.
| I've written about that more a few times,
| https://news.ycombinator.com/item?id=42347382,
| https://news.ycombinator.com/item?id=34299569,
| https://news.ycombinator.com/item?id=32010160.
| AndriyKunitsyn wrote:
| Firefox's units are quite smart, actually. 60 is divisible by
| 3, 4, 5 and 6, so they are quite future-proof for the future
| when we'll have the displays with devicePixelRatio = 6.
| samweinig wrote:
| For those curious, in WebKit, this stems from the use of the
| LayoutUnit
| (https://github.com/WebKit/webkit/blob/main/Source/WebCore/pl...)
| for most computed length values. LayoutUnits use a fixed point
| representation where the smallest unit is 1/64 of a pixel.
| https://trac.webkit.org/wiki/LayoutUnit is a bit old, but has
| some good information on the topic.
| ethan_smith wrote:
| This 2^25-1 pixel limit makes perfect sense - with 1/64 pixel
| precision, that's exactly 2^31-1 layout units (the max value of
| a signed 32-bit integer).
| aarestad wrote:
| Is the almost-24-bit limit related to the fact that 32-bit floats
| have 24 bits of significand? (cf.
| https://en.wikipedia.org/wiki/Single-precision_floating-poin...)
| chriseing wrote:
| The correct answer. In particular, up to 2 ^ 24 the float32
| behaves like a regular integer, which can be important in some
| cases. Above that value, the integer starts to have missing
| values, and strange int behavior such as (n+1)+1 not equal to
| (n+2)
| yosefk wrote:
| But why are 32b floats relevant? JS, the language famously
| representing ints as floats, uses 64b floats. Who puts ints
| into 32b floats and cares about precision loss?
| matthewmacleod wrote:
| Layout engines are not implemented in Javascript.
| bobmcnamara wrote:
| Plenty of embedded GPUs do coordinates that way. But I
| doubt they're running browsers.
| chriseing wrote:
| I didn't say JavaScript anywhere in my comment. No relation
| to JavaScript. Rendering is typically done in tiles, in
| GPU, and the best precision that can be used across all
| GPUs is float32. Some GPUs don't implement float64.
| AnotherGoodName wrote:
| But it's specifically 25bits not 24?
|
| As in n+1 == n once you go past 2^24 on a float and here they
| are at 2^25-1. So it doesn't quite make sense as a reason to
| me.
|
| There's a post above that browsers divide pixels into 1/64th of
| a unit which accounts for 6bits which puts this limit at
| precisely that of a signed 32bit integer. This makes much much
| more sense than the significand of a float.
| chrismorgan wrote:
| No. Everyone has always used fixed-point numbers for layout,
| see my comment for further details.
|
| Now _SVG_ ... try defining a view box up where float precision
| drops, and interesting things happen.
| echoangle wrote:
| > Chrome and Safari both get very close to 225-1 (33,554,431),
| with Safari backing off from that by just 3 pixels, and Firefox
| by 31.
|
| Typo, the last browser in this sentence should be "Chrome",
| right?
| r0b05 wrote:
| This website is pure art. I enjoyed visiting.
| omnicognate wrote:
| As befits the author of CSS: The Definitive Guide.
| gregsadetsky wrote:
| As noted by another comment here [0], when you use a virtual
| DOM/canvas based "infinite" data grid such as Glide Data Grid [1]
| or TanStack Virtual [2], you get the performance/usability of
| native scrollbars because under the hood, both of those libraries
| create scrollable DIVs with a very large height. ie, you're
| scrolling a big empty div, and a viewport into the "infinite"
| grid is actually drawn in the canvas.
|
| But this does fall apart for very very large grids, as you get
| close to the height limit described in this article.
|
| For a project that I'm working on, I ended up re-implementing
| scrollbars, but it's super janky - and even more so on mobile
| where you lose the "flick"/inertia/momentum touch gestures (or
| you have to re-implement them at your peril).
|
| Are there any good tricks/libraries to tackle this? Thanks!
|
| [0] https://news.ycombinator.com/item?id=44825028
|
| [1] https://github.com/glideapps/glide-data-grid
|
| [2] https://tanstack.com/virtual/latest
| moritzwarhier wrote:
| Since it seems unlikely that a single scroll gesture passes the
| threshold, and also the scrollbar thumb probably is invisible
| (either intentionally or due to the extreme height): maybe an
| "infinite scroll" paginated stack of virtual lists would be
| enough? I mean a dumb "load more" implementation that swaps out
| the main container once you reach the end/start of each "item"
| (virtual lists themselves)?
|
| If that doesn't help, maybe check out this fun post (no native
| scrolling experience):
|
| https://everyuuid.com
|
| https://eieio.games/blog/writing-down-every-uuid/
| gregsadetsky wrote:
| great point re: Nolen's site -- I've collab'ed with him on
| https://eieio.games/blog/talk-paper-scissors/, I should have
| remembered that! :-)
|
| it's not crazy to stack virtual lists... at that point, I
| might also just see that the user is near/at the end of the
| list, and just swap out the content completely and place them
| back at scrolling position y:0 or something
|
| for sure, I shouldn't make perfect the enemy of good here.
| thanks for the ideas!
| moritzwarhier wrote:
| Oh, I'm glad i wasn't talking past you :) that uuud site
| and the post about it was genius, and haha, I didn't check
| the RPS-via-phone number app yet.
|
| Sounds equally fun! Just like the uuid one, also seems very
| worth bookmarking for a fitting moment
| fnordpiglet wrote:
| So only slightly related Netscape used to assume the layout
| during load was infinite and would resolve features to their size
| as the sizes are known, which meant usually nothing showed until
| everything was loaded in a world of div and tables.
|
| IE4 did the opposite and assumed everything was sized zero and
| filled sizes as they become known. this allowed them to load
| objects and render them as the page objects load appearing to be
| substantially faster at loading than Netscape.
|
| Early engineering decisions like this can make or break a
| company. Not saying this was the only challenge Netscape had, but
| it was one that really drove the need to build the Gecko layout
| engine. Despite some wildly misleading yet famous blogs written
| by a Microsoft engineer discussing what happened internally at
| Netscape that he couldn't possibly know about and basically got
| totally upside down and self serving ......
| waynecochran wrote:
| if there was a period of time where 24-bit values were in vogue,
| I must have missed it.
|
| The mantissa in a single precision IEEE float is 23 bits. Count
| the hidden bit for normalized floats and you have 24 bits.
___________________________________________________________________
(page generated 2025-08-07 23:00 UTC)