CSS snag of the day: images in tables with max-width set, not displaying properly in Firefox

When did Firefox become such a steaming pile?

OK, that’s not how I intended to start this. Just kinda had to get it out there. Anyway, a client brought an unusual bug with their website to my attention today.

Since embracing responsive web design last year, I’ve become quite fond of using this little bit of code to make images resize dynamically to fit their containers:

img {
  height: auto;
  max-width: 100%;
  width: auto;
}

Most of the time this little bit of CSS works magic. But in this particular case, it did not. The client has put together a table on a page to present a set of photos of board members. In most browsers, the table looks great and is fluidly scaling down the images. But in Firefox, we found it was clumsily overflowing its borders, rendering the images at their full sizes.

After working my way through a few surprisingly unhelpful posts on Stack Overflow, I found my way to this, which seemed to hold an only-too-simple answer:

table {
  table-layout: fixed;
}

I don’t know about you, but I never use table-layout. I’ve come to realize there’s a whole realm of CSS that I just basically never touch, because it’s (usually) completely unnecessary to the way I build pages. But every once in a while, these things come in handy. Turns out, table-layout: fixed was exactly what I needed to — BOOM! — fix the problem with the too-large table images in Firefox.

And, suddenly, CSS was magic again.

My (just-discovered) workaround to the WebKit letter-spacing bug

Update (5/29/2012): Upon working further with the project that formed the basis of this post, I discovered that my solution did not work, or at least, no longer worked. It’s not uncommon as I get deeper into a project with a large CSS file that there are subtle, inadvertent effects of the various CSS properties that get added along the way. Looking back now, I can’t determine for sure whether my solution did once work with the simpler version of the site, and something else I added later counteracted it, or if I was just too eager about a solution to realize it never quite worked in the first place. As a result, I had considered deleting this post entirely, but I have decided to leave it live, to further the discussion of the topic, or at the very least to serve as a monument to my challenges.

WebKit, the rendering engine “under the hood” in both Safari and Chrome, has a known issue handling the CSS letter-spacing property at certain small increments, and at certain font sizes.

Specifically, if defining letter-spacing in increments smaller than 1px or 0.1em, it seems to just ignore the property altogether… except at larger-than-default sizes.

I typically use em or % these days to define text sizes in CSS. So in my situation, I’ve found that my letter-spacing: 0.05em works if I also specify font-size: 125% (or larger), but if I have font-size set to 100% or less, the letter-spacing gets ignored.

Typically, after loading reset.css, I set a baseline font size for the document with body { font-size: 100%; } (or some size… actually it’s usually 80% but these days I’ve been leaning towards larger type).

I decided to play around with this a bit to see if I could resolve the letter-spacing issue, and I found a nice, easy solution that works at least for the particular site I’m currently testing it on. Your experience may vary, depending on how your HTML is structured and how complex your design is.

Here’s the solution:

body {
  font-size: 125%;
  letter-spacing: 0.05em;
  line-height: 1.3em;
}

body>* {
  font-size: 85%;
  line-height: 1.3em;
}

You may want to adjust the exact values of font-size to suit your needs. (And, yes, I’m aware that mathematically 125% and 85% don’t cancel each other out, but they’re close enough for my purposes.) It’s important to include the line-height property in body>* to define your target line height; otherwise your lines will be too far apart. Set it to whatever your ideal value is. (I usually prefer line-height: 1.5em personally, but for larger type, as on the site I’m currently working on, it gets too spaced-out.)

So what’s going on here? Well, strangely, it seems WebKit can actually render smaller type with line-spacing less than 1px or 0.1em just fine, but it won’t unless somewhere in the “cascade” the type has been defined as being a certain amount larger than 100%. I don’t get it, but until the bug (which it seems clearly to be after all of this) gets fixed, at least this seems to be a reasonably clean workaround.

It’s very important that you use body>* and not just body *. If you don’t know why, well… try it out and see. (The upshot: we’re applying a uniform scaling-down across the board on all elements directly under body, which is practically the same as just defining our target font size directly on body itself, but with the benefit of working around the letter-spacing bug.)

Note: I have only tested this using em as the unit of measure for letter-spacing. I’m aware of the issue with px as well, but I’m not sure this solution will work for that. But… really… just use em instead!

The :first-child conundrum

I like to think I’m a pretty adept CSS developer. I may not have written the book, but I have a solid understanding of CSS and can do some sophisticated things with it.

