Hiding and revealing portions of images

It’s possible to dynamically “crop” both background and foreground images as the layout changes in width, solving the problem of overflowing fixed-width images in a flexible page.

This tutorial is slightly adapted from Chapter 9 of my book, Flexible Web Design: Creating Liquid and Elastic Layouts with CSS. You can download most of Chapter 9 for free as a PDF at the Flexible Web Design companion site, as well as download the HTML, CSS and image files that go along with this tutorial.

Since the area available for an image to display within a flexible layout changes on the fly, your images may need to as well. While fixed-width images can work within flexible layouts—as long as they’re not too large, or you have matching minimum widths in place—there are lots of ways you can dynamically change the screen area that an image takes up.

I’ve already written about how to make images literally scale, but another way to change the amount of screen area an image takes up is to dynamically change how much of the image is shown at any given time. The image itself doesn’t change in size—the amount of space in which it’s allowed to show does, and the rest of the image just remains hidden outside of that space. I call this “variable cropping.”

You can create a variable cropping effect with either background or foreground images. Both look the same, but each is specially suited to different situations.

Variable cropping with background images

Putting the image that you want to dynamically crop in the background is ideal when the image is purely decorative. This technique lets you keep the image in the CSS with the other decorative images, so if you later change the look of the site, all the decorative images can be changed in a single style sheet instead of having to replace multiple img elements across multiple pages of the site. By keeping the decorative image as a CSS background, you’re also making it likely that the image won’t print when the user prints the page—background printing is turned off by default in all major browsers—so the user can save ink by printing only content.

To use a CSS background image, you’ll fi rst need an element on which to place the background. This example will use a div:

<div id="background"></div>

The div is completely empty; it contains no content, but exists simply to hold a background image. If you have a more semantic element you can hang the background on instead, use it. For instance, perhaps the image you want to dynamically crop sits above an h3 element and matches it in width. You could add the image as a background to the h3 element and give the h3 enough top padding to make sure its text sits below the image, not on top of it.

Next, create a rule for this div that sets the image as its non-tiling background:

div#background {
	background: url(styx.jpg) no-repeat;
	border: 2px solid #000;
	}

I’ve added a border on to this div as well so you can easily see where its edges lie. Right now, with no content within the div, it will collapse to zero height. Add dimensions to the div to prop it open:

div#background {
	width: 50%; 
	height: 330px;
	background: url(styx.jpg) no-repeat;
	border: 2px solid #000;
	}

Tip: To dynamically change the height of the image as well as or instead of the width, use a flexible value for the height property.

The width is set to some flexible dimension—either a percentage, as I’ve done here, or an em value to make it elastic—so that the div can change in width to show more or less of the image. The height is set to the pixel height of the image so that the entire height of the image will show at all times.

The div will now always be 50 percent as wide as the viewport; its background image doesn’t change in size, but gets cropped to a varying degree from the right side.

However, this particular image would look better cropped from the left side, as the cat’s face is on the right side of the photo. To specify from where the image gets cropped, use the background-position property, or its shorthand in the background property, to change the alignment of the image within the div:

div#background {
	width: 50%;
	height: 330px;
	background: url(styx.jpg) no-repeat right;
	border: 2px solid #000;
	}

The image is now anchored to the right side of the div, so more or less of its left side shows as the div changes in size.

This is all the CSS necessary to get the basic variable cropping technique working, but you can add a few other enhancements if you like. For instance, right now, once the div exceeds the width of the image, empty white space shows within the div. There are a few ways you could handle this. You could add a background color to the div as well that would fill up whatever space the image cannot; if you blend the edge of the image into this background color, the effect can look seamless. Or, you could add a maximum width to the div so it can never grow larger than the image. You could also add minimum widths, as well as maximum and minimum heights, to ensure that the div can never grow or shrink past particular
points in the image.

Variable cropping with foreground images

If the image that you want to dynamically crop is functional content, you’ll want to keep it as a foreground image by placing it in the (X)HTML using the img element. You can ask yourself these questions to determine if the image is content, not decoration:

  • Does the image convey information that I ought to put as text in an alt attribute?
  • Do I want to make sure the image always prints because without it the
    printout wouldn’t make sense or be complete?
  • Do I want to link the image?

If the answer to any of these questions is yes, the image is content and should be kept in the (X)HTML. CSS background images can’t achieve any of these goals—at least not without some complicated workarounds and hacks, all of which are quite silly, considering how easily a simple img element can achieve all this.

As with the background-image version of the variable cropping technique, you’ll need some block element in the (X)HTML to hold the image. We’ll use a div again; this time it won’t be empty, but will instead contain the img element:

<div id="foreground">
	<img src="styx.jpg" alt="my cat Styx" width="500" height="330">
</div>

Note: The img element has an alt attribute providing the text equivalent of the image. You can’t do this with a CSS background image.

Just as before, the div needs to have a flexible width and a height set to the pixel height of the image:

div#foreground {
	width: 50%;
	height: 330px;
	border: 2px solid #000;
	}

So far, all we have is a regular div holding a regular image—there’s nothing yet that makes this a variable cropping technique. If the image is bigger than the div, it doesn’t get cropped, but simply overflows.

To get the cropping effect, add overflow: hidden; to the CSS rule:

div#foreground {
	overflow: hidden; 
	width: 50%;
	height: 330px;
	border: 2px solid #000;
	}

Now whatever portion of the image would overflow out of the div is hidden from view.

Once again, though, it would be better for this image to be cropped from the left side, not the right. We can’t use the background-position property this time because it’s not a background image. To change how a foreground image is anchored within its parent, you can float the image:

div#foreground img {
	float: right;
	}

This anchors the image to the right side of the div, so more or less of its left side shows as the div changes in size. Using a foreground image results in an effect that looks exactly like using a background image, but the foreground image has alternative text, and you could also easily add a link to it.

Did you like this?

72 Responses to “Hiding and revealing portions of images”

  1. edward

    “This anchors the image to the right side of the div, so more or less of its left side shows as the div changes in size.”

    Does not work that way in IE 7.

    Reply

Leave a Reply

  • (will not be published)

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>