Equidistant Objects with CSS

Avatar of Chris Coyier
Chris Coyier on (Updated on )

📣 Freelancers, Developers, and Part-Time Agency Owners: Kickstart Your Own Digital Agency with UACADEMY Launch by UGURUS 📣

Just take me down to the solutions, please.

Creating a horizontal row of objects that are equidistant from each other is another one of those things in web design that is much more difficult than it should be. This can be a very useful thing to do, especially in fluid width layouts when you are trying to make the most of whatever horizontal space you have.

equidistant.png

Here are the goals we are trying to achieve:

  • The left-most object is left aligned with it’s parent element.
  • The right-most object is right aligned with it’s parent element.
  • Each object is equidistant from one another at all times.
  • The objects will stop short of overlapping each other as the browser window narrows.
  • The objects will not wrap down as the browser window narrows.
  • The technique will work in a fluid width environment. Even one that is centered.

I tried a number of different techniques to try and achieve this. Let’s go through all my failures and then to the final technique which seems to work pretty good.

FAIL: Give each object a percentage left position

First I gave each image a unique class:

<img src="images/shape-red.png" class="first-r">
<img src="images/shape-green.png" class="second-r">
<img src="images/shape-yellow.png" class="third-r">
<img src="images/shape-blue.png" class="fourth-r">

Then I gave percentage-based left positioning to each of those classes:

img.first-r  { left: 0%; position: relative; }
img.second-r { left: 25%; position: relative; }
img.third-r  { left: 50%; position: relative; }
img.third-r  { left: 75%; position: relative; }

Notice the relative positioning. This is required to get the left-most image to respect the parent element assuming the content is centered and not left-aligned. The problem with this is that the left margin being applied to the right-most object is 75% of the browser window width, but applied starting at the left of the parent element not the browser window. This can cause the right-most element to push off the screen (not respecting the right edge of the parent element). Also, inexplicably, these element will eventually wrap if you move the browser window narrow enough.

If you switch to absolute positioning here, you solve some of the above problem but then your objects will be left-aligned and ignore the parent elements left position entirely. Also, at narrow enough browser window sizes, the images will overlap. But hey, at least the objects were equidistant!

FAIL: Give the objects a common left percentage margin

My next stab was to give each element, except the first one, a common percentage left margin.

<span class="do-not-wrap">
  <img src="images/shape-red.png">
  <img src="images/shape-green.png" class="mover">
  <img src="images/shape-yellow.png" class="mover">
  <img src="images/shape-blue.png" class="mover">
</span>

Applying the margin:

img.mover {
  margin-left: 15%;
}

You should be able to tell from looking at that percentage that this technique is doomed. I just picked a percentage that seemed to work best. There is nothing mathematical I could think of that would work here. Because the parent element is a percentage of the width of the browser window, and the margin is a percentage of the browser window not the parent element, the growth rates will be very difficult to match. Also notice the “no-wrap” span, which is necessary to prevent …wait for it… wrapping. But hey, at least the objects were equidistant!

FAIL: Just use a table!

Even “throwing in the towel” on CSS doesn’t seem to work here. I thought this would work for sure, being that tables have that sometimes-useful-sometimes-infuriating ability to auto space it’s cells evenly.

<table>
	<tr>
		<td class="leftalign">
			<img src="images/shape-red.png">
		</td>
		<td>
			<img src="images/shape-green.png">
		</td>
		<td>
			<img src="images/shape-yellow.png">
		</td>
		<td class="rightalign">
			<img src="images/shape-blue.png">
		</td>
	</tr>
</table>

Notice the extra align classes in the first and last cells. If all the cells are centered, that allows the objects to be equidistant but then neither the left object or the right object is aligned to the edge of the parent element. This is solveable by applying a left alignment to the left-most cell and a right alignment to the right-most cell — but then the objects are no longer equidistant. Back to the drawing board.

PASS: Flexbox Justification

I’m adding this in June 2015 (seven years later!) because it’s the best solution (if you’re able to use flexbox).
<div class="container">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>​
.container {
  display: flex;
  justify-content: space-between;
}

See the Pen Equidistant Objects by Chris Coyier (@chriscoyier) on CodePen.

PASS: First on the left, float the rest right in equal size boxes

Fortunately the table idea sparked some thought. The first image needs to be left aligned, but all the rest of them could be right-aligned. In fact, if they are, and also inside of boxes that divide the rest of that space evenly, that might just do it. Perhaps this is best explained visually:

floatytechnqiue.png

HTML:

<img src="images/shape-red.png">
<div id="movers-row">
	<div><img src="images/shape-green.png"></div>
	<div><img src="images/shape-yellow.png"></div>
	<div><img src="images/shape-blue.png"></div>
</div>

CSS:

#movers-row {
	margin: -120px 0 0 120px;
}
#movers-row div {
	width: 33.3%;
	float: left;
}
#movers-row div img {
	float: right;
}

There is an example page, where I was working this. It’s not pretty… but you can see the winner on the bottom. I’m sure some of you all have some better solutions for this, so let me have it!

PASS: Using inline-block and justified text

This can be done by setting the elements to display: inline-block; and the parent element to text-align: justify;. Well, it’s slightly more complicated and what I’d call a bona fide CSS trick. You add an additional element (via pseudo element) that is 100% wide and the previous inline blocks will line up.

<div id="container">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>​
#container {
  height: 125px;
  text-align: justify;
  border: 10px solid black;
  font-size: 0.1px; /* IE 9/10 don't like font-size: 0; */
  min-width: 600px;
}
#container div {
  width: 150px;
  height: 125px;
  display: inline-block;
  background: red;
}
#container:after {
  content: '';
  width: 100%; /* Ensures there are at least 2 lines of text, so justification works */
  display: inline-block;
}

Demo:

Check out this Pen!