A flexible inline block

When working on this website, we stumbled upon an unexpected problem: How should we create the text highlighting in our headers giving each line a larger padding to the right? It took us a while, but in the end we found a clever solution.

  • css
  • html
  • tip
  • web design

The problem resulted from a static mockup that looked quite simple. We wanted the markup to be simple as well and as semantic as possible, so we started with just a paragraph:

<p>
    Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. 
    Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Donec id elit 
    non mi porta gravida at eget metus.
</p>

p {
    padding: 5px 45px 0 9px; 
}

But there was a problem.

A flexible inline block

Using display: block didn’t work: while it respects a given padding, it creates a single big box and doesn’t apply to lines.

Flexible inline block

Using display: inline didn’t work either, as it just creates a single line of text. So we thought: display: inline-block to the rescue! But that didn’t change the situation. We had to add additional markup for each line to get things working:

<p>
    <span>Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis </span>
    <span>vestibulum. Morbi leo risus, porta ac consectetur ac, vestibulum </span>
    <span>at eros. Donec id elit non mi porta gravida at eget metus.</span>
</p>

p span {
    padding: 5px 45px 0 9px;
    display: inline-block;
    margin: 4px 0 0; // needed to separate the lines
}

This finally worked perfectly.

Making it more complicated

Nevertheless, we had another requirement: our site knows two states – a wide and a narrow one, applied responsively based on the windows size (just give it a try and resize this window). So a line was no longer a line: what might be single line in the wide version could become one and a half lines in the smaller version. We needed to add more span elements to our highlighted paragraph. This led to a new problem: every few words, for each span, the padding - needed at the beginning of the line - was repeated. Sure enough this was not what we were after.

Flexible inline block

Flexible inline block

The solution

To get rid of the newly introduced gaps, we added a matching negative margin to the right of all spans, hence removing the left padding. This nearly made everything work as needed: no gaps between lines and everything wrapping nicely when resizing the window. But the left padding we just removed was now also missing at the beginning of the lines.

Flexible inline block

What saved us was a rather neat idea: we added a pseudo element before each span. By positioning this element absolutely without specifying the top but setting a left coordinate, it automatically aligned at the beginning of each line:

p span::before {
    width: 9px;
    height: 34px;
    display: inline-block;
    content: " ";
    position: absolute;
    left: 0;
    margin-top: -5px;
}

Job done! And this is what the different layers look like when relocated by a few pixels:

Flexible inline block

Post scriptum

A few quick responses on Twitter:

@nilshoerrmann <span>That</span><span>makes</span><span>very</span><span>ugly</span><span>code</span>. <span>Unmaintainable.</span>

This is true – the described method makes the markup harder to read. But in our case maintenance is not a big problem because we have a simple XSL template that generates the needed markup on the fly. I’ll post more on this later this month.

@nilshoerrmann @yatil I made something similar with display: inline: dabblet.com/gist/1753471 This way you don’t have to markup each line.

Really nice. But this gets extra bonus points as it also solves the problem of a larger right padding:

@nilshoerrmann dabblet.com/gist/1753540 /cc @yatil

Fancy!