Fluid Image Replacement Techniques

While you can find two dozen blog posts and articles about various image replacement techniques using Google, I couldn’t find any article that would help when you want the replacement to be fluid.

If the term “image replacement” is unknown to you, it basically means that we replace some content on a page—usually text—with an image.

I’m not a huge fan of using image replacements in the first place, but it’s often necessary to do so. One quite popular example is a logo. Logos—when used on a Web page—are usually images that have text inside them. If we want that text content to be visible to search engines, screen readers and text based browsers (Elinks, Lynx, …) we need to use some kind of image replacement technique.

The most popular image replacement technique right now is probably this:

HTML:

1
<h1>Header</h1>

CSS:

1
2
3
4
5
6
7
h1 {
  background: url(image.jpg) no-repeat;
  text-indent: -9999px;
  overflow: hidden;
  width: 100px;
  height: 50px;
}

I think that the method described above is good if we just need to replace a logo, but what can we do when we want the replacement to be fluid and scale with the layout? Well, we could add a background-size CSS property which is supported in Firefox, Safari, Chrome, Opera, and IE9+ to make it a bit better:

CSS:

1
2
3
4
5
h1 {
  -webkit-background-size: 100% auto;
  -moz-background-size: 100% auto;
  background-size: 100% auto;
}

Now by changing the width and height of the header between different Media Query trigger points we could change the size of the replacement image. That doesn’t help much though if we want/need the replacement to be completely fluid.

Back to the past

Because of the non-fluid nature of the last example, I’m suggesting an alternative method to “replace” the text, which, I think, is actually the way image replacement was done before all these CSS methods about 10 years ago (…now added with few improvements):

HTML:

1
2
3
<h1>
  <img src="image.jpg" alt="Header">
</h1>

CSS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
h1 img {
  width: 100%;
  height: inherit;
  -ms-interpolation-mode: bicubic;
}

@media print {
  h1 img {
    display: none;
  }
  h1:after {
    content: "Header";
  }
}

This method also hides the image when you print the page and replaces it with the text from the image. This is something that’s really useful if the text inside the image is white as on my own home page. You might also want to add a max-width for the H1 or the IMG to avoid the image scaling too much.

I’m not a SEO expert so I don’t know how this particular technique performs against H1 with real text content, but at least screen readers, text browsers and search engines see the text now (I tested if the ALT description used in this kind of example shows up in Google results by searching for my own site and the words inside ALT description. The text did, in fact, show up there).

Putting more thought into this

I started wondering if it’s possible to automatically get the content of the ALT description for printing, so that we wouldn’t have to write all the texts inside the stylesheet. This is what I came up with:

CSS:

1
2
3
4
5
6
7
8
@media print {
  h1 img {
    display: none;
  }
  h1 img:after {
    content: attr(alt);
  }
}

That should work in all major browsers + now we don’t have to worry so much about our stylesheet anymore.

Usage of an H1 tag

I’d say that you shouldn’t probably wrap a logo inside an H1 tag. The Example uses H1 just because the main header on this site uses an image replacement and this blog post kind of grew up from that particular use case. I’m using image replacement because I wanted to make the header look identical across multiple platforms/devices, also the ones that don’t have support for @font-face.

Further reading

CSS-Tricks has an article about similar method (non-fluid), called Rethinking CSS Image Replacement, but I think that the “remaining problems” described there are incorrect. This method does show the alternative text when someone is browsing CSS turned on and images turned off, Webkit being the only exception. At least this was the case when I tested it.

There are few caveats also: If you are worried about how Internet Explorer (prior to version IE8) and older mobile devices will render the image when it’s scaled down, then I suggest you to read Ethan Marcotte’s article called Fluid images. There’s a small script to fix the problem with Explorer.

At this stage we (and I) should also probably think about how to implement responsive images and not just serve one big image for all screen sizes. Jeremy Keith has an interesting post titled Responsible responsive images about that subject. ❦

ResponsiveSlides.js

I created this plugin while I were developing my own site and decided few days ago to release it as an open source version. Its basic function is to create responsive slideshow using images inside a container. The interesting thing is, that this is actually the very first JavaScript plugin I’ve done and that’s why I thought that I should write down some notes while I’m at it.

Basics first

Let’s start with the Markup and CSS. I used the same markup which I used on blog.kiskolabs.com as the foundation for this plugin, but I wanted to make it a bit better this time. The problem with my previous version was that if there was any content below the slideshow, you had to change the height between Media Query triggerpoints for it to work properly. Now we don’t have to specify/calculate height anymore, so this scales really smoothly.

HTML:

1
2
3
4
5
<div id="slides">
  <img src="1.jpg" alt="" />
  <img src="2.jpg" alt="" />
  <img src="3.jpg" alt="" />
</div>

CSS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#slides {
  position: relative;
  overflow: hidden;
  max-width: 800px;
  width: 100%;
}

img {
  position: absolute;
  height: inherit;
  width: 100%;
  left: 0;
  top: 0;
}

.img_visible {
  position: relative;
  float: left;
}

