Forum How do I...?

Justify all lines except the last with forced line breaks

iznogood
Hi

I'm working with a poetry book that shall be published both as epub and pdf. For the pdf edition I hope to go for a traditional fixed layout, but need a more re-flowable layout for the epub since it's impossible to design epubs for fixed screen dimensions.

In my html file, I have a lot of verses in this form:
<p>This is line 1 and it's indented<br/>
This is line 2<br/>
This is line 3 and it's a long line</br>
Line 4</p>


The <p> is indented, and I would like to generate a pdf output that justifies all the lines except the last one.

With this css code:
p{
	margin:0;
	text-indent:1.2em;
	text-align:justify;
}

I get the layout I want except for the justification of the lines. It's the <br/> that's the culprit.

With this css code:
p{
	margin:0;
	text-indent:1.2em;
	text-align:justify;
	text-align-last:justify;
	text-justify:distribute;
}

I get justification on all lines, including the last one. The last one is a lot shorter than the other lines, and full justification on this line looks rediculous. Is there a way to get full justification on all lines except the last one using just css? I'm going to re-use the html code for the epub and publication on net, so I would like not to change the html code dramatically.
jim_albright
I suggest you change your markup to:
<p class="line1">This is line 1</p>
<p class="line2">This is line 2</p>
<p class="line3">This is line 3 and it is really a long line yes it is.</p>
<p class="doxology">This is line doxology as in the end of a book of Psalms: Amen and Amen</p>

in the css
This is actual functioning CSS for formatting poetry in NIV Bible. It is probably a lot more complicated than you need since you don't have to work with verse numbers nor a mixture of paragraphs with included poetry. Having justified poetry is strange. But having a long line wrap to a constant position is doable. enjoy.


.Line1 { margin-left: 60pt; text-indent: -48pt; text-align: left;}
.Line1 > .Verse_Number:first-of-type{ width:10pt ; text-align: right; display:inline-block; margin-right: 2pt ; }
.Line2 { margin-left: 60pt; text-indent: -36pt; text-align: left; }
.Line2 > .Verse_Number:first-of-type{; width:10pt ; text-align: right; display:inline-block; margin-right: 2pt ;}
.Line3 { margin-left: 60pt; text-indent: -24pt; text-align: left; }
.Line3 > .Verse_Number:first-of-type{ ; width:10pt ; text-align: right; display:inline-block; margin-right: 2pt ;}
.List_Item1 > .Verse_Number:first-of-type { text-indent: -18pt; ; width:2em ;; text-align: right}
.List_Item1 { text-indent: -12pt; padding-left: 18pt; list-style-type: none; page-break-inside: auto; }
.List_Item1_Additional { margin 0pt ; padding-left: 18pt; }
.List_Item2 { margin-top: 0; text-indent: 0; padding-left: 24pt; list-style-type: none; page-break-inside: auto; page-break-before: avoid ;}

