[gcpm] custom pages and page lists

This message is a writup of the possible solutions to a problem we
have disussed for a while. In its simplest form, the issue is: how do
we set different headers/footers on the first page and subsequent
pages in a chapter? For example, given this markup:

  <div class="chapter">
    <h1>The beginning</h1>
    ....
  </div>

  <div class="chapter">
    <h1>The end</h1>
    ....
  </div>

How does one make the first page of each chapter have no headers,
while the remaining pages have the chapter title as header? This is
called use case 1 (UC1)

Another common use case is how to achieve the same formatting without
having 'div' elements to rely on:

  <h1>The beginning</h1>
    ....
  <h1>The end</h1>
    ....

This is called use case 2 (UC2)

Finally, we need to make sure that the 'page' property can continue to
support one of the use cases in CSS2, namely to put an element on a
separate page with a page break before and after:

  @page rotated {size: landscape}
  table { page: rotated }

This is called use case 3 (UC3)

In this message, I will sketch several solutions and evaluate them
wrt. the three use cases above.

------------------------------------------------
OPTION A

The latest Editor's copy of the GCPM draft contains a simple solution
using named strings:

  http://www.w3.org/Style/Group/css3-src/css3-gcpm/Overview.html#named


UC1:

  @page { @top-center { content: string(title, first-except) }}
  h1 { string-set: title content(); page-break: before }

That is, the keyword "first-except" specifies that the header should
not appear on the first page.

UC2:

  @page { @top-center { content: string(title, first-except) }}
  h1 { string-set: title content(); page-break: before }

The code is the same as UC1, the 'div' element is simply not used.

UC3:

There is no change in the 'page' property so the same code can be
used:

  @page rotated {size: landscape}
  table { page: rotated }

Option A, however is quite simple and does not allow the first
page to have (say) different margins from the subsequent pages. 


------------------------------------------------
OPTION B

Page Groups is also described in the (alas, unreleased) GCPM draft:

  http://dev.w3.org/csswg/css3-gcpm/Overview.html#page-groups

UC1:

  @page chapter { 
    @top-center { content: string(title) }
  }
  @page chapter:first { 
    @top-center { content: none }
  }
  div.chapter { page: chapter; page-group: start }
  h1 { string-set: title content() }

This solution is based on using the 'page' property as well as a new
'page-group' property. The 'page' property remains inherited. A page
break is generated before every 'start' page.

UC2:

Not possible -- this code would, e.g., result in h1 elements
being alone on a page:

  @page chapter { 
    @top-center { content: string(title) }
  }
  @page chapter:first { 
    @top-center { content: none }
  }
  div.chapter {  }
  h1 { page: chapter; page-group: start; string-set: title content() }


UC3:

No change, this code would still work:

  @page rotated { size: landscape }
  table { page: rotated }


------------------------------------------------
OPTION C

Named page lists:

  http://dev.w3.org/csswg/css3-gcpm/Overview.html#named2

Further, option C makes some assumptions:

 - the 'page' property no longer inherits

 - every element with a non-auto value on 'page' start on a new page,
   so there would e.g. be a page break between these two div elements:

     div.capter { page: chapter }
     <div class="chapter">...</div>
     <div class="chapter">...</div>

  - if 'page' has more than one value, it will not generate any page
    breaks between/after the pages in the list.


UC1:

  @page chapter { 
    @top-center { content: string(title) }
  }
  @page chapter-start { 
    @top-center { content: none }
  }
  div.chapter { page: chapter-start chapter }
  h1 { string-set: title content() }

UC2:

  @page chapter { 
    @top-center { content: string(title) }
  }
  @page chapter-start { 
    @top-center { content: none }
  }
  h1 { page: chapter-start chapter; string-set: title content() }


UC3:

No change, this code would still work:

  @page rotated { size: landscape }
  table { page: rotated }


------------------------------------------------
OPTION D

If the inheritance of 'page' is changed, another option opens up. 

UC1:

  @page chapter { 
    @top-center { content: string(title) }
  }
  @page chapter:first { 
    @top-center { content: none }
  }
  div.chapter { page: chapter }
  h1 { string-set: title content() }

That is, the ':first' pseudo-class can be applied to any named page --
not just the first page of the document.


UC2:

No, this doesn't work as 'h1' would be on a page by itself:

  @page chapter { 
    @top-center { content: string(title) }
  }
  @page chapter:first { 
    @top-center { content: none }
  }
  h1 { page: chapter; string-set: title content() }


UC3:

No change, this code would still work:

  @page rotated { size: landscape }
  table { page: rotated }


------------------------------------------------
OPTION E

Bert has sketched another solution:

  http://lists.w3.org/Archives/Public/www-style/2008Jul/0425.html

UC1:

  @page chapter-start { 
    next-page: chapter;
    @top-center { content: string(title) }
  }
  @page chapter { 
    next-page: chapter;
    @top-center { content: none }
  }
  div.chapter { page-break-before: chapter-start }
  h1 { string-set: title content() }

UC2:

  @page chapter-start { 
    next-page: chapter;
    @top-center { content: string(title) }
  }
  @page chapter { 
    next-page: chapter;
    @top-center { content: none }
  }
  h1 { page-break-before: chapter-start; string-set: title content() }


UC3:

Unclear, as there is no 'page' property.

This proposal avoids using any new properties one the element, but
relies on a new 'next-page' property in the page context. (Also,
there's a new 'page-side' property to replace :left and :right).

------------------------------------------------

Here are my personal favorites:

I like the syntax of Option D the best (as it requires no new syntax),
however UC2 doesn't work.

Option A is a simple solution that works with all use cases, but it
has limited functionality.

Option C, including the stated assumptions, addresses all use cases in
a familiar syntax.

In sum, I'd probably argue to keep Option A along with Option C.

-h&kon
              Håkon Wium Lie                          CTO °þe®ª
howcome@opera.com                  http://people.opera.com/howcome

Received on Tuesday, 19 August 2008 03:14:29 UTC