Search code examples

Is there a way around Safari's min-font size?



<div>This is 20px text</div>
<div class="shrunk">This should appear as 4px size text (20px * .2)</div> 


div {
  font-size: 20px;
  margin: 20px;

div.shrunk {
  zoom: .2;

The JSBIN example renders two divs. Text is set to 20px. The second div, however, has a zoom: .2 set on it.

If you open these side-by-side in Safari and Chrome you will see that zoomed text in Safari is bigger. If you play with the zoom setting in Safari, you will see that there is something acting as a min-font-size setting where you simply can't shrink the text down any smaller.

Anyone know why Safari does this? And is there a way to over-ride this?

I should note that I do not have the Safari preference setting of 'never render type below size x'.

The issue is that I'm designing a Kiosk that's going to be stuck a a particular aspect ratio. But the browser in use (full screen) may vary in size (unknown variable at this point).

So I'm simply using a little bit of JS to zoom the contents to fit whatever the viewport size may be.

In chrome this means no matter what size I set my browser, everything on screen scales as a whole and nothing breaks (outside of it just being too small to read/see).

But in Safari, it breaks pretty quickly as you shrink things down due to this weird font issue.

I'm guessing this is just how Safari is, and I can probably get around this with some more thoughtful design/layout changes. But I am curious as to what Safari is doing here if it's a known thing.

UPDATE: I was pointed to this answer regarding using -webkit-text-size-adjust: 100%. That may 'fix' the issue in mobile safari but does not work in the desktop.


  • Yes, it appears Safari has a lower limit that prevents text from being affected by zoom at values less than 0.5. We can see this from the rendered result of text at scales 1~0.1:

    <p style="zoom:1.0">text at zoom:1.0</p>
    <p style="zoom:0.9">text at zoom:0.9</p>
    <p style="zoom:0.8">text at zoom:0.8</p>
    <p style="zoom:0.7">text at zoom:0.7</p>
    <p style="zoom:0.6">text at zoom:0.6</p>
    <p style="zoom:0.5">text at zoom:0.5</p>
    <p style="zoom:0.4">text at zoom:0.4</p>
    <p style="zoom:0.3">text at zoom:0.3</p>
    <p style="zoom:0.2">text at zoom:0.2</p>
    <p style="zoom:0.1">text at zoom:0.1</p>

    Here is how that text gets rendered in three Mac desktop browsers:

    Chrome Safari Firefox
    Zoom in Chrome Zoom in Safari (Desktop) Firefox

    Apple almost certainly has chosen to do this for accessibility reasons. Text that is too small to read is a problem that often crops up when designers assume all of their audience's eyesight is as good as their own. Apple is big on accessibility, so I am not surprised to see this limit. I'm not saying I agree with setting a hard limit, as it could be a problem for certain CSS animations, preventing a "fade out" type of scale-down effect, as just one example.

    How to work around this?

    First, the question must be asked: why do you want to have text in your design that is too small to read?

    There are a couple of valid use cases I can think of:

    Use case 1: image-like usage of text

    Your design contains thumbnail images of other designs - for example, you have an ad banner promoting a book. The cover of the book is on the banner. And the cover of the book includes some text that is too small to read, but we still get the gist of it, so that's okay. In such a case, convert the book cover to an image if it isn't already.

    Converting text to SVG or another image format is fine in certain cases. A vector format is generally preferred over a raster one for text. If your text is appearing that small, then it's probably not functioning as normal text. Consider treating it as an image instead.

    Use case 2: text with animated transitions

    The text zoom property is to be animated (as I described above). In this case consider animating other CSS properties, such as transform: scale() translate();

    Just be aware that scale() has the unfortunate side effect of offsetting your element relative to its transform-origin. It can't be helped - that's what scaling does. And translate() often needs to be used in conjunction with scale() to offset the positioning changes.

    <p style="transform: scale(1.5)">text at scale:1.5</p>
    <p style="transform: scale(1.4)">text at scale:1.4</p>
    <p style="transform: scale(1.3)">text at scale:1.3</p>
    <p style="transform: scale(1.2)">text at scale:1.2</p>
    <p style="transform: scale(1.1)">text at scale:1.1</p>
    <p style="transform: scale(1.0)">text at scale:1.0</p>
    <p style="transform: scale(0.9)">text at scale:0.9</p>
    <p style="transform: scale(0.8)">text at scale:0.8</p>
    <p style="transform: scale(0.7)">text at scale:0.7</p>
    <p style="transform: scale(0.6)">text at scale:0.6</p>
    <p style="transform: scale(0.5)">text at scale:0.5</p>
    <p style="transform: scale(0.4)">text at scale:0.4</p>
    <p style="transform: scale(0.3)">text at scale:0.3</p>
    <p style="transform: scale(0.2)">text at scale:0.2</p>
    <p style="transform: scale(0.1)">text at scale:0.1</p>

    Rendered result of transform: scale() - does not vary noticeably between browsers:

    (screenshot is from Safari)

    The effect of the scale() property

    Note that elements with scale values >1.0 are drifting left, while elements with values <1.0 are drifting right. This can be adjusted for using translate(), but is a hassle involving trial and error to get the right values. Even then, there are issues to consider, including how this may impact responsiveness. I'm not necessarily recommending this "hack". It may be alright for small adjustments though.

    I'm going to leave this answer as it is for now. But I may have more ideas if you can describe the purpose and function of this tiny text, and why you believe it will not pose a problem for your audience. Maybe there's a better way to accomplish what you are trying to do.