Five Useful eBook CSS Snippets

You may not know what we’ve been doing behind the scenes of the Blitz framework but we’re actually working a lot. As a matter of fact, now that we (feel we) have a sensible foundation, a lot of R&D is happening. By “R&D” I mean “progressive enhancement”.

Let’s be honest, with ePub 3.1 aligning on the web, using the “new and shiny” is just a matter of time. Yes, we must deal with legacy RMSDK. Nope, CSS doesn’t have to be the lowest common denominator. Accepting that crappy denomatinator as our fate won’t obviously improve the situation. And as long as you’re doing “progressive enhancement”, I do believe you’re OK.

So I thought it would be cool to share a few CSS snippets I’ve been using lately. Sure, that won’t turn your eBook CSS into the most advanced CSS ever but the devil is in the details and, when combined, they can make a real difference.

Simple is so beautiful

Images are painful.

You’ve got so little control over their display (spread using columns, device aspect-ratio, etc.) that it’s no wonder some RS actually override images’ styles.

Style your images based on width and it may overflow on some aspect ratio for some images.

Style your images based on the viewport’s height and then users do this…

Try styling your images based on everything and, well, keep trying.

But there’s a new terrific CSS property, ladies and gentleman. It’s like “background-size” but for inline images.

img {
object-fit: contain;

And that’s it.

Now, your image will keep its aspect ratio, whatever happens. And that’s just brilliant.

Reflowable asterism

Contextual breaks are terrible.

We must now use <hr/> in HTML5 to imply that but… it’s a self-closing tag so you can’t put anything inside it. So you’ve got two choices:

  1. adding content using :after, which may be terrible for text-to-speech as “Context break Asterisk asterisk asterisk bla bla bla Context break Asterisk asterisk asterisk bla bla bla Context break Asterisk asterisk asterisk bla bla bla Context break Asterisk asterisk asterisk bla bla bla Context break please kill me now bla bla bla.”
  2. using background-image, which may be terrible because night mode and user’s font-size setting, etc.

Enter SVG.

And here’s the trick…

hr {
width: auto;
border: none;
margin: 1.5em 0;
height: 1.5em; /* will reflow with font-size #VerticalRhythm */
text-indent: 0;
text-align: center;
background: transparent url("../Images/asterism.svg") no-repeat center;
background-size: 2.5em 1.25em; /* will reflow with font-size */
overflow: hidden; /* getting around RMSDK bug */

So OK, you’ll probably tell me “BUT SUPPORT FOR BACKGROUND-SIZE IS TERRIBLE!!!” and I’ll admit you’re right.

But, in your SVG, you’ve got the following.

width="48" height="24" viewBox="0 0 48 24"

which means that oh yeah, if background-size is not supported, it will fall back to the values in the width and height attributes. Sure, it won’t reflow with font-size in legacy RMSDK but as far as I’m concerned, it’s good enough.

Feel the power of SVG.

Yo Reading System, avoid that annoying blank page

I’m usually trying to avoid using margin-bottom in my CSS. The reason is simple: should your last element have a margin-bottom, it may sometimes overflow the last page and create a blank one in some Reading Systems. And this is just terrible.

On the other hand, there are elements for which you may need a margin-bottom like say figures, bordered asides and stuff. And using a specific or adding a functionnal class every time this happens would be painful.

So, here we go…

body > *:last-child {
margin-bottom: 0;

It’s just about telling the Reading System to strip the margin of the last direct child of body. That can be <section> or <div> or anything.

Now, if you are using <section> or another cool semantic kid, you may have to use this as well…

body > section > *:last-child {
margin-bottom: 0;

This may also come in handy for bordered asides, for which you’ll probably declare padding. In that case, margin-bottom and padding won’t collapse so you’ll get unexpected spacing.

aside {
border: {whatever};
padding-bottom: 0.75em;

aside > *:last-child {
margin-bottom: 0;
Left, without snippet. Right, with snippet.

We cool now?

Yo Reading System, compute for me

Epigraphs, one of eBook authors’ worst nightmares.

Do as in print… no, just don’t. Setting a 40% or, even worse, à 50% margin-left is malpractice which should lead to your firing because you’ve obviously never QA-ed your eBook on a smartphone.

Try finding a compromise and maybe it might look OK in narrow containers… but it will also look like absolute crap in wide containers.

And then, calc() brings bliss…

@supports (max-width: calc(30em + 5%)) {
.epigraph {
max-width: calc(30em + 5%);
padding-left: 5%;
margin-left: auto;
margin-right: 0;

To sum up:

  • max-width is 30em (will reflow with font-size) + 5% of the container’s width;
  • there’s a padding-left of 5% in case the container’s width is inferior to the max-width;
  • margin-left is set to auto so that the difference between the container’s and the element’s width is the margin;
  • epic win.

It’s responsive (without media queries), it sticks to the right, it won’t extend to 95% of 1500 pixels, etc.

On the other hand, allowing such a huge line-length is terrible, ADE, especially as you’ve got a “two-column view”…

Lines of code, numbered

Last but not least, numbered lines for code snippets.

Apple for instance, is structuring code as ordered lists (<ol>) and putting it in a <div> (and not <pre>, which allows for indenting for instance).

Question is do you really need those fancy numbers everywhere, especially as some RS are just terrible at ordered lists?

After all, lines of codes are not numbered absolutely everywhere. And maybe you complained once or twice because numbers were copied and pasted too.

So, in case you consider that progressive enhancement, here’s the snippet:

pre code {
counter-increment: line;

pre code:before {
content: counter(line);
width: 2em;
display: inline-block;
text-align: right;
padding-right: 8px; /* won’t reflow with font-size */
margin-right: 8px;
border-right: 1px solid currentColor; /* will invert */
-webkit-user-select: none; /* won’t be copied/pasted */
-moz-user-select: none;
-ms-user-select: none;
user-select: none;

And that’s it, your lines are now numbered if each line is wrapped in <code></code>.

Modern CSS is modern

It can solve a lot of problems.

Properties and values were added in specs because they are useful and we wished they had existed during all those years we suffered.

Once again, it’s all about progressive enhancement i.e. designing a solid foundation, which works everywhere, then building on top of it.

That should also be a friendly reminder to our RS friends: no doubt CSS is going to be more and more difficult to override; finding a sensible compromise to manage that is now or never.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.