Easy CSS Wins

CSS Is Awesome
  • Sumo

Here at EPUB Secrets we are very lucky to have a broad, global community of smart developers who want to share their R&D with us. This Guest Post is from Jiminy Panoz, French ebook developer extraordinaire.


I love modern CSS.

It is so simple once you get it, has responsive design covered out of the box, and can even be super fun. It makes you feel like you’re a wizard.

It makes you feel like you’re a wizard.

Modern CSS is how you enable the Open Type features of your beloved fonts.

It can deal with your layout in a responsive manner. Just throw some flexbox properties in a container and its layout is managed automagically.

And it is powerful too! Sometimes a one-liner can deal with all the painful stuff for which you previously needed complex CSS hacks.

It’s obvious I’m sold, and this is why I’ll try to convice you you should go for “easy CSS wins” whenever possible, as soon as possible.

A note about support

Because this is somewhat important and you don’t want to break things in a terrible way.

But Jiminy, it won’t work here and there!

Let’s take a look at CanIUse, a website helping web developers cope with all the old an shiny new specs.

Feature Unprefixed Global
Flexbox 86.83% 97.68%
@font-face N/A 95.41%
Border radius 94.97% 95.04%
Box Shadow 94.88% 95.01%
Hyphens 57.84% 84.83%

Sources:

But Jiminy, those are raw numbers!

Well, yeah, but this wasn’t the idea. Indeed, the “global column” is the message; there is no “100%” in there.

However, that doesn’t stop us from using hyphens extensively, applying border-radius to a super boring box because it brings some swag to the layout or embedding fonts because we are fontichists.

But Jiminy, it’s for browsers, not reading systems!

You should check this presentation by Micah Bowers. It’s a good recap about the previous and current states of EPUB rendering.

TL;DR: modern Reading Systems are using browsers’ rendering engines e.g. WebKit, Blink, EdgeHTML, etc.

Two words for ya: progressive enhancement.

But Jiminy, my mobi7s and RMSDKs!

Two words for ya: progressive enhancement.

This concept is not that difficult to understand: it’s about building a rock-solid foundation (a well-structured document which works if CSS is not supported) and then adding enhancements to it.

Reading Systems provide a wide range of possibilities, it’s up to you to leverage them. And, as a matter of fact, you are already doing it since you’re using CSS which is not supported by old Kindle eInk Readers or, even worse, some Android apps—they are the worst.

If you missed ebookcraft this year, here are my slides about progressive enhancement. There is a lot you can do in EPUB. Today.

Also, I’ve just launched a micro-service online, I hope it will be inspirational.

Doebooksneedtolookexactlythesameineveryreadingsystem?

(Spoiler: the real fun kicks in when resizing the height of your browser’s window.)

(Disclaimer: it is also kind of buggy because it is sort of a statement on the current state of ebook rendering. No sarcastic github project is perfect after all.)

Seven Easy Wins

By now you should be assured these won’t be seven deadly sins.

I’m personally using some with feature queries because I’m extra cautious or couldn’t test them extensively yet.

The declarations within a feature query will simply be ignored by Adobe’s RMSDK and Kindle so you won’t annihilate your ebook design when using them.

The syntax is:

@supports (property: value) {
  selector {
    property: value;
  }
}

Of course you can use the “and”,  “or”, and “not”operators to design more complex queries if needed.

Keep the correct aspect ratio for medias

Image sizing is super tough, especially when you can’t tell the ratio of the Reading System’s page. In some cases, it might even overflow and the reader finds her/himself with a truncated desolation.

Enter object-fit, which specifies how the contents should be fitted to the box established by its used height and width.

img, svg {
  object-fit: contain;
}

Apple has been using this in iBooks for ages now. And it indeed solves a complex issue. Best part of it? You don’t even need a feature query, you can drop it like it’s hot in your existing declaration.

See the Pen Easy CSS Win #1: object-fit by Jiminy Panoz (@JayPanoz) on CodePen.

Feature Query? Nope | MDN | CanIuse

Make a figure-heavy book more legible

For some reason the default for a lot of fonts is lining numerals. Now, if you have an awful amount of figures in your body copy, this can become painful real fast.

Hopefully, Open Type features will save the day. You can tell which alternate the Reading System should use for the selectors of your choice.

