Sunday, January 15, 2012

Media Queries for formatting Poetry on Kindle and EPUB

What a tangled web we weave! Amazon wants to maintain support for its legacy ereaders, we all want to support different size ereaders, but nobody supports the code the same way. What to do? One solution is to use media queries, something I've been meaning to explain for months.

A media query lets you create multiple sets of CSS (just what you want to do, right?) and then apply the most appropriate set automatically according to the ereader the ebook is opened in. So, in a single ebook file, there would be various choices of CSS, perhaps one best suited for old legacy Kindles, another for KF8, another for really small screens like iPhones, and yet another for the full-color 9.7” iPad. The ebook would adapt to its environment, giving each user the best possible experience.

That's the theory anyway.

Of course, there are a couple of caveats. Media queries only affect CSS, not HTML, which limits to some degree what can be changed for those ereaders that don't understand a lot of CSS (yes, I'm talking about clunky old mobi). And not all devices of the same screen size support CSS the same way. Ebook designers, like web designers before them, will continue to make multiple versions of the same ebook until the code is standardized. (And don't expect ebook reader manufacturers to adhere to standards without a lot of prodding.)

But media queries do help. Let's see how they work.

Suppose you want to format poetry in your ebook. Poetry is tricky because each line's length must somehow be respected, even in a screen where the line does not fit. The typical solution is to divide each line of poetry into multiple lines, with the 2nd and subsequent lines indented below the first. No matter how narrow the ereader screen, the reader will still be able to identify each line of poetry as a unit.

Let's look at Whitman's O Captain! My Captain! on the Kindle App in a landscape-oriented iPad. (All of these screenshots are from Kindle Previewer, just so I don't have to copy them to a bunch of different devices.) Notice that no matter how short, each line of poetry is displayed on its own line. Poetry doesn't reflow. It's hard to tell from this screenshot, but note that Kindle automatically indents lines of text 40px for Kindle and Kindle for iPad and iPhone, but not for Kindle Fire!

Poetry, little formatting

If we turn the iPad sideways, or make the text bigger, or both, the lines suddenly don't fit. Not only that, the automatic first line indent that Amazon adds makes poetry look particularly bad. It starts being hard to tell what is the second half of a long line, and what is an individual shorter line.

Poetry, vertical

Here's what it looks like on a legacy Kindle (what I'm calling "old mobi"):
Poetry, Kindle (old mobi)

Not pretty.

And here's what it looks like on Kindle Fire. Remember that Kindle Fire doesn't have an automatic first-line indent:

Poetry, Kindle Fire

The combination of automatic full justification with no first-line indent and no adjustment for the poetry lines looks particularly bad on the Kindle Fire. It's just a sea of text.

What's the solution? The convention for formatting poetry is to indent the part of the line that doesn't fit. What layout folks call a hanging indent.

You can do this pretty easily with CSS. Add a left margin of say, 2em, which will push the whole line over and then add a negative text-indent of -2em so that the first line starts at the flush left as usual. In this way, each line of poetry will start at the left margin, but any part of the line that overflows will be displayed indented on the second and subsequent lines. Here's the CSS code:

p {line-height: 1;padding:0;margin:0}
p.firstline {margin-top:2em; margin-left:2em; text-indent: -2em;}
p.line {margin-left:2em; text-indent: -2em;}

And here's what it looks like on the Kindle Fire:

Poetry- KindleFire formatting

I'd certainly want to adjust the general formatting a bit, but now the lines of poetry are at least inteligible.

But if you open it up with a legacy Kindle, it looks pretty bad:

Poetry - bad Kindle formatting

And it looks equally bad on Kindle for iPad:

Poetry, Kindle for iPad, bad formatting

What's going on?? It turns out that old mobi handles values for text-indent in a very strange way. If you don't set a text-indent value, old mobi automatically indents 40px. If you set a positive text-indent, it will use that instead. (You can use px or em, but if you use em, only whole numbers will work.) But if you set a negative text-indent, it actually creates a hanging indent, with the first line flush left and the second and subsequent indented as much as the absolute value of text-indent. Go figure. That's weird and unexpected, but if you set the left margin at the same time, it all gets mucked up and the details are way too boring to explain. Trust me, you don't want to go there.

To create a hanging indent on old mobi, you use just a negative text-indent, but no left margin. It shouldn't work, but it does.

h1 {text-align: left}
p {line-height: 1} 
p.firstline {margin-top:20px;text-indent:-40px}
p.line {text-indent:-40px}

And here's what it looks like on a legacy Kindle:

Old Kindle poetry

That's fine, but look at the same code on a Kindle Fire:

Poetry bad formatting Kindle Fire

Because of those negative-indents and the lack of an automatic left margin, or whatever hack old mobi used, now our text is cut off. Unacceptable.

So, Kindle Fire and decent EPUB ereaders that support CSS like iBooks want a left margin and a negative text-indent, but old mobi can't handle that combination, being able to use only the negative text-indent.

The answer is to serve different CSS to different ereaders, by way of a media query. I'm going to show you how to do it in an internal stylesheet but the same principles would hold in an external stylesheet.

First, create a regular stylesheet with no media attribute that will contain the styles that should be applied to all versions of the ebook.


<style type="text/css">
    h1 {text-align: left}
    p {line-height: 1;padding:0;margin:0}
</style>


Next, create a second stylesheet with media="not amzn-mobi" in the opening style tag. The stylesheet should include all of the styles that should apply to all ereaders except legacy Kindle. Amazon says you should use media="kf8" but that's just because they imagine a world where all ereaders are either Kindle Fire or legacy Kindle. Let's just say that most people's worlds are bigger than that.

<style type="text/css" media="not amzn-mobi">
    p.firstline {margin-top:2em; margin-left:2em; text-indent: -2em;}
    p.line {margin-left:2em; text-indent: -2em;}
</style>


Finally, create a stylesheet just for legacy Kindle, adding media="amzn-mobi" to the opening style tag.

<style type="text/css" media="amzn-mobi">
    p.firstline {margin-top:20px;text-indent:-40px}
    p.line {text-indent:-40px}
</style>


Here's what it looks like on Kindle Fire:

Kindle Fire Poetry - good

And here's what the very same file looks like on a legacy Kindle:

Old Kindle Poetry -good

Success!

And just in case you were worrying, here's what the EPUB file looks like in iBooks on the iPad:

Poetry in iBooks

Indeed, it looks fine, because iBooks' support of CSS is pretty good. 

A technical note. There was some concern that you couldn't serve different indents to Kindle Fire and to legacy Kindle because the legacy Kindle code uses the width attribute (in a bizarre way) in the HTML, and not the CSS. But the technique described above works because KindleGen converts the CSS in a good EPUB into the weird, hackish old mobi code—complete with width tag—that legacy Kindles love, but creates "KF8" code for the new Kindle Fire, which, as I mentioned Thursday, is virtually the same as the original EPUB. And EPUB readers will get the original, good, EPUB file. So everyone's happy.

Except designers who have to do twice the work. Think standards don't matter? Think again.

One final note. I've been saying that the KF8 files that KindleGen generates from the original EPUB are practically identical to that original EPUB. That's true only for the CSS that KF8 supports. I haven't tested it extensively, but I suspect KindleGen will just ignore the CSS it doesn't support. And I have yet to determine (nor have seen elsewhere) just how well Kindle Fire supports CSS in the first place. I need a couple more days!


20 comments:

  1. Thank you for this information, Liz. Very helpful.

    ReplyDelete
  2. Liz, I think you're being overly generous in what you call "acceptable." Personally, I wouldn't apply that term to poetry with any justified lines or end-of-line hyphenation. In fact, I wouldn't even try to put serious poetry on any ereader that didn't give the designer control over those elements -- unless it was by way of something like SVG images.

    There's only so much I'm willing to sacrifice on the altar of ebooks!

    ReplyDelete
  3. Thanks Liz,
    Great information, as always.

    ReplyDelete
  4. Hi Aaron:

    My iPhone is 2" wide and I can't change that. So, I prefer the text to wrap then be displayed too small to read. We can't have everything.

    Some, I'm sure, would continue to read at least certain poetry in print. But not all.

    ReplyDelete
  5. So where is IDPF in all this? You'd think that the lessons of HTML would serve to make things easier this time around. On the web it used to be a nightmare coding around IE6 weirdness but then the web standards project came along and things are much better now. Not perfect but better.

    ReplyDelete
  6. Wow, this is awesome. I'm about to publish a poetry ebook and got the hanging indents working beautifully in EPUB but not for Kindle. I could make it look great for the new Kindles and lousy for the others or forgo the hanging indents altogether. Just yesterday I was wishing there was a way to serve reader-specific css files. Then I came upon your site today and your solution works quiet well. Thank you, a thousand times, thank you for this post.

    ReplyDelete
  7. When I used

    <div style="padding-left: 2em; text-indent: -2em;"> </div>

    as the poetry line wrapper, it seemed to work well on both NOOK Touch and Kindle Touch. But I will try your media query approach.

    Thanks.

    ReplyDelete
  8. I've had bad luck with media queries. Last one I tried choked ADE--it didn't parse the CSS file at all.

    ReplyDelete
  9. There are a lot of threads on a lot of forums asking questions which are answered by this post. Nice one.

    ReplyDelete
  10. Hi Liz,

    This is definitely helpful. What about situations where we want to feed one rule to iBooks and a different one to the Kindle Fire?

    Its seems that:
    "not amzn-mobi"

    is also read by the ipad unfortunately. It would be better if we had a syntax that was Kindle specific also.

    If you have a solution I'd love to hear it.

    ReplyDelete
    Replies
    1. Here's a cool reference for different media queries (beyond the not amzn-mobi if needed). It's totally for web developers so it's all about that kind of stuff.

      http://css-tricks.com/snippets/css/media-queries-for-standard-devices/

      Delete
  11. This is really great info, thanks.

    Another wrinkle here is that if you set a left margin for verse (as I do when it is quoted in a prose work), Kindle ignores text-indent. There doesn't seem to be any way to create a hanging indent for paragraphs that already have a margin.

    ReplyDelete
    Replies
    1. @Peter. This article might help: http://www.pigsgourdsandwikis.com/2012/02/multiple-indents.html

      Delete
  12. Rather than multiple stylesheets wouldn't something like @media only screen and (min-device-width: 768px), amzn-mobi, amzn-kf8 {definitions} be easier to maintain (example supposes particular styles for iPad and Kindles).

    ReplyDelete
  13. awesome! i'll definitely be bookmarking this page for help. thanks for the post. =)

    ReplyDelete
  14. My problem is I haven't a clue what this all means! Can you recommend a service that could format a poetry book (with pictures) that would suit most digital readers? I've searched extensively, but nobody seems to handle poetry. (Well, actually it's a story in verse, so there are no chapters or headings, but several pictures.)

    ReplyDelete
  15. I am not able to follow the technical code you propose, but I am very happy to see the results. Congratulations! As a reader of professional texts, I am very frustrated since much technical information on reports (pdf usually) on the web is not adapted to be read in eReaders. Information on tables, figures and plots is incomplete or unreadable when transferred to an EPUB format. I understand your work should help in that field.

    ReplyDelete
  16. Thanks, Liz. Very helpful.

    I'm curious if you or anyone has had any experience using anything other than amzn-mobi or amzn-kf8 in the media query and the result on other ereaders. I've had success using those two, with everything rendering perfectly across devices (kindles, ipad, kobo, sony, nook) but as soon as I use anything other than those two, even using 'not amzn-mobi', causes ADE to ignore all CSS. This baffles me, since it *should* only ignore anything in the media query... right?

    ReplyDelete

More of my books