webcompat / web-bugs

A place to report bugs on websites.
https://webcompat.com
Mozilla Public License 2.0
747 stars 67 forks source link

toebes.com - Print preview issues #139133

Closed toebes closed 4 months ago

toebes commented 4 months ago

URL: https://toebes.com/codebusters/Samples/firefox_toebes_printing_example.html

Browser / Version: Firefox 128.0 Operating System: Windows 10 Tested Another Browser: Yes Chrome

Problem type: Something else Description: Printing doesn't format correctly Steps to Reproduce: This is an extract of a sample case of the set of tools for Science Olympiad Code Busters (https://toebes.com/codebusters/) that generate and print tests.

When we print the tests using other browsers (Chrome, Edge) we are able to get consistent formatting and output such that the page fits on the sheet of paper and text is rendered cleanly. However, in the past year or so we have received complaints from Firefox users that it doesn't format and print well.

I have run through the W3c validator to ensure that the HTML is valid.

If you load the file in Firefox and then print, you will notice several issues: 1) Firefox generates 5 pages instead of the 3 that it should. 2) The names of participants table ends up wider than the page. 3) The Score table on the first page is off the right hand edge of the page. 4) The header for the second page (Page 1) is on a page by itself 5) The footer for the second page (Page 1) is near the top of the third page 6) The text for the timed question appears too high on the page 7) The text for the timed question is in a slightly larger font such that it wraps early. 8) Similar problems are on the last page, with the header appearing nominally in the correct place 9) The footer for the last page is on a page by itself.

Note that I have experimented with multiple options for the print scale and margins, for purposes of comparison I set the margins to .5" all around and forced the scale to 100% in all three browsers.

I've uploaded an image showing a side by side comparison of the rendered first page.

View the screenshot Screenshot
Browser Configuration
  • None

From webcompat.com with ❤️

toebes commented 4 months ago

If you need me to generate a smaller example showing individual problems, don't hesitate to ask.

softvision-raul-bucata commented 4 months ago

Thanks for the report. I was able to reproduce in Firefox Nightly, and Firefox Release.

Reproducible issues are moved to our Bugzilla component; please see: https://bugzilla.mozilla.org/show_bug.cgi?id=1907822

Closing as moved.

[qa_29/2024]

dholbert commented 2 months ago

Hi @toebes - I'm only seeing one difference (aside from font subtleties) between Firefox and Chrome, and it's a case where Firefox is honoring a forced pagebreak that the content is requesting, and Chrome is ignoring it (near the top of page 2).

I'm not entirely sure which behavior is correct -- I filed https://bugzilla.mozilla.org/show_bug.cgi?id=1917145 on it with a reduced testcase -- but in the meantime I think you can avoid that difference by removing pagebreak from this element in your testcase:

                    <div class="question pagebreak">

With that addressed, I'm not seeing any other substantial differences. Would you mind retesting and seeing if you're still seeing differences between Firefox and Chrome? And if you are, maybe share PDFs and/or screenshots to highlight the issues? Thanks!

toebes commented 2 months ago

Remember that this is a reduced case. I didn't want to burden you with the 20 page version.

Removing the pagebreak breaks lots of cases and is there to ensure that everything is paginated correctly. In theory the pagebreak should be innocuous when you are already at the start of a page.

To show the differences, I generated this from your test case: here's the Firefox version which ends up as 5 pages and if you look at the first page, the table is cut off to the right. Firefox-Bug.pdf

Here's the Chrome version which is only 3 pages (as expected). Chrome-OK.pdf

Please let me know what else I can provide. If you want to see the extreme case you can go to:

toebes.com/codebusters/TestManage.html?importURL=Samples/NC_C_Regional_1_2024.json Then click on Test Packet and then the Print button. It should be a 20 page document with the first page not being numbered and all subsequent pages numbered 1-19. With Firefox you get 26 pages with the last page numbered as Page 12.

dholbert commented 2 months ago

Remember that this is a reduced case. I didn't want to burden you with the 20 page version.

