pre-posterous Mobile Browsers

I was alerted to the fact that code on my home page looked teensy-tiny on Android. What could be wrong? It was just enclosed in pre tags. Preposterously, and probably for prehistoric reasons, mobile browsers apply weird rules to preformatted code instead of just following CSS styles. It took me foreever to find the magic pixie dust, so I wrote it up so that the search- and chatbots can find it.

My home page has a sequence of code snippets that shows the evolution of number formatting through the ages. Each snippet is simply enclosed in <pre>...</pre>. What could possibly go wrong?

You can no longer see the effect on my home page because I fixed it, as explained below. But check out this test page on your mobile device.

Here is how it looks like with Chrome on Android (click to magnify):

.png

Firefox on Android displays the test page in essentially the same way.

Search Frustration

I tried searching for “tiny pre font android”, and to my surprise it was slim pickings.

I asked ChatGPT: “When viewing a web page on my Android phone, code in pre tags comes out tiny. How should one fix the web page so that the code has the same size as the surrounding text?” Its answer:

One way to fix the issue with the code in pre tags appearing tiny on an Android phone is to apply CSS styling to the pre tag. Here is an example CSS rule that can be added to the page's CSS file:

pre {
   font-size: inherit;
   line-height: 1.5em;
   white-space: pre-wrap;
}

I should have tried the chatbot first instead of using a search engine! I asked a followup question: “Why does this work? white-space should have nothing to do with font size!” The reply:

You are correct that the white-space property is not directly related to font size. However, in this case, setting the white-space property to pre-wrap actually helps to prevent the code from overflowing the container and causing it to appear smaller.

By default, the white-space property of the pre tag is set to pre, which means that whitespace in the code will be preserved and the text will not wrap. This can cause the code to overflow the container if it is too wide, which can make it appear smaller and harder to read.

Setting the white-space property to pre-wrap allows the text to wrap when it reaches the end of the container, which helps to prevent the code from overflowing and appearing smaller. This property also preserves the formatting of the code, so the indentation and line breaks will be maintained.

This is a weird argument. Why is overflowing code smaller and harder to read when it doesn't wrap?

Anyway, the solution works. Fortunately, wrapping is only a visual feature. When you copy the code from the page, there are no added line breaks.

You can also set white-space to break-spaces, which is almost the same, but it wraps trailing spaces. I don't think that's useful.

I don't love giving up the overflow behavior for pre. I prefer for readers to scroll instead of pondering whether something got wrapped.

But Why?

I used the Firefox Remote Debugging tool to inspect the font size of the pre areas. Here are the reports:

Style Reported font size
None 12px
white-space: pre-wrap 12px
white-space: break-spaces 12px
white-space: pre 12px
font-family: monospace, monospace 16px
font-size: 1em 1em

What are the dev tools smoking? The first four code blocks do not all have the same size!

My guess is that there are two unrelated issues. First, many monospace fonts have a taller x-height than text fonts. Since the mist of time, browsers use different font sizes for text and monospace fonts. On desktop browsers, the user can override the browser defaults. Since they can't do that on mobile browsers, your best bet is to use matching custom fonts for text and code. Or use the monospace, monospace hack and hope for the best.

The tiny pre is a separate, and more frustrating problem. I can't begin to understand why anyone ever thought it was a good idea to render pre content at about 50% of the text size on mobile browsers. But someone must have had a reason for it. And apparently the behavior is kept for compatibility unless the browser sees some sign of modernity. Such as the viewport meta tag or the white-space CSS property.

Finally, I ran into Rahul Chhodde's article Improving mobile design with the latest CSS viewport units, which casually suggested to use:

body { font-size: 3vmax }

I tried that (with 2vmax) in this document. On the desktop, the page scales when you resize the window. (This is often called “fluid typography”.) On mobile, you get a reasonable font size in portrait and landscape orientation. Without using pre-wrap, the pre elements are a little smaller than they should be according to the CSS, but they are readable. I have no explanation for this.

Conclusion

  1. Even in 2023, browsers do weird things when rendering the most basic HTML content.
  2. If you use a content management system or someone else's style sheet, your preformatted code probably looks fine because someone else has figured out the magic pixie dust. Just verify it on your mobile device.
  3. If you sling your own HTML and CSS, you don't want pre contents to be teensy tiny on mobile browsers. Set the white-space CSS property if you are ok with wrapping. Consider the viewport meta tag. Or try fluid typography.

Comments powered by Talkyard.