Solved: Tricky Floating Image Alignment

Solved: Tricky Floating Image Alignment

At 4/19/2024

If you want to pair an image alongside some text content in CSS, you have a few options.

You can float the image left or right. Any text that extends past the image will naturally flow beneath, which is neat. But if the text is shorter in height than the image, you get an Oklahoma Panhandle effect with one big corner of negative space.

An image of a smiling puppy floating alongside some text. The text is much shorter than the height of the image, and the empty space is highlighted in red.

Instead, you might set a containing element’s display to grid or flex, arranging the image and text in their own columns. This gives you much finer control of alignment, so you can vertically center the text content until it overflows. Unfortunately, that overflow will never flow beneath the image, which makes it less space efficient.

The same image as before, but with more text content alongside. Because this image is arranged using a grid, there is now empty space highlighted in the bottom right corner.

Ideally, we’d combine these two alignments: The overflow behavior of float, with the alignment behavior of grid or flex. Surely that would require some newfangled CSS involving container query units or scroll-driven animation wizardry?

The first example, but with the shorter text content centered vertically within its container.
The second example, but with the longer text content wrapping around the bottom of the image.

It turns out, we can pull this off using a clever combination of properties that browsers have supported for a long time.

Here’s a demo of the solution in action. You can edit the content directly (thanks to contenteditable), or use the buttons to shorten or lengthen the text content.

This is the relevant HTML:

<div class="media">
  <div class="media__inner">
    <img class="media__object" src="…" alt="…" width="…" height="…">
    <div class="media__content"></div>
  </div>
</div>Code language: HTML, XML (xml)

Which we style with this CSS:

.media {
  display: grid;
}

.media__object {
  float: right;
  margin-left: 1em;
}

.media__content {
  position: relative;
  top: 50%;
  transform: translateY(-50%);
}Code language: CSS (css)

(You may want to replace physical direction properties and keywords above with equivalent logical properties, depending on your project and audience.)

This bonafide CSS trick involves the following elements:

  1. .media: The outer wrapping element, which establishes a grid. This clears floats, establishes a new stacking context and, most crucially, resolves the container height for relative positioning (more on that later).
  2. .media__inner: The inner wrapping element. Grid items can’t float, which is why we have to nest our floating image and adjacent content two elements deep. The class name is optional since this has no styles of its own.
  3. .media__object: The image, floating to the right.
  4. .media__content: The content, which flows around the image. We offset its position to achieve the alignment effect.

The .media__content class has two different positioning rules applied to it:

  1. A combination of position: relative and top: 50% shifts the content down by half the height of the parent element.
  2. translateY(-50%) shifts the content back up by half its own height.
Step 1: The content shifts down by half the parent height using top.
Step 2: The content shifts up by half its own height using transform.

When the text content is shorter than the image, it will also be shorter than the container. By extension, the offset that uses translateY will be smaller than the offset using top, resulting in the content centering itself vertically.

But when the text content is tall enough to flow around the image, then the containing element will have stretched to match its size. This means the offsets will be equivalent, canceling each other out.

For this to work, top: 50% needs to be relative to the parent element, including its children (floating or otherwise). I tried a bunch of techniques for creating new stacking contexts, and setting the display to grid or flex were the only ones that seemed to work for this scenario. I chose grid since it’s very well-supported and requires no additional styles.

This technique doesn’t play well with the shape-outside property when the content is shorter. (That’s a bummer for circular images.) It’s also a shame that the grid wrapper is required.

I think it’s pretty neat that in this era of rapid development of CSS standards, there are still novel combinations of long-stable properties to discover.

Huge thanks to Vesa Piittinen for suggesting the original solution and granting me permission to write about it. Thanks also to Miriam Suzanne for confirming when I was barking up the wrong tree, to Nicole Sullivan for inventing the media object pattern I used in this demo, and to Buster for being a very good boy.

Copyrights

We respect the property rights of others and are always careful not to infringe on their rights, so authors and publishing houses have the right to demand that an article or book download link be removed from the site. If you find an article or book of yours and do not agree to the posting of a download link, or you have a suggestion or complaint, write to us through the Contact Us, or by email at: support@freewsad.com.

More About us