Search code examples
cssflying-saucercss-paged-media

Changing CSS running element counter style after few pages


I am generating PDF document using FlyingSaucer with page numbers in running header. What I am trying to achieve is to be able to change style of counter applied to running element used for header.

Since the CSS is applied by FlyingSaucer I cannot use javascript.

Example html:

<body>
    <div id="right-header"/>
    <div id="title-page"></div> <!-- page i -->
    <div id="toc-page"></div> <!-- page ii -->
    <div id="content"> <!-- counter reseted -->
        <div id="chapter1"> 
        <!-- page i ( should display 1 instead of i )-->
        <!-- page ii ( should display 2 )-->
        </div>
        <div id="chapter1"> 
        <!-- page iii ( should display 3 )-->
        <!-- page iv ( should display 4 )-->
        </div>
    </div> 
</body>

css:

#right-header {
    display: block;
    text-align: right;
    position: running(right-header);
}

#right-header:after {
    content: counter(page, lower-roman)
}

@page:right {
    @top-right {
        content: element(right-header);
    }
}

This piece of css correctly applies headers to the whole document after

<div class="right-header"></div>

is placed.

I am trying to start my document with above page styling ( lower-roman ) and after specific place in my document - let's say I would like to either change content of right-header or replace @page content with different running element for the rest of the document with styling set to decimal numbers.

I know that FlyingSaucer has limited CSS3 support but I cannot find any solution ( not restricted to only FlyingSaucer) for such problem.

Content of running header can be changed without effect on previous headers as FlyingSaucer allows to reset the counter at any point of the document using css rule.

-fs-page-sequence: start;

and change is visible only after that point.

So my current status is that I have pages numbered with lower-roman i-iv ( for title page, TOC etc. ) and then reset back to i and increment till the end of document. All I need to do is to change

#right-header:after {
    content: counter(page, lower-roman)
}

to

.right-header:after {
    content: counter(page)
}

or switch displayed running element to the new one.

Another solution I have tried which adds another possibility to solve this problem:

<div id="right-header">
    <div id="before"/>
    <div id="forcontent"/>
</div>

 

#forcontent {
    display: none <!-- initially not displayed for a few first pages -->
}
#before:after {
    content: counter(page, lower-roman)
}

#forcontent:after {
    content: counter(page)
}

with this code I think the solution would be to enable #forcontent and disable #before at the beginning of #content. I have tried working with ~ selector but it doesn't work for changing preceding elements.

Does anybody know how this could be achieved or could point me to different solutions I could try?


Solution

  • While working on something else I found that FlyingSaucer supports css3 named pages (https://www.w3.org/TR/css3-page/#using-named-pages) which allow elements to have different @page definition with another elements set as running headers and footers.

    Below is short example how different styling for "introduction" pages can be achieved using this method.

    html:

    <html>
        ...
        <div id="introduction-right-header-placeholder">...</div>
        <div id="content-right-header-placeholder">...</div>
        <div class="introduction">
            <!-- these pages will have roman letters as page numbers -->
            ...
        </div> 
    
        <div class="content">
            <!-- these pages will have decimal page numbers -->
            ...
        </div> 
        ...
    </html>
    

    css:

    #introduction-right-header-placeholder {
        text-align: right;
        position: running(introduction-right-header);
    }
    
    #introduction-right-header-placeholder:after {
        content: counter(page, lower-roman)
    }
    
    #content-right-header-placeholder {
        text-align: right;
        position: running(content-right-header);
    }
    
    #content-right-header-placeholder:after {
        content: counter(page);
    }
    
    .introduction {
        page: introduction-page;
    }
    
    .content{
        page: content-page;
    }
    
    @page introduction:right {
        @top-right {
            content: element(introduction-right-header);
        }
    }
    
    @page content:right {
        @top-right {
            content: element(content-right-header);
        }
    }
    

    This example shows how to add differently styled page numbers in FlyingSaucer for right side pages ( I removed left side to reduce amount of code ).