Marco Carag

Expert er of things.

CSS Transparency and Overlapping Glyphs

Example of overlapping glyphs using CSS rgba()
Example of overlapping glyphs using CSS rgba()

rgba() is a supremely useful CSS value. But I noticed, while working on the footer of this site down below, that operating systems render typography using this value in interesting ways.

About CSS transparency

To start, a quick overview. rgba() is a CSS property value specified in the CSS3 color module that allows one to set in single value the traditional red/green/blue color sub-values, as well as a fourth sub-value for alpha transparency. The syntax is pretty straightforward: rgba(red,green,blue,alpha), where red, green, and blue are specified either as a percentage (0 to 100%) or as a number from 0 to 255, and alpha is specified as a decimal value — “1” translating to 100% opaque, “.5” is 50% transparent, “0” is completely transparent, etc.

The awesomeness of this idea is that with rgba() as a value, it can be applied on any CSS property where color values are accepted, such as color, background-color, text-shadow, what-have-you. The end result is the ability to apply individual levels of transparency to a single CSS selector for different properties — for instance, you can set your background to one transparency, and your text to another. Contrast this with the older opacity CSS property, which applies an alpha transparency value (in the same 0 to 1 decimal scale) to the entire selector — meaning, the selected element and any of its children would all get the same opacity, background, text, and all.

Rendering issues with overlapping glyphs

While tooling around with my footer down below, I noticed rgba() being even more granular than I wanted it to be with regards to typefaces that naturally had overlapping glyphs. I had my footer set to something like this:

  .myFooter {
    font-family: DeftoneStylusRegular;
    color: rgba(255,255,255,.2);
  }
  

Via @font-face, I’m using Ray Larabie’s Deftone Stylus, which is a retro styled script font that’s intentionally kerned so that there’s overlap for the glyph connectors, as are most script fonts. The above CSS would set the text’s color to be white with 20% opacity. And the result looked like this:

Example of overlapping glyphs using CSS rgba()
Example of overlapping glyphs using CSS rgba()

Where the glyphs’ serifs overlap to act as connectors, the opacity is multiplied. I created a simple little test to try to isolate what the issue was:

    <style>
    .test{
      font: bold 5em sans-serif;
      color:(0,0,0,.25);
      letter-spacing: -.2em;
    }
    </style>

    <p class=”test”>This is a test using rgba.</p>
  

This uses the browser’s standard sans-serif typeface, sets it to black at 25% opacity via rgba(), and condenses the glyphs via negative letter-spacing to get overlap. It looks like this in Firefox 3.6 and Chrome 5 in OS X:

OS X screengrab of standard sans-serif font condensed via negative
    letter-spacing and set at 20% opacity via rgba()
OS X screengrab of standard sans-serif font condensed via negative letter-spacing and set at 20% opacity via rgba()

As you can see, it appears as if each character is being targeted for transparency, and when they overlap they are treated as independent layers… in OS X, that is. Take a look at the same in Windows Firefox and Chrome:

Windows screengrab of standard sans-serif font condensed via negative
    letter-spacing and set at 20% opacity via rgba()
Windows screengrab of standard sans-serif font condensed via negative letter-spacing and set at 20% opacity via rgba()

In Windows, in either browser, it looks like it renders all the glyphs as a single vector object before then applying the transparency uniformly on the whole shebang. So my best guess is that browsers use OS-level compositing here, and there are discrepencies between operating systems. Most unfortunate, if you’re aiming for semi-transparent typography that has intentional glyph overlap. However, there’s a way out via opacity:

    <style>
    .test{
      font: bold 5em sans-serif;
      color: #000;
      letter-spacing: -.2em;
      opacity: .25;
    }
    </style>

    <p class=”test”>This is a test using opacity.</p>
  

This should actually look exactly the same as the first example — and that much is true in Windows. However, in OS X:

OS X screengrab of standard sans-serif font condensed via negative
    letter-spacing and set at 20% opacity via opacity
OS X screengrab of standard sans-serif font condensed via negative letter-spacing and set at 20% opacity via opacity

It looks just like Windows does — and actually, it looks the way I had originally intended. And this makes sense, since according to the spec regarding CSS transparency, “…after the element (including its descendants) is rendered into an RGBA offscreen image, the opacity setting specifies how to blend the offscreen rendering into the current composite rendering.“ In otherwords, render the elements at full opacity, and then crank the opacity down post-rendering based on the opacity property value before finally rendering on screen. Conceivably, rgba() is the same thing, only with multiple layers nested across multiple properties — but turns out OS X takes it a step further with text by isolating each glyph.

Check out this test page for the above examples (make sure to view in both Windows and OS X).

Conclusion

Honestly, this shouldn’t make a big difference in the vast majority of situations where traditional sans-serif or serif fonts are in use, as their glyphs don’t usually overlap. But think twice about it if you’re thinking about applying transparency to text set using a font with intentional character overlap — which includes just about all script fonts. Here’s an example of just a few, including Deftone Stylus which I used in my footer — these are at their default kerning, with no forced condensing via letter-spacing:

Demo of fonts with intentional glyph overlap.

If I wanted to apply transparency to text using any of the fonts in the above demo, I’d have to forego rgba() in favor of wrapping the text in its own element, and then targeting that element with opacity, instead. That’s exactly what I ended up doing for my footer, by the way. It means extra DOM elements, but at least it works!

Note about Opera in Windows

In OS X, Opera 10.61 looks much the same as Firefox and Chrome. But in Windows, it has some issues with certain typefaces when transparency is used in any form:

Screengrab of Opera 10.61 in Windows cutting off glyphs on certain fonts
    when transparency is applied

As you can see, it’s cutting off certain glyphs along the vertical. Not sure what the issue is, but I haven’t hunted around much for answers, either, so I’ll update this if I find anything.

Credits

Thanks to the wonderful Font Squirrel and all of its participating typographers, for their wonderful collection of type, and handy @font-face kits!

blog comments powered byDisqus