CSS, <pre>, and trailing whitespace lead to browser layout weirdness

March 12, 2017

Today someone left a comment on this entry of mine about Python which consisted of a block of code. The comment looked normal in my feed reader, but when I looked at it in my browser (for neurotic reasons) I got a surprise; the new comment was forcing my Firefox to display the page really widely, with even regular text out of my viewport. This was very surprising because I theoretically made that impossible years ago, by forcing all <pre> blocks in comments to have a CSS white-space: pre-wrap setting. At first I thought that my CSS had broken at some point, but with Firefox's style debugging tools I could see the actual CSS being applied and it had the proper white-space setting.

More experimentation showed that things were even weirder than it had initially looked. First, the behavior depended on how wide my Firefox window was; if it dropped below the critical width for my responsive design here to show the sidebar as a sidebar, the problem went away. Second, the exact behavior depended on the browser; in Chrome, the overall page gained a horizontal scrollbar but no actual content extended out the right side of the browser's viewport (ie, its visible window area).

(I've fixed how the live version of the page renders, but you can see the original version preserved here. Feel free to play around with your browser's tools to see if you can work out why this is happening, and I'd love to know what other browsers beyond Firefox and Chrome do with it.)

Eventually (and more or less by luck), I stumbled over what was causing this (although I still don't know why). The root cause is that the <pre> block has a huge area of whitespace at the end of almost every line. Although it looks like the widest <pre> line is 76 characters long, all but the last line are actually 135 characters long, padded out with completely ordinary spaces.

The MDN writeup of white-space contains a hint as to why this is happening, when it says that for pre-wrap 'sequences of white space are preserved'. This is what you need in preformatted text for many purposes, but it appears to mean that the really long runs of trailing whitespace in these lines are being treated as single entities that force the content width to be very wide. Firefox doesn't visibly wrap these lines anywhere and has the whitespace forcing the surrounding boxes to be wide, while Chrome merely had it widen the overall page width without expanding the content boxes. My Chrome at the right width will force the longest line or two of the <pre> content to wrap.

My fix for now was to use magic site admin powers to edit the raw comment to trim off the trailing whitespace. In theory one possible CSS-level fix for this is to also set the word-break CSS property to 'break-all' for <pre> elements, which appears to make Firefox willing to break things in the middle of this sort of whitespace. However this also makes Firefox willing to break <pre> elements in the middle of non-whitespace words, which I find both ugly and unreadable. What I really want is a setting for word-break that means 'try not to break words in the middle, but do it if you have to in order to not run over'.

(Maybe in another ten years CSS will have support for that. Yes, there's overflow-wrap for regular text, in theory, but it doesn't seem to do anything here. Possibly this is because Firefox doesn't feel that the large chunk of whitespace is actually overflowing its containing box but instead it's growing the containing box. CSS makes my head hurt.)

Comments on this page:

I ran into this when I was trying to make Slate Star Codex scale. The CSS that worked for me was word-wrap: break-word, which apparently tells the browser to do the right thing (only break words if you have to).

See JSFiddle here for an example: https://jsfiddle.net/cza8ruka/

By Brendan Long at 2017-03-12 14:35:01:

I'm not sure what's up with JSFiddle but this link should work: https://jsfiddle.net/cza8ruka/1/

By Aneurin Price at 2017-03-14 14:42:36:
I've fixed how the live version of the page renders, but you can see the original version preserved here

I think you might have accidentally fixed that version as well? Either that or my Chrome is not displaying the same behaviour.

By cks at 2017-03-14 16:35:33:

The Chrome version is more subtle and I may not have described it well. In Chrome, none of the content escapes out of visible window, but (Linux) Chrome has a horizontal scrollbar that it shouldn't have. If you scroll it right, the only thing in the right side is empty space. In Chrome, the fixed version of the page has no horizontal scrollbar until you get extremely narrow, and even then it's a very short one.

By cks at 2017-03-14 16:48:21:

Belatedly: Brendan Long, word-wrap aka overflow-wrap doesn't seem to work here with this particular example, at least based on trying it in both Firefox and Chrome with their live CSS/Style editing tools. My theory about why is that I'm not setting an explicit width for my content (and my maximum width is quite wide, 60em); instead it's supposed to be implicitly confined to the browser width, except that apparently doesn't force overflow-wrap to break words here.

By Aneurin Price at 2017-03-14 18:14:49:

Ah, I see. I had to make the window very narrow to be able to see it. In this case, I would personally be strongly tempted to use overflow: hidden. It solves this particular case in combination with the white-space: pre-wrap that's already there (not tested in FF), though who knows what other side effects it might have because I just can't seem to internalise the CSS model no matter how hard I try.

By cks at 2017-03-15 01:20:17:

I just gave it a spin and overflow: hidden didn't do anything in Firefox (although as you noted it does make the scrollbar go away in Chrome). I suspect this is for the same reason that overflow-wrap isn't doing anything much, which is that Firefox is expanding the content box and so doesn't consider the <pre> text to 'overflow' it.

I really do like CSS sometimes.

Written on 12 March 2017.
« Your live web server probably has features you don't know about
What should it mean for a system call to time out? »

Page tools: View Source, View Normal, Add Comment.
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Sun Mar 12 01:47:25 2017
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.