body {
  font-variant-numeric: oldstyle-nums proportional-nums;
}

Default fonts Reading Systems offer may not ship with those features though, but Minion and Myriad Pro, Iowan Old Style and San Fransisco (which can be accessed by using -apple-system in your font-family), for instance, provide ebook designers with a good set of figure alternates.

It is worth noting that usage might drive the need for better default fonts. In other words, the more people will use open type features, the better the fonts Reading Systems might choose to embed.

See the Pen Easy CSS Win #2: font-variant-numeric by Jiminy Panoz (@JayPanoz) on CodePen.

Feature Query? Probably not | MDN | CanIuse

Use true small capitals

When you’re using font-variant, small capitals are faked by the rendering engine. This means it scales down the capital letters to make small capitals. As a result, they will look like dog shit thin.

So how to enable real small capitals?

.small-caps {
  font-variant: small-caps;
}

You don’t have to change anything! That’s probably the easiest CSS Win ever. But you could use font-variant-caps to make it more readable in your CSS.

Once again, rendering will depend on the font selected by the user but in this case, if small capitals are not available, it will fall back to fake small capitals. It could be worse.

See the Pen Easy CSS Wins #3: font-variant by Jiminy Panoz (@JayPanoz) on CodePen.

Feature Query? Probably not | MDN | CanIuse

Get every block element on the same baseline

This one is not modern by any standard but it appears you can teach young puppies old tricks.

With line-height, there’s a subtle detail you might not be aware of: the behaviour of inherit will change based on the value you’re using.

section {
  line-height: 1.5em; /* or 150% */
}

/* You might need this because of overrides */
section * {
  line-height: inherit;
}

If your value is unitless e.g. 1.5 then the rendering engine will re-compute the value for each child based on its font-size.

If you’re using em or % then the rendering engine will use the computed value of the parent and apply it to its children. In other words, it’s like setting a baseline grid in InDesign.

While it is generally advised to use unitless values because of this difference, it can become an asset if you know in advance that the computed value of the parent will be OK for all its children. This basically means you’d better not have children which font-size is larger than the parent’s line-height.

Easy win for vertical rhythm, the rendering engine takes care of everything.

See the Pen Easy CSS Win #4: line-height by Jiminy Panoz (@JayPanoz) on CodePen.

Feature Query? Nope | MDN

Use the current text color for borders

What if you could retrieve the element’s (text) color for its borders so that they automatically change depending on the reading mode the user has picked?

This actually is possible, and it works everywhere—Yep, even in Kindle and RMSDK.

aside {
  border: 1px solid currentColor;
}

Often called “the first CSS variable”, currentColor basically maps to color. As a consequence, if the Reading System sets the text in white when night mode is enabled, the border will become white.

See the Pen Easy CSS Wins #5: currentColor by Jiminy Panoz (@JayPanoz) on CodePen.

Feature Query? Nope | MDN | CanIuse

Pimp your underlines

While we’re at it, why not applying a color to underlines?

Sometimes you have so many underlines on a “page” that it might disrupt the reading experience. In that case, why not toning down?

a {
  -webkit-text-decoration-color: rgba(0, 0, 0, 0.5);
  text-decoration-color: rgba(0, 0, 0, 0.5);
}

And you can define a specific style too, no more border-bottom hack which becomes a huge mess when the Reading System insists on underlining links.

See the Pen Easy CSS Wins #6: text-decoration by Jiminy Panoz (@JayPanoz) on CodePen.

Feature Query? Probably not | MDN | CanIuse

Vertically-align elements on a page

This last trick is the icing on the #eprdctn cake.

Remember the last time someone asked if it were possible to put the publisher’s logo at the bottom of the titlepage? Yeah you made an image and felt ashamed.

This last trick is the icing on the #eprdctn cake.

You can flex your muscles, folks, because there is a layout module you can use to achieve that.

Let’s say you want to vertically-center an element on one page.

.v-center {
  height: 99vh;
  display: flex;
  align-items: center;
}

BOOM! All your pics and your headings are now vertically-centered, using three lines of CSS. Flexbox manages everything for you.

And now to the titlepage.

.titlepage {
  min-height: 95vh;
  display: flex;
  flex-direction: column;
}

.titlepage .bottom-element {
  margin-top: auto;
  page-break-inside: avoid;
}