But one place I always get snagged with CSS is in using the :first-child pseudoclass. The idea behind :first-child is that you can apply different styles to the first child element inside a parent element than for the rest of the instances of that child element inside the same parent.

A way I end up wanting to use it a lot is to give the first child different margins than the rest. Maybe most of them need margin-top: 2em; for instance, but I want the first one to be flush to the top of the parent by using margin-top: 0; to override the default margin.

The full CSS might end up looking like this:

div>h2 { margin-top: 2em; }
div>h2:first-child { margin-top: 0; }

And then that would be put together with some HTML like this:

<div id="content">

<h2>First header</h2>
<p>This is the first paragraph!</p>

<h2>Second header</h2>
<p>And, surprise! This is the second paragraph!</p>

</div>

So far, so good. The problem is, what if you stick something else into the <div> before the first <h2> that isn’t another <h2>? Say, something like this:

<div id="content">

<div class="floating_sidebar">This should be floating to
the right of the content.</div>

<h2>First header</h2>
<p>This is the first paragraph!</p>

<h2>Second header</h2>
<p>And, surprise! This is the second paragraph!</p>

</div>

You may have guessed at this point that I’m not describing a hypothetical situation here. This is a stripped-down version of exactly what I’m building right now. The problem is, now the first <h2> is no longer the first child element of the parent <div> overall, so the :first-child CSS gets ignored.

True, it’s not the first child element, altogether, inside the parent. But it is the first <h2> child inside the parent. I can understand how, in other circumstances — say, if the inserted <div> wasn’t a float — you’d want the h2:first-child not to apply here. But in general it seems to me that if you’re specifying a tag with your :first-child, it should only matter that it’s the first tag of that type under the parent, even if there are other different tags before it.

I guess the real solution here would be to create another pseudo-class that does what I want. Now I just need to convince the standards folks and the browser makers to do that.

Note: The sample HTML was kind of a mess when I originally posted this. That’s what happens when you write a blog post in a hurry before rushing out the door for a meeting. It has now been corrected, and I made some other edits for clarity while I was at it.

Google: anatomy of a (half-assed) web redesign

There are many things Google is good at. Internet search and targeted advertising clearly being the top two. I use and appreciate several of Google’s products, especially Gmail, Google Reader and Chrome. But I only use Gmail as a reliable email provider with great spam filtering; I hate the web interface, and check my mail using the native mail clients on my Mac and iPhone. I use Google Reader solely to manage my subscriptions, whereas I actually read my RSS feeds, on all of my devices, with Reeder. And the only times I fire up Chrome are when I need to use Flash, per John Gruber. In general, I like Google’s products for the power of their underlying technologies, just as I hate them for their miserable user interfaces.

I think there are very few people who would consider design to be one of Google’s strong suits, from their traditionally un-designed home page, to their hideous logo (which, nonetheless, went through several apparently well-, or at least extensively-, considered revisions), to the notorious case where, engineers to the core, they logically weighed the relative merits of 41 shades of blue.

If you actually use any of Google’s websites directly, you’ve surely noticed in the last 24 hours that there has been a redesign. The most distinctive feature is the jarring black bar now at the top of all (well, most) pages. Personally I’d prefer something a little more subtle, but it’s tolerable, and presumably achieves its goal of getting your attention by being the only solid black area on your computer screen.

What really bothers me about this redesign is the lack of internal consistency as you dig deeper. To wit, let’s have a look at the landing pages of Google’s three biggest search tools (as determined by their placement in the black bar): Web, Images and Search:

The main things I notice about the main Google (Web) search page compared to the previous version are that the logo is slightly smaller (and appears to have been refined in terms of the extent of 1997-era Photoshop effects applied to it, although I think that change happened a few months ago), and that the “Google Search” and “I’m Feeling Lucky” buttons have been redesigned. They have very slightly rounded corners, an extremely subtle off-white gradient, and are set in dark gray Arial bold 11-point (or so) type.

On Google Images, the logo appears to be basically the same (although perhaps a bit more dithered), but it is much higher on the page. The search box itself is darker and has a drop shadow. The “Search Images” button is larger, has sharp corners and a more intense gradient, and is set in black Arial, larger and normal weight. If I’m not mistaken, this is how the buttons on most Google sites looked prior to yesterday’s redesign, so this appears mainly to be a case of Google Images not keeping up with the changes happening elsewhere.

