Tinier is a pretty cool font. It is a so called pixel font, and it is just about the smallest font I could find. The letters can be displayed at a font-size of 4px. This means that each character is only 3 pixels tall.

The wizard quickly jinxed the gnomes before they vaporized.

The wizard quickly jinxed the gnomes before they vaporized.

I think this is pretty cool, so I tried to implement this on my website for the footer blurb. It turns out though, that pixel fonts look absolutely hideous in modern browsers. Here is how it looked: Font sample Font sample

Do you see these hideous colored pixels? It ruins the pixel font. The footer was originally white on blue, where the problem was even worse: Font sample Font sample

How it should look: Font sample Font sample Nice, clean, black on white Pixels.

As with any modern software, browser employ font smoothing. This is done so text looks good on a low DPI screen. It is done with antialiasing and subpixel rendering and for normal fonts this is pretty great, but for pixel fonts it looks terrible. There is no way for a font to disable it, so it usually has to be done at a software level. Some browsers have a setting for disabling font smoothing. This is obviously pretty useless, since I can't expect readers of my blog to have turned this off and made all normal fonts look bad except my tiny blurb.

There must be a CSS setting right?

Well, let me tell you about font-smooth. It was present in early drafts of CSS3, but has been removed from the specification since. It only works on some browsers and only on the Mac OSX operating system. So it looks like there is no easy way to implement a pixel font without ugly rendering artifacts.

But why don't you just use an image?

Yes, I could just write my text in GIMP and upload it as a picture. But I want it to be dynamically generatable. I want to do it in good old HTML and CSS.

So I have decided to go the spritemap route instead

Font sample Having it as a spritemap has many advantages including (and probably limited to):

  • You can still wrap text around newlines
  • You only have to have one image for any size and length of text.
  • Because the original characters are still in the HTML you can select and copy it

Here is how the HTML of a very short text looks:

<span class="charfont-tinier"><span class="charfontO">O</span><span class="charfontL">l</span><span class="charfontI">i</span></span>

As you can see every letter is just a <span> with a special class and the original letter inside it. And since this is a Jekyll blog, I wrote a short ruby plugin to achieve this, but it would probably work really well in JavaScript as well.

module Jekyll
    class Charfont < Liquid::Tag
        def initialize(tag_name, text, tokens)
            super
            html = "<span class=\"charfont-tinier\">"
            text.upcase.split("").each do |i|
                if i == " "
                    classname="SP"
                elsif i == "."
                    classname="dot"
                else
                    classname=i
                end
                html = html + "<span class=\"charfont"+classname+"\" >" + i + "</span>"
            end
            html = html + "</span>"
            @output=html
        end
        def render(context)
            @output
        end
    end
end
Liquid::Template.register_tag('charfont', Jekyll::Charfont)

And here is the accompanying CSS:

.charfont-tinier span {
    color: transparent;
    background-image: url("../media/images/tinier.png");
    margin-left: calc(1px * var(--scale));
    display: inline-block;
    background-size: calc(5px * var(--scale));
    width: calc(3px * var(--scale));
    height: calc(4px * var(--scale));
    overflow: hidden;
    background-repeat: no-repeat;
    image-rendering: optimizeSpeed;
    image-rendering: -moz-crisp-edges;
    image-rendering: -o-crisp-edges;
    image-rendering: -webkit-optimize-contrast;
    image-rendering: pixelated;
    image-rendering: optimize-contrast;
    -ms-interpolation-mode: nearest-neighbor
}
.charfont-tinier{
--scale:1;
}
.charfont-big .charfont-tinier{
--scale:5;
}
.charfont-tinier .charfontA {
    background-position: 0px calc(-0px * var(--scale));
}

.charfont-tinier .charfontB {
    background-position: 0px calc(-4px * var(--scale));
}

.charfont-tinier .charfontC {
    background-position: 0px calc(-8px * var(--scale));
}

You can look at the whole CSS file here.

So, this is a very complicated solution to a problem that really should be as simple as font-smooth. And it still isn't prefect. Having it do proper line-wrapping would require a bit more complicated HTML and CSS. Also the image-rendering part doesn't work on all browsers, so when text size is large it would look like this: Font sample

Edit:

Since writing this post Chrome has made some changes. It now enforces a minimum font-size of 6px. Therefore my previous method of using em and font-size=1px no longer works. I've updated the code in this post to use a css variable to define scale. This way I can still enlarge the font with css.