Forum Bugs

Different flex orders for spreads

cmahnke
I'm just writing to either confirm, this is a known bug / missing feature, of if I did understanding something wrong.
I have the following CSS fragment:
```
@page :left {
margin-left: 1cm;
margin-right: 1.5cm;

@bottom-left {
content: counter(page);
vertical-align: bottom;
}

article.entry .page .text {
order: 2;
text-align: right;
}

article.entry .page .image {
order: 1;
}
}

@page :right {
margin-left: 1.5cm;
margin-right: 1cm;

@bottom-right {
content: counter(page);
vertical-align: bottom;
}

article.entry .page .text {
order: 1;
text-align: left;
}

article.entry .page .image {
order: 2;
}
}

```
My expectation is that the page number the image part and the text are displayed different on a left and a right spread. From inner side (binding edge) to the outer side the text, then a image and then the page number should appear.

This doesn't work in Prince except for the page number...
markbrown
Hi,

CSS @page rules can declare a limited set of properties and can contain other @-rules related to pages. They don't allow regular CSS rules, so you can't style things in that way based on which side of the spread they are on.

It's possible to include multiple items in the content property value so perhaps you can refer to all of the components here, in the required order? That could be hard to style in the way you want, however, so please let us know if you're still encountering problems.

Mark
cmahnke
Ok, thanks. I'll have look.
But are you sure? This construct is supported by Paged.js. And for me it seemed to be obvious to solve it that way.
markbrown
> But are you sure?

Yes, this construct is not supported in the CSS specification. Refer to the documentation on Paged Media to see what Prince provides.

Generally CSS doesn't work this way because the cascade is resolved prior to layout, so it doesn't know what page each element will be placed on and therefore what style it should get.
cmahnke
Ok, I understand - I suppose that it's then a byproduct of having page / spread sided classes in Paged.js since it's technically just a polyfill on top of a browser. Maybe this could even supposed to be a bug in there ;)
But having things styled / or in this case positioned depending on the on the relation to the binding edge isn't actually rocket science. Is there a example how to do that (independently from the content) in Prince?

Edited by cmahnke

cmahnke
@markbrown: I thought a bit more about it and was asking myself if could be an idea to think about the issue a bit more like media queries. I think that the position of the binding edge is comparable with detection of screen width or orientation. In those use case the (flex) layout works depending on the outcomes of such queries.

Don't get me wrong, I don't ask on Prince specifically here anymore, but in a more general sense. Maybe this can also lead into a proposal to the W3C editors to provide an example how they envisage the use case to be implemented.
David J Prokopetz
If you're willing to do a bit of custom coding, this is something that one of the projects I'm working on is dealing with using Prince's support for multi-pass Javascript. Basically, we have Prince generate the PDF once, inspect the boxes produced by each relevant element to determine what page number it ended up on, apply classes to those elements based on whether that page is a left page or a right page, then re-generate the PDF with these classes in place. Here's a simple example which targets <aside> elements:

Prince.trackBoxes = true;
Prince.registerPostLayoutFunc(addPageClasses);
function addPageClasses() {
	let elems = document.getElementsByTagName('ASIDE');
	for (let i = 0; i < elems.length; i++) {
		let elem = elems[i];
		let boxes = elem.getPrinceBoxes();
		if (boxes.length == 1) {
			if (boxes[0].pageNum % 2 == 0) {
				elem.classList.add('on-left-page');
			} else {
				elem.classList.add('on-right-page');
			}
		}
	}
}


This code would be placed in an external .js file, then applied either via the "JavaScript (JS)" pane of the Prince graphical UI, or via the --script option on the command line.

(Note that this example explicitly checks whether an element has more than one box to ensure it's only applying these classes to non-page-spanning elements; I don't know whether that's something you need to worry about in your use case. This check can be omitted if you only care about whether an element starts on a left or right page, regardless of whether it spans multiple pages. The modulo operator also assumes a document that reads from left to right, and that page 1 is a right-facing page; you may need to flip that conditional around if that's not the case for you.)
markbrown
> But having things styled / or in this case positioned depending on the on the relation to the binding edge isn't actually rocket science.

The challenge is in defining what is supposed to happen in the context of the full CSS cascade. For example, what happens if the styling of something on a left page causes it to end up on a right page? Did the author intend those styling rules to still apply?

> Maybe this can also lead into a proposal to the W3C editors to provide an example how they envisage the use case to be implemented.

See the containment module for how the CSS working group are tackling the general problem. This spec is aimed at allowing CSS rules to depend on aspects of layout and previously computed styles, while avoiding problems like the one above.

For the time being, there are some "logical" properties and values that can help managing spreads in specific cases, such as 'margin-inside' and 'float: inside'.
cmahnke
Thanks all for your replies.
I've added a comment to the CSS bug tracker:
https://github.com/w3c/csswg-drafts/issues/3780#issuecomment-3567968462

I'm not sure if anybody will read this, since the last comment on this is from 2019 (6 years ago). But my hot take on the issue is: There is no such thing as modern typesetting using CSS until this isn't easily possible ;)
markbrown
> But my hot take on the issue is: There is no such thing as modern typesetting using CSS until this isn't easily possible ;)

That's not unreasonable :-)

For more flexibility in styling you can try taking elements from the document, which is from the above link. Here's one example that uses different elements for left and right pages, which allows them to be styled separately:

<style>
@page:left {
    @bottom-left {
        content: element(left-footer);
    }
}
@page:right {
    @bottom-right {
        content: element(right-footer);
    }
}
.footer {
    display: flex;
    width: 50%;
}
.footer > * {
    flex-grow: 1;
}
.footer .pagenum {
    content: "Page " counter(page);
}
.left.footer {
    position: running(left-footer);
    flex-direction: row-reverse;
}
.right.footer {
    position: running(right-footer);
}
.break {
    page-break-after: always;
}
</style>
<div class="left footer">
left page
<img src="../adhoc/logo.jpg">
<div class="pagenum"></div>
</div>
<div class="right footer">
right page
<img src="../adhoc/logo.jpg">
<div class="pagenum"></div>
</div>
<h1>Normal text</h1>
<div class="break"></div>
<h1>Normal text</h1>
<div class="break"></div>
<h1>Normal text</h1>
<div class="break"></div>
<h1>Normal text</h1>