The page is also cluttered up with instructions and a rather arbitrary set of four sample images. I never bothered to read that text or figure out why the images were there until just now as I was writing this article. Being able to perform a visual search by dragging a sample image into the search box is a really cool idea, but anecdotally I would suggest Google has a daunting challenge in educating users about it, if making it the only thing on the page besides the search box itself still doesn’t get the user’s (i.e. my) attention. Maybe their insistence on using undifferentiated plain text (while it might make Jakob Nielsen proud) for everything is part of the problem.

Google Videos is really the odd man out. A smaller logo, set too far down on the page, and a bright blue search button with no text, just a magnifying glass icon, that would look more at home on a Windows XP start screen than on a Google page. (Astute observers will also note from these screenshots that Google Videos, unlike Google Images and Google Web, displays a glowing focus state on the search box, which is due to the lack of :focus { outline: none; } on the CSS for that element.)

I realize this blue button is more of the direction Google’s heading and I do like it visually, even if I don’t think the search button needs to be so prominent on a page that contains very little else. But the thing that bothers me is the overall inconsistency between these tools.

Consistency is a big buzzword for me. To me it is absolutely the most important thing to consider in good UX and UI design. It doesn’t matter how novel your design elements are; if you present them consistently users will quickly learn how to use them and will gain confidence with your tools. They will also gain expectations that you then have to manage. These do impose limitations on you in the future, sure, but they also relieve you of the burden of having to reinvent every page.

Consistency demands a good style guide, something that is easy to overlook. And just as important as having the style guide is having the commitment to using it. That’s something even a company as big as Google clearly struggles with.

Fun with CSS in WordPress

I just had an email exchange with an old friend and fellow web developer (and WordPress user) regarding some techniques for CSS trickery on home pages in WordPress themes. Up until this week, I had been running a version of my theme that just featured brief excerpts of articles on the home page. I was doing this by brute force in PHP, truncating the post text with the substr() function, and then cleaning things up using the strip_tags() function, which removes all HTML tags from a string.

It got the job done, but as he and I were discussing, it wasn’t pretty: it stripped out the “dangerous” stuff — that is, unclosed HTML tags (cut off during truncation) that would have screwed up the formatting of the rest of the page. But it also stripped out desirable styling (bold, italics, links) and paragraph breaks.

The ideal situation would be to have a way to show just the first two paragraphs of each post, retaining all of their original formatting. Of course, WordPress has a feature to handle this: if you put a <!--more--> comment tag in your post, your page template can truncate the post at that point, with a link to the single-post page to display the rest of the content. But I’ve never liked having to put that <!--more--> into my posts. I want a completely automated solution.

And then it hit me… this could be done with CSS. It took a little trial and error, but I came up with the following:

#content .entry p,
#content .entry h3
{
display: none;
}

#content .entry h2:first-child,
#content .entry h2:first-child + p,
#content .entry h2:first-child + p + p
{
display: block;
}

A few things to note:

  • This assumes that your entire loop is wrapped inside <div id="content">...</div>. You may need to come up with a specific ID to use just for this block in your index page, and be sure not to use that in your single-post page, or your posts will never appear in their entirety.
  • This also assumes that you’re using the WordPress convention of wrapping your posts in a pair of <div> tags with the attributes class="post" and class="entry" (though technically, class="entry" is the only one that matters here).
  • Your post title should be in an <h2> tag, immediately following <div class="entry">.
  • The first definition may need to be extended to include other HTML tags you want to hide on your index page. In this example, it’s only hiding content that is inside <p> or <h3> tags.
  • If you want to hide every HTML tag except the ones you explicitly specify, you could change the first block to #content .entry *, but keep in mind that will also remove styling like bold and italics, and it will remove links. Probably not what you want.

The specifics may vary depending upon how your WordPress theme is set up; I just know that with the way mine is set up, which pretty closely follows standard convention, this CSS worked to get the index page to list the posts and only show the first two paragraphs of each. (It also retained the images that I embed at the start of each post, and also retains any embedded video from YouTube or Vimeo, since — at least the way I insert them — those are not wrapped in <p> tags.

Note that all of the HTML content for each post is still loaded by the browser — we’re just using CSS to tell the browser not to show it on the page. This is not going to help with performance; it’s strictly aesthetic.