End of the layout game, flexbox deals with the vertical margins automagically. Should the user set a huge font-size, the bottom element will just overflow on the next page.

See the Pen Easy CSS Wins #7: flexbox by Jiminy Panoz (@JayPanoz) on CodePen.

By the way, there’s a new layout spec for grids, which is kind of flexbox on steroids, you should definitely take a look.

Feature Query? Yep | MDN | CanIuse

Conclusion

It is important to remind you those one-liners should not be used in a vacuum, you must add them to your existing code, with fallbacks where needed—flexbox, I’m looking at you.

I’ve been using them in production (with feature queries in some cases) for a significant amount of time now, and haven’t any issue to report so far.

Sure, you might still tell yourself it’s not worth it, although it can be implemented in seconds. Once again, usage is important for Reading Systems.

For instance, Amazon is already dealing with a couple of CSS hacks and currentColor in KFX—I can tell, I’m retro-engineering it. So if you’re starting to use Open Type features, they’ll probably add support for that. And the same goes for flexbox.

CSS has come a long way. “It just works” is what I love the most about it today.

Ebooks, your turn.


Jiminy Panoz is a freelancer who has been helping French publishers make the transition to digital for the last five years. In addition to ebook conversion, he has conducted QA audits, managed interactive projects, built custom tools, and designed tailored workflows for his clients. He’s also the creator and maintainer of open-source projects dedicated to ebooks, including the blitz framework.

4 Responses to “Easy CSS Wins”

  1. […] does not support this CSS (though for progressive enhancement, this would be a great place for a feature query). Media queries are another potential solution, but this will double already extensive CSS work […]

  2. Jorge says:

    Wouldn’t it be advisable to add the disclaimer in the CSS for title-page that only iBooks and Google Play Books will display the `.bottom-element` at the bottom of the page?

  3. Jorge says:

    …and ADE ≥4.

  4. Gianmaria delfino says:

    hi I hope so much that someone can help me.
    I have to create an epub where there are many photos and many tables. As for the photos I think I have solved with this command
     img {
    height: auto;
    width: 95%;
    image-break-before: always;
    }
     
    but the problem remains for the tables. In fact, if I look at my epub with the phone, the tables are cut and you see badly. there is a command to make the table responsive based on the device. I report below all the commands that I insert in the main of the css
    if anyone wanted to give me some advice I would be grateful.

    table.main {}
     tr.row {}
     td.cell {}
     div.block {}
     div.paragraph {}
    body {
    -epub-hyphens: auto;
    -webkit-hyphens: auto;
    }
    table {

    border-color: blue;
    border-style: solid;
    border-width: 2px;
    margin-bottom: -4px;
    margin-top: 4px;

    border-collapse: collapse
    }
    th, td {
    padding: 5px;
    text-align: left;
    }
    h1 {
    page-break-before: always;
    -epub-hyphens: none;
    -epub-ruby-position: over;
    -webkit-hyphens: none;

    color: # 0000FF;
    font-family: Sylfaen, serif;
    font-size: 1.5em;
    font-style: normal;
    font-variant: normal;
    font-weight: normal;
    line-height: 1.2;
    margin-bottom: 3px;
    margin-left: 6px;
    margin-right: 6px;
    text-align: left;
    text-decoration: none;
    text-indent: 0px;
    }
    h2 {
    -epub-hyphens: none;
    -epub-ruby-position: over;
    -webkit-hyphens: none;
    color: blue;
    font-family: Sylfaen, serif;
    font-size: 1.2em;
    font-style: normal;
    font-variant: normal;
    font-weight: normal;
    line-height: 1.2;
    margin-bottom: 3px;
    margin-left: 6px;
    margin-right: 6px;
    text-align: left;
    text-decoration: none;
    text-indent: 0px;
    }
    h3 {
    -epub-hyphens: none;
    -epub-ruby-position: over;
    -webkit-hyphens: none;
    color: blue;
    font-family: Sylfaen, serif;
    font-size: 1.2em;

    }
    h4 {
    -epub-hyphens: none;
    -epub-ruby-position: over;
    -webkit-hyphens: none;
    color: blue;
    font-size: 1em

    }

     img {
    height: auto;
    width: 95%;
    image-break-before: always;
    }

    img.cover {
    height: 100%;
    width: auto;
    }