0

In a website I'm coding, the designer wishes to have ragged-right text with a background color (over a photo). The design prescribes some padding on both the left and the right side and also a well balanced background: all background "blocks" have the same height and stack tightly on top of each other. The following image shows an example.

example of properly padded, ragged-right text with a solic background-color

Searching for solutions for this, it turned out that this design has two distinct challenges:

  1. Make sure that any left and right padding are applied to all lines; and

  2. Make sure that the vertical spacing is perfect.

Challenge 1 can be solved using some css-tricks on multi-line-padded-text. This has also been discussed here on SO on several Q&A's: span background-color & padding problems, CSS create padding before line-break, to link some.

Challenge 2 is a bit trickier and is also related to the box-shadow-solution for the left and right padding on all lines.

First on this last point: even after carefully setting top and bottom padding to the text, I notice subtle errors (in Firefox, which is definitely one of the targeted browsers):

subtle errors (in Firefox) on the box-shadow

These subtle lines may also occur between (some of) the lines upon zooming. This would be indicative of a non-exact line-height (thus padding). However, setting the vertical padding too much (to be on the safe side) also has problems:

enter image description here

I used a semi-transparent background (and box-shadow) here to highlight the issues. First, the solution will not work for cases where transparency is needed. And second: the background "blocks" are not anymore of equal height (e.g. the gap between lines 2 and 4 is much narrower than line 4).

It turns out that there exists an inherent problem with setting the right padding: it cannot be predicted exactly how high the actual line-height is (i.e. not without digging very deep into the internals of the font metrics). Especially in cases where the font used is not predictable (which is common on the web).


So the question is, how to add a background-color to a flowing piece of text, having it properly left and right padded, and having the lines to stack exactly on top of each other?

Some caveats:

  • Setting display: inline-block is a no-no: it will create a rectangular background.

  • The afore-mentioned solutions work "a bit", which is not enough. They have their issues, as illustrated.

  • Obviously, I am looking for a css-only solution, NOT javascript.

  • Of course, the text used is server-generated and can change.

I have found one solution which works for me: using a background image of the right color, which can be scaled to exactly one line-height. I will submit this self-answer. Although I do like the hack, I am still open for other suggestions.

Marten Koetsier
  • 3,389
  • 2
  • 25
  • 36
  • [this](http://meyerweb.com/eric/css/inline-format.html) is also a deep level post on why the height of the content box is unpredictable. `line-height` can be set in css, but not `content-area-height` or `leading` (or `half-leading`). Background is drawn on the content-area, not the line-height. – Marten Koetsier Jul 05 '17 at 06:10

1 Answers1

1
<p>
    <span>Lorem ipsum dolor sit amet ...</span>
    <span>Sed ultrices, leo eu porta mattis ...</span>
</p>
p {
    width: 30em; /* as needed */
    font-size: 12px;
    line-height: 2;
}
span {
    padding: 0.6em 0.5em;
    background-image: url(data:image/gif;base64,R0lGODdhAQABAIABAFVVVf///ywAAAAAAQABAAACAkQBADs=);
    -webkit-box-decoration-break: clone;
    -ms-box-decoration-break: clone;
    -o-box-decoration-break: clone;
    box-decoration-break: clone;
    background-repeat: repeat-x;
    background-size: 1px 2em ;
    background-position: center;
}

Notice that I did not specify a font-family: font metrics are now not an issue anymore. Also, any font-size can be used. It is important to match the line-height to the settings for the span (see below), but this is also 'free'. It's even possible to use line heights lower than normal, although ascenders and descenders may of course extend from the background in that case.

The actual trick is specifying a background image and setting its height exactly equal to the line height (2em in this example). For this, I use a single-pixel gif image that I crafted in the Gimp. The string in the data-uri is just the base-64 encoded content of the gif file (of 35 bytes). This gif is then expanded to the desired height using background-size and setting background-repeat: repeat-x makes sure that the width is set properly. Not setting vertical repeating allows us to set an imprecise amount of vertical padding (see below). background-position: center takes care of properly aligning the text to the background vertically.

The vertical padding is another part of the trick: set it high enough so that the padding (both top and bottom) plus the line-box height exceed the line height. 0.5em should have been enough, but I'm using 0.6em here to be on the safe side (and it distinguishes nicely from the 0.5em horizontal value). Since there is no background-color, everything outside the background-image is transparent! (if the span inherits some background-color, just override it to be transparent)

The horizontal padding (0.5em here), together with the box-decoration-break: clone setting (also with prefixes, although I do not know which are actually needed) takes care of the left and right padding, also setting it equal for all lines.

For semi-transparent backgrounds, a dito png-image will work instead of the gif. I chose a gif here because of the file size. The image can also be loaded separately, but using the data-uri saves a http-request (which would be way more than the current 70 bytes and take a long time).

Marten Koetsier
  • 3,389
  • 2
  • 25
  • 36