Text-align: Justify and RWD

Tags: design, development, framework, front-end, grid, inline-block, justify, responsive, rwd.


Did you know that one of the most powerful tools for fluid and responsive layout has been a native feature for every browser since HTML 4?

View/Edit Demo on CodePen


While working on a project early last year, I quickly became frustrated having to re-calculate the margins between menu items in my full-width footer nav each time the client requested a new link in the menu.

Thinking about how “justified” text in Microsoft Word fills the entire width of the line by creating even word spacing, I wondered if the same principle could be applied to a menu of text links in HTML. Knowing that ‘text-align: justify’ was a long established CSS property (the descendent of HTML 4  attribute align=”justify”), I did some Googling for answers.

Sure enough, I found some discussions on StackOverflow about justified horizontal nav menus.

Fig. 1: An example of a full-width “justified” navigation menu.

How it works

In its natural state, ‘text-align: justify’ will not work unless the contents of the line are long enough to cause a line-break. Otherwise, the text remains left aligned. Incase you’re wondering why this is, it’s because in a typesetting situation this is the desired behavior – the final line of a block of justified text is always left aligned. Perhaps this was an oversight when the CSS spec was designed, but even if we only have one line of text, that one line still behaves like the final line.

It took me a few tries, but we can solve this problem by giving 100% width to an invisible inline element at the end of the line (shown in purple for demonstration purposes). As this “break” element is too wide to share a line with anything else but itself, it causes a line-break, thus becoming the final line, and  forces the words before it to justify (fig. 3).

Without a "break" element. As there are not enough elements to break the line, all elements will align left.
Fig. 2: Without a “break” element. As there are not enough elements to break the line, all elements will align left.
Fig. 3: With a “break” element. The “break” element, shown as a purple dash, forces a line break due to its 100% width. All preceding inline elements are now justified.

Because ‘text-align: justify’ is designed to work on individual inline words, it works on any inline element—and more importantly any inline-block element.

As this particular project was a fixed grid, non-responsive site (remember when we used to build those?), the potential significance of this technique for RWD didn’t occur to me until later, when I started to combine it with percentage based inline-block elements.

Fig. 4 Justified "inline-block" elements. Note the "break" element is used to make sure the last row justifies.
Fig. 4 Justified “inline-block” elements. Note the “break” element is again used to force the last row of elements to justify.

Implications for Responsive Web Design

Almost all of our responsive designs at Barrel feature some sort of boxed content in a grid. Traditionally, the way I handled this was to give each element in the grid a percentage width, and then divide up the available leftover space into equal, percentage-based margins.

When I wanted my grid to go right to the edges, I would target the first and last element of each row using nth-of-type, and remove their left and right margins respectively. This already seemed like way too much calculation, and if a browser decides to round your percentages up instead of down when converting to pixels,  that one extra pixel is enough to cause elements to jump on to the next row at random (even though all widths and margins add up to 100%!).

I’m sure we’ve all grappled with some of these issues. Enter ‘text-align: justify’ to save the day!

You’ll never have to deal with horizontal margins ever again

By simply applying ‘text-align: justify’ to the container, and giving the child elements ‘display: inline-block’ and a percentage width, you’ll never have to deal with horizontal margins ever again! (Oh and did I mention, when using this trick, you’ll also never need to use float on your elements ever again, so you can wave goodbye to those ignominious  clearfixes and clear divs too!)

NB: We should be aware that when using ‘display: inline-block’, our elements will be at the mercy of various typographic CSS properties, including font-size, line-height, vertical-align and word-spacing. These properties will have a visible affect on your layout’s whitespace, but can be easily adjusted or removed as needed. In 99% of cases, setting ‘font-size: 0.1px;’ to the container and ‘vertical-align: top’ to the child elements should do the trick.

“Break” Elements

As mentioned earlier, the first caveat of this technique is that it is necessary to force each row to “break” before it will justify. If you have a multi-row grid, this won’t be necessary until you get to the last row, but it is crucial to the technique and there are two ways we can solve the problem.

1. Adding a “break” element as the last child in the container

<ul id="Grid">
	<li class="break"></li>

With the following styling:

	text-align: justify;
	font-size: 0.1px; /*hide whitespace between elements*/

#Grid li{
	display: inline-block;
	width: 23%;

#Grid .break{
	width: 100%;
	height: 0;

2. Applying an ::after pseudo-element to the container

	content: '';
	display: inline-block;
	width: 100%;

I recommend the second method for cleaner, semantic markup.

“Placeholder” Elements

