Technology

CSS subpixel rendering

Posted by Pixafy Team | Monday, May 13, 2013

CSS Subpixel Rendering  |   www.pixafy.com

Working on a responsive site a little while ago, I was running into a very strange problem where elements were refusing to line up.

I had a list of menu links (<a> tags wrapped in <li>’s) and above them I had <h3> tags labeling each section. All the widths I was using are % based. The <h3> tags were 100% of the wrapper, the <li>’s the same (and their wrapping <ul>’s), and the <a> tags were 90% width with 5% padding on the sides (90%+5%+5% = 100%) width <span>’s wrapping the inner text.

And yet somehow the <h3>’s were appearing a tiny bit longer than the <a> tags when testing on mobile! In fact they were exactly 0.5px off. That is really odd and I knew it had to do something with subpixel rendering:

CSS-Sub-Pixel-Rendering_1

If you don’t know what subpixel rendering is, do a quick Google search and you will likely come up with most of the same results I did when trying to combat this latest responsive design pitfall. There are a lot of articles and blog posts that describe how great subpixel rendering is, and even older ones that were waiting in anticipation for every browser to support the feature. CSS subpixel rendering occurs when you have CSS values that result in decimal or partial pixel values. This is usually the result of using percentage based layouts.

An example would be having a containing <div> with a width of 555px and four child elements with a width of 25%. That means each child element is 138.75px when rendered. So how do browsers (and your monitor) interpret the extra 0.75 pixels? In older browsers everyone had their own way of doing it. IE would round everything up, Safari would round down, and Firefox would try to do a “best guess” width, with some rounding up and others rounding down.

But wait! The top search results are mostly out-of-date because this feature has been out for quite a while! Modern browsers like Chrome and iOS Safari (the browsers I was testing on) are supposed to have resolved this issue. Most of the time.

There were still a few edge cases in which it seemed my problem fell. Through my searches, I read many explanations, but there weren’t any explanations for the exact problem and how to fix it. This post is in response to that lack of information so that hopefully, anyone with the same problem as I can see my fix. I did come across the background color issue with percentages, but if my issue was only that, the <a> and <h3> would both be half a pixel off, allowing them to line up.

Back to the problem at hand.

So how could items that should be the same length be half a pixel off? Well first, I should show you a basic version of the HTML and CSS that I had:

This HTML was coming from Joomla (version 1.5) so changing it was not an option. That narrows down the approaches I could use to fix it. My first approach was to increase the wrapper width from 96% to 98% in the hopes that it would be that quick of a fix. My hope was dashed quickly, but what I did notice is that the issue sometimes went away depending on the page width.

For example, on our iPhone 4, the half pixel difference was clear as day in portrait mode, but it was gone in landscape. So the issue did depend upon the wrapper width. It seemed the calculations on the <a> tag and the <h3> were “usually” the same.

CSS-Sub-Pixel-Rendering_2

It was at this point that my issues reminded me of an old IE7 padding bug. To test my new theory, I removed the padding from the <a> tag and made it 100%. Suddenly in portrait mode, everything lined up! Awesome, except for the fact that I needed the padding, otherwise the text would be right at the edge. So I moved the padding to the <span>’s inside my <a> tags. I also made the <span>’s display: block and I did not put any width on them at all.

And eureka! The edges line up no matter how wide or narrow the page width!

So if you happen across an issue like this, give these solutions a try:

1)      Change/clean up your HTML. 95% of the time, this will solve the issue.

2)      Make sure you are using an up-to-date normalize.css or CSS reset file. Also make sure there are no issues with inherited styles.

3)      If it’s still not fixed, make your layout styling match on your elements.

4)      When everything lines up, add your padding back in for the elements that were off. Best bet to add it to a child element.

Thanks, and I hope this helps someone else out!

Leave us a comment with your thoughts and questions!