Removing the pagebreak breaks lots of cases and is there to ensure that everything is paginated correctly.

Sure -- I wasn't suggesting you remove all requested pagebreaks. :) Let me go into a bit more detail about why that one is troublesome...

In this particular case, the testcase is essentially requesting two pagebreaks in a row. Specifically, right now the content on the original reduced testcase looks like this:

<div class="page">
  <div class="head">2024 Science Olympiad National Codebusters Division B</div>
  <div class="headright">Team Number:_B_________</div>
  <div class="foot">Page 1</div>
  <div class="question pagebreak">

And here, both the page and question pagebreak elements have page-break-before:always:


            .page {
[...]
                page-break-before: always;
[...]
            }
[...]
            .pagebreak {
                page-break-before: always;
            }

This means the content is essentially requesting a page-break before each of those elements. That's why the first bit of content (notably the head/headright) end on on one new page, and then the question itself ends up on another page, in Firefox and Safari at least.

I think technically Chrome is correct because the second forced-pagebreak here is supposed to be propagated to its parent since it's the first child (or the first non-abspos child, at least), which means the parent is essentially requesting two pagebreaks at the exact same spot (once explicitly, one propagated from the child), which results in a single break. At some point Firefox and Safari will implement those page-break propagation rules (maybe in this Firefox bug -- forced page-breaks in Firefox are a bit hairy and are something we'd like to rework, but we probably won't get to it in the next few months at least).

In the meantime, if you're looking for ways to work around this issue, you might try avoiding this sort of "double-page-break-request" where the content has two page-break-before:always elements in a row and is relying on the browser to coalesce them into a single pagebreak.

Hopefully that makes sense and might be workable, if you're interested in ideas for workarounds. Thanks again for the bug report!

dholbert commented 2 months ago

To show the differences, I generated this from your test case: here's the Firefox version which ends up as 5 pages and if you look at the first page, the table is cut off to the right. Firefox-Bug.pdf

Thanks for sharing this -- so for me, in order to get that "cut-off-on-the-right" issue (and in order to get a 5th page), I have to activate a non-default setting -- I have to choose "Scale: 100%" in the Firefox print dialog** (in the "More Settings" expandable section).

Could you check if you have that setting toggled? If so -- I'll bet things improve for you with the "Scale: Fit to Page Width", as shown here: image (that's the default setting, in both Firefox and Chrome -- "Fit to Page Width" in Firefox, and "Scale:Default" in Chrome.)

dholbert commented 2 months ago

If you want to see the extreme case you can go to:

toebes.com/codebusters/TestManage.html?importURL=Samples/NC_C_Regional_1_2024.json Then click on Test Packet and then the Print button. It should be a 20 page document with the first page not being numbered and all subsequent pages numbered 1-19. With Firefox you get 26 pages with the last page numbered as Page 12.

Thanks. So, good news -- analyzing that extreme case, I can get Firefox to match Chrome with fairly-minimal workarounds. Details:

Here's the Chrome output that I get from this document: chrome.pdf

Here's the output that I get with Firefox with the above two CSS styles added to the stylesheet (to override some of the styles that are otherwise requesting double-pagebreaks that Firefox doesn't currently coalesce together): firefox-with-workaround-css.pdf

dholbert commented 2 months ago