In this section I use the term “column” as a visual metaphor only, as we should all be aware that there is arguably no such thing as a vertical column, (or a grid for that matter) in HTML/CSS. One of the keys to understanding this technique is understanding that by default, HTML flows inline and horizontally across the page, left to right, line by line. By using text-align: justify, we are harnessing this characteristic instead of fighting against it with floats and absolute positioning.

The second caveat occurs in cases where we don’t have control over the number of elements in our grid.

Fig 5. Coming up short. As the last row of our grid is not complete, the justified margins are calculated based on two elements, and not four.
Fig 5. Coming up short. As the last row of our grid is not complete, the justified margins are calculated based on two elements, and not four.

Say you get to the last row of your four-column grid, and you only have two elements instead of the normal four—and you want those last two to align neatly with everything else—you will need to add invisible “placeholder” elements to make up the difference. This forces the browser to calculate the margins as if there were four items and not two (fig. 5).

If you had only one element on that last row, it wouldn’t be an issue—as it will always align left naturally. However, if you have any number of elements greater than one and less than the total columns per row, you will have to “fill in the gaps” manually with “placeholder” elements (fig. 6).

Fig. 6. "Placeholder" elements. This four-column grid requires two placeholders (shown in solid purple), to ensure margins are calculated correctly.
Fig. 6. “Placeholder” elements. This four-column grid requires two placeholders (shown in solid purple), to ensure margins are calculated correctly.

To account for any and all possible numbers of elements on the last row, the number of “placeholder” elements you will need to add is equal to the maximum number of elements per row, minus 2. These elements should be inserted at the end of your grid (before the “break” element if you are not using a pseudo-element to break the row) and then left alone. Since they do not occupy any vertical space, the “placeholder” elements won’t affect the layout if the last row is full or if your site is responsive and the number of elements per row changes. As long as you have enough placeholders for the widest view, you’ll be fine.

No. of placeholders = max elements per row – 2

Obviously, this has some semantic implications—as there is no way to create any of these placeholders using pseudo-elements. On a grid where the last row will always have the maximum number of elements, we don’t need to use placeholders at all (just a break), but in most CMS situations they are necessary, and should be hard-coded into your HTML.

Media Queries

Media queries can be used to dictate the number of columns in the grid based on viewport size. For each new column layout, we need only redefine our column width, and justify will take care of the rest. Check out the demo to see it in action across four different layouts (NB: Our demo also uses fluid, dynamic element height via the old padding-top trick).

Wider Uses

After having great success with this technique, I’ve started using it as a powerful layout tool for all sorts of applications. I rarely, if ever, need to use floats for layout anymore, and combined with media-queries, it becomes an incredibly powerful and time-efficient technique for tackling percentage-based fluid layouts.

It’s also just as useful on non fluid layouts, if you don’t want to spend time calculating your margins—why not let the browser do that work for you?

Why not let the browser do that work for you?

Perhaps most impressive, is the cross-browser compatibility of this technique. Because “justify” and “inline-block” have both been around for a very long time, this technique can be used confidently on IE7 and up (with a few small IE7 hacks!).

As a footnote, the main stimulus behind the creation of the MixItUp plugin was preserving the elegance of this technique on a grid that required dynamic client-side animated filtering. I knew that using masonry or isotope on it (both incredibly powerful plugins but perhaps overkill for a standard grid layout) would force absolute positioning on my elements, convert their percentage-based widths and heights into static pixels, and require a disproportionate amount of custom JavaScript to maintain the responsive behavior I had so easily achieved with CSS and media queries alone. So MixItUp was born, and I’m very excited with how the two techniques are working together so far.

If you’re interested in exploring this technique further, check out the following links:

Basic Examples:

Fully functioning grid demo
Further examples

Advanced Examples:

New Music USA (grants page, musician stories, blog)
Barrel NY (work page, team page, blog, and many other places!)
MixItUp (homepage and demos)


Popular This Week
25 Must-Have Pages for Your E-commerce Website
January 30, 2015

25 Must-Have Pages for Your E-commerce Website

By Yvonne Weng
Taking Control of Image Loading
July 29, 2013

Taking Control of Image Loading

By Patrick Kunka
From Zero to Backbone in 48 Hours
May 22, 2014

From Zero to Backbone in 48 Hours

By Kevin Kneifel
5 Blind Spots to Consider When Designing Web Apps
July 31, 2014

5 Blind Spots to Consider When Designing Web Apps

By Yvonne Weng

Like what you’re reading? Sign up for the Barrel newsletter and receive updates.