Cropping and Pinning Images With CSS

It feels really good to figure out a tricky CSS problem on your own without consulting the
googles. This is a brief story about how I did that very thing while working on the
forthcoming Great Bleything.net Refresh of ‘08™.

As you can see in the image below, the template I’m using wasn’t expecting to have an image
in the left-hand column, so when I put one there, weird stuff happened when the browser was
smaller than about 1100px:

Of course, expecting that people’s browsers are wider than that is kinda crazy, so instead of
ignoring the problem, I fixed it. On some advice from Matt Lyon,
I tried to figure out how to make the image crop itself when the window got too small to
contain it.

As you see it in the image above, it’s actually inside an unordered list, because that’s how
the template came and I just dropped in my content. I initially tried making the li
relatively positioned and overflow: hidden, and the img absolutely positioned, but that
resulted in the image going right up to the edge of the grey box instead of leaving a border
around it.

Realizing that the unordered list thing was kind of insane markup anyway, I switched to using
a div. I tried the same positioning trick with no luck. At some point in my fiddling I even
got the image to disappear altogether when overflow: hidden was on the div. I slowly came
to realize that I was going to need more than one div.

That led me to the solution, which is reproduced below for your enjoyment:

1
2
3
4
5
6
7
8

id="headshot">
class="image"> src="/images/headshot.png" />

Ben Bleything, Bit Poet

... and the relevant CSS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

div#headshot {
  background: #555;
  padding: 10px;
}

div#headshot div.image {
  position: relative;
  height: 211px;
  overflow: hidden;
}

div#headshot div.image img {
  position: absolute;
  right: 0;
}

If you’re not familiar with this technique, allow me to explain a touch. First, the outer
div acts as a container for all the goodness to come. We set its background color and give
it some padding so we have the nice border around the image.

Next, we have the div that will contain the image. This is what gives us the ability to
crop the image, as well as the ability to “pin” it to the right-hand side (since in the shot
I’m on the right). By setting position: relative on the inner div, we gain the ability to
absolutely position elements inside it. Note that the terminology is kinda strange here,
since what we ultimately accomplish is having the absolutely-positioned elements be relative
to the relatively-positioned element.

We also set overflow: hidden, which makes anything that would normally be outside the div
disappear. Finally, we set an explicit height (which matches the height of the image).
Without the height attribute, the div wouldn’t take up any space. I’m not entirely sure I
understand the reasoning for this, but I believe that absolutely positioned elements are
removed from the flow so they don’t cause their containing elements to resize. Similar things
happen when you float elements.

Finally, we absolutely position the img tag inside the inner div, and pin it to the
right-hand side. The cumulative effect is that at full width, you see the entire image. As
you shrink the page, the left column will eventually start to shrink too. When it does, the
left-hand side of the image will start to “overflow” the left-hand side of the containing
div, but thanks to overflow: hidden, it just disappears, leaving our nice border in
place.

Cool, right? I really do love this stuff. Stay tuned, I should be rolling out the new design
soonish.