The markup is really simple: you only need one container and few images inside that. Max-width on the container isn’t necessary, but we might want to prevent images scaling too much.

The last img_visible class in CSS fixes the height problem I mentioned earlier. It’s basically applied to a slide when it fades in and removed when it fades out. The idea for using position: relative on visible slide came from a comment on the previous blog post. float: left makes the fix also work on IE6.

That part is pretty straightforward, but what about JavaScript?

Making it a plugin

There’s a pretty good tutorial on docs.jquery.com about writing your own plugins. It’s a good place to start if you are interested to learn how it works. After you become familiar with the concept you can try something simple first and build up from there.

I had three things in my mind when I started doing this. First, it should scale smoothly without any glitches, second, the whole plugin should be very light in file size and third, I wanted to avoid feature bloat. Because of the second and the third thing there isn’t very many options you can customize and I didn’t even plan to include much more in the future.

Hooking it up:

1
2
3
4
5
6
7
8
9
10
11
12
$("#slides").responsiveSlides({
  auto: true,           // Boolean: Animate automatically, true/false
  speed: 1000,          // Integer: Speed of the transition, in ms
  timeout: 4000,        // Integer: Time between transitions, in ms
  pager: false,         // Boolean: Show pager, true or false
  nav: false,           // Boolean: Show navigation, true or false
  prevText: "Previous", // String: Text for the "previous" button
  nextText: "Next",     // String: Text for the "next" button
  maxwidth: "none",     // Integer: Max-width of the slideshow, in px
  controls: "",         // Selector: Where controls should be appended
  namespace: "rslides"  // String: change the default namespace used
});

Was it worth it?

I think it was. I learned a ton about jQuery plugins + now I have something to use with new projects. I do know though, that there’s still a lot of things that I could probably do better, but given the time that I used for the development, I’m satisfied with the results. See the plugin in action on it’s homepage and check out the repository on GitHub. ❦

Update: Decided to change the name “AdaptiveSlides.js” to “ResponsiveSlides.js”. That just makes more sense here.

Update 2: I changed the markup to use unordered lists. Check out the new version.

New Website

Since you are here, you have probably noticed that there’s a new design which I have been working on for some time now. I wanted to focus on the content and make something much more simple. I also wanted my site to work with various devices from smartphones to TV’s. That’s why I used the so called “Mobile First” technique and made the whole site responsive from about 240px and up.

Designing mobile first forces you to think more about the content. It’s also easier to get the site working on large number of devices, even on those that don’t support Media Queries.

As a starting point for the work I used the 320 and up boilerplate, but I ended up changing almost everything to suit my own way of working (if you don’t know, the 320 and up is a boilerplate that prevents mobile devices from downloading desktop assets by using a tiny screen’s stylesheet as its starting point). I’m still using small parts of it like the folder structure, print styles and JavaScript helpers for iPhone, but that’s about it.

When you are using tiny screen’s stylesheet as the starting point you have to design the mobile version first and build up from there progressively. The best thing in that approach is that it’s relatively easy to get the site working with large number of devices, even on devices that don’t support Media Queries. This “reversed” approach also forces you to think more about the content.

Viewed on different devices:

viljamis.com viewed on different devices

The end result

I created probably dozen different drafts before I started to work with the one design I really liked. At somepoint I even hand drew some of the texts using Mensch. I’m still not quite satisfied with the way this turned out to be, but I can improve things here along the way.

Below is a quote from Jason Rhodes’ post titled “More Responsive Design, Please.” It holds the same meaning in it as the introduction on my home page, and I think it summarizes exquisitely what I was thinking while I were building this site, and how we—as a web designers—should be building the web.

You either build for a device or you build for the web. You can’t build a web-app that’s just for the iMac. If you try, people will access it from other devices and rightfully expect to be able to use it, because that’s what the web is. When we build for the web, our initial design should respond to what we know about our users, and the layout and content should be able to subtly respond to a user’s capabilities on the fly. That’s how we build a more responsive web. Not a mobile web, or a desktop web, or an iPad web, or any other kind of web we might try to predict.”

Update: You can now browse older versions of this site via subdomains: v1.viljamis.com and v2.viljamis.com. I also fixed some accessibility issues: Now the navigation works properly on small screen when JavaScript is turned off. ❦

Responsive jQuery Slideshow Revisited

I wrote a blog post about making responsive jQuery slideshow on 18 May 2011 (You can read it on Kisko Labs’ blog). Since then much has happened and there’s now quite a lot of options where you could choose from. I did a short summary for this blog post about the options out there right now.

I’m myself using Dynamic carousel plugin by Mat Marquis on the home page, but I made slight changes to how it handles the touch events and dragging. If you want to try it out, head to the home page with either iPhone or iPad and try dragging the text caption under the big headline. Update: I removed the slider from the home page. Mainly because it didn’t make so much sense in that context.

I also created a tiny script while developing my own site and despite it being really simple I decided to release it as a plugin. If all you need is fading (with pagination), then it might be what you want to use.