/*
.Line1 > .Verse_Number.single_digit:first-of-type:before {content: "\2007\2007"}
.Line1 > .Verse_Number.double_digit:first-of-type:before {content: "\2007"}
.Line2 > .Verse_Number.single_digit:first-of-type:before {content: "\2007\2007"}
.Line2 > .Verse_Number.double_digit:first-of-type:before {content: "\2007"}
.List_Item1 > .Verse_Number.single_digit:first-of-type:before {content: "\2007"}
.List_Item1 > .Verse_Number.double_digit:first-of-type:before {content: ""}
.Item1 + p:not([class='Item1']) { margin-top: 11pt; / * add space after poetry * / }
.Line1 { page-break-after:avoid; margin-left: 60pt; text-indent: -48pt; text-align: left;}
.Line1 + .Paragraph { margin-top: 11pt; / * add space after poetry * / }
.Line1 + .Paragraph_Continued { margin-top: 11pt; / * add space after poetry * / }
.Line1 > .Verse_Number.single_digit:first-of-type:before {content: "\2007\2007"}
.Line1 > .Verse_Number.double_digit:first-of-type:before {content: "\2007"}
.Line1 > .Verse_Number:first-of-type{text-indent: -60pt; float:left; }
.Line2 { margin-left: 60pt; text-indent: -36pt; text-align: left; }
.Line2 + .Paragraph { margin-top: 11pt; / * add space after poetry * / }
.Line2 + .Paragraph_Continued { margin-top: 11pt; / * add space after poetry * / }
.Line2 > .Verse_Number.single_digit:first-of-type:before {content: "\2007\2007"}
.Line2 > .Verse_Number.double_digit:first-of-type:before {content: "\2007"}
.Line2 > .Verse_Number:first-of-type{text-indent: -60pt; float:left; }
.Line3 { margin-left: 60pt; text-indent: -24pt; text-align: left; }
.Line3 > .Verse_Number:first-of-type{text-indent: -60pt; float:left; }

Jim Albright
Wycliffe Bible Translators

  1. Line1_example_2.gif19.4 kB
  2. Line2_example_2.gif19.4 kB
  3. Line3_example_2.gif9.7 kB
mikeday
If instead of using <br/> to separate lines you wrapped each line in a <div> element, then you could use the :last-of-type CSS selector to match the last line and control its justification.
tofi86
With prince 11, this problem still exists.

If I have user generated text which should be rendered with
text-align: justify; text-align-last: left;
and the paragraph contains a
<br/>
(or any other block element), this specific line which contains the
<br/>
element is left-aligned. When making books, this is never desired!

So at the moment I use XSLT in a pre-process to split those paragraphs into multiple paragraphs and apply different styling based on attributes.

But in the name of all book publishers, please change this behaviour with the next Prince release! Thanks! :)
pjrm
Note that the current css-text-3 specification specifically says that text-align-last is to apply to lines that end with a "forced line break".

If the goal for inserting <br> elements is just to influence the line breaking within a paragraph but without wanting the reader of the book to see that you've forcefully ended a line there, and if using Prince for Books, then you can style that paragraph (or just the <br> elements that you don't want to look forced) with prince-forced-breaks:full, in which case Prince will try to make those breaks look unforced, and they don't count as "forced breaks" for purposes of text-align-last.

Often, the reason for wanting to influence line breaks is actually to avoid breaking up a certain word or phrase. If that's the case, then consider achieving that goal directly by wrapping that word or phrase with an inline element and asking Prince not to break that element, whether by forcing it with white-space:nowrap (see below), or by using prince-wrap-inside. The advantage over forcing breaks with br is that it won't be affected as badly by subsequent changes to the content or styling that would make those forced breaks no longer appropriate.

If you are not using Prince for Books, but it's still for styling a normal-looking paragraph of prose, then one possible alternative would be that instead of using a <br> element to force a break, you instead create a span around text where you don't want a line break, and style that span with white-space: nowrap. E.g.
<style>
nobr { white-space: nowrap; }
p { text-align: justify; text-indent: 1em; }
</style>
<p><nobr>This is the first line, so text-indent applies.</nobr>
<nobr>This is line 2, of similar length to line 1.</nobr>
<nobr>Being prose, all lines are of similar length,</nobr>
<nobr>except the last.</nobr></p>


The reason I say "If it's for normal-looking prose" is that this white-space:nowrap trick relies on the spans being of appropriate length for the paragraph: if two nobr spans were less than half of the content width of the p element, then they might get placed together on the same line. If you really wanted an extremely spaced out line, then you might need to force it using word-spacing.
twantzen
I would strongly vote for my feature request about -prince-forced-breaks, but for a workaround, I tested this out and it works for PrinceXML (14.1):
<style>
    p { 
        text-align: justify; 
        text-indent: 1em; 
    }
    .lineBreak {
        letter-spacing: 99999em;
    }
    .lineBreak:after {
        content: "\0020";
    }</style>
<p>This is the first line, so text-indent applies.<span class="lineBreak"></span>
This is line 2, of similar length to line 1.<span class="lineBreak"></span>
Being prose, all lines are of similar length,<span class="lineBreak"></span>
except the last.</p>


Tobias
  1. testing.html0.6 kB
  2. testing.pdf22.4 kB

Edited by twantzen

howcome
How about:
<html>
<style>
div { text-align: justify }
div.justify { text-align-last: justify }
</style>
<div class=justify>This is line 1 and it's indented</div>
<div class=justify>This is line 2</div>
<div class=justify>This is line 3 and it's a long line</div>
<div>Line 4</div>
  1. foo.html0.3 kB
  2. foo.pdf17.1 kB
twantzen
@howcome , yes, that’s totally fine for print output, but semantically sometimes not the best option for the incoming data (we recieve our content via database).
If a <br /> is semantically the best option, I can simply replace all <br />s with RegEx with my suggested <span class="lineBreak"></span>. Changing tags on block level for the <div>s is a bigger challenge.

Tobias
howcome
Semantically, it might make more sense to have small microformat to represent stanzas and lines. E.g.:
<html>
<style>
div.line { text-align: justify; text-align-last: justify }
div.line:last-child { text-align-last: initial }
</style>
<div class=stanza>
  <div class=line>This is line 1 and it's indented</div>
  <div class=line>This is line 2</div>
  <div class=line>This is line 3 and it's a long line</div>
  <div class=line>Line 4</div>
</div>
  1. bar.html0.3 kB
  2. bar.pdf17.1 kB
twantzen
@howcome , in this usecase (poems), I’m totally with you.

We are handling rather long texts, where people want to define, where exactly the text should wrap to the next line in order to avoid hyphenation of a word. There I'd prefer the “<span> approach”.

Edited by twantzen