(side note: given that "Scale: Fit to Page Width" and "Scale: 100%" produce different results, that's actually a good clue that the page here is using some explicitly-sized content that's wider than the available space on the page. That's why stuff gets clipped when you ask for 100% scale, and why it gets scaled down to avoid clipping when you use the default "Fit to Page Width".

Specifically looking at the clipped elements on the first page in the reduced testcase, we have this for the "nameline" (the section where "Team numb[...]" gets clipped):

table.nameline {
[...]
  width: 50rem;

And we have this defining the size of the scoring table below that (note that there are 5 th elements, so we've got 5*11 = 55rem).

        table.testscores th {
[...]
            width: 11rem;
        }

1rem is 16px here, so 50rem is 50*16px = 800px and 55rem is 55*16px = 880px here.

And in Firefox at least, 800px is slightly wider than the available width on a US Letter page with 0.5in-wide margins. Here's a testcase to visualize this: data:text/html,<div style="width:800px; height: 100px; border: 5px solid black; box-sizing: border-box">

Chrome has an interesting behavior where they seem to force "fit to page width" even if you try to choose a large scale factor. But if you try reducing the scale factor, you can see that ~92% scale is where 800px exactly fills the page area (with default margins), and they seem to refuse to scale up beyond that (including to 100%) even if you ask them to.

dholbert commented 2 months ago

So, bottom line, this is my diagnosis of what's going on:

dholbert commented 2 months ago

@toebes I hope the above helps, particularly my notes with good news on the extreme case. Let me know if you have further questions about what's going on here; otherwise I'm hopeful that it's not too tricky to work around this in the meantime (e.g. using CSS similar to my [...]: initial !important rules quoted above -- or rather removing the CSS declarations that those ones are stomping on), should you choose to do so.

toebes commented 2 months ago

Some great observations! Thank you.

I've fixed the width issues on that score table (thank you for pointing that out) and it works "better" as long as they specify scale to width. Scale to 100% still doesn't behave as expected (you can see the page number on the subsequent page). I hope to get that pushed out to production after a bit more testing.

One thing that I did want to point out is that the .page style has a page-break-inside: avoid; which might have some bearing on bug 1772396 being applied to this case.

   .page {
        page-break-inside: avoid;
        padding: 0.5in 0in 0.25in 0in !important;
        position: relative;
        width: 100%;
        height: 100%;
        page-break-after: always;
        page-break-before: always;
    }
dholbert commented 2 months ago

it works "better" as long as they specify scale to width. Scale to 100% still doesn't behave as expected

That's good news, though if you're still seeing a difference between those configurations in Firefox, then that's an indication that you've still got some element with too large of a specified width to actually fit on the page. If everything is fitting horizontally, then "Fit to Page Width" and "scale: 100%" would produce exactly the same layout.

(Note: Chrome has a bug in these scale settings, meaning their "scale:100%" layout can't be relied on -- so if you're seeing good results from them with scale:100%, don't trust it too much -- it might not remain good after they fix that bug. :) )

you can see the page number on the subsequent page

That indicates that your positioning for these page numbers is too large for them to fit in the available space on the page. (You happen to be getting lucky that "fit to page width" is having to scale stuff down, such that it happens to scale the heights enough to make stuff fit vertically too.)

Looking at your original testcase, I can see that this is trivially happening with the "Page 2" text that you mentioned was being pushed to its own page when printed at 100% scale.

Here's the relevant CSS from your testcase:

  @page {
    margin: 0.5cm;
  }
  .page .foot {
    height: 0.25in;
[...]
    position: absolute;
[...]
    top: 10.5in;
}
.page .foot {
  margin: 0.7em auto;

Those various offsets are placing the .foot element beyond the bottom of the printable area on the page, which is why the text overflows onto another page.

Specifically, for a US Letter sheet of paper:

To avoid that overflowing page number, you need to use smaller top value there -- 10.5 is too tall and (when combined with the margins) is basically pushing that text off the page. (You might find things are more robust if you use bottom-based indexing -- but that requires your .page elements to be sized to precisely fill the actual page, which might lead to further rabbit-holes/whack-a-moles.)

One thing that I did want to point out is that the .page style has a page-break-inside: avoid;

Yup, I saw that -- that turns out not to be relevant here. Quoting the spec, "...a forced break value effectively overrides any avoid break value that also applies at that break point." https://drafts.csswg.org/css-break-3/#forced-breaks

("page-break-inside: avoid" also can't save you in cases where the content is simply positioned at too far of an explicit offset to be able to fit on the same page, as is the case with the .page .foot CSS discussed above in this comment. :) In that situation, a page-break is unavoidable, unless there are additional scale factors coming into play.)