Search code examples
htmlcssprintingmedia-queries

CSS marginless printing of multiple pages. Where is this tiny additional height coming from?


Live Demo, sorry for the messy CSS, I've been trying out a bunch of things.

I am trying to "print" PDF files using the browser print dialog. Each file contains 4 pages in the DIN lang format plus 3mm on each side.

In the HTML below, each .page represents a physical page with dimensions as defined above. The printable area is the exact DIN lang dimensions (105mm x 210mm) centered on the page.

For some reason, no matter what I try, I cannot get the .page element to fit exactly into what's defined in @page, there's a tiny bit of additional height that becomes more pronounced as I add pages. Adding page-break-after: always; reveals however, that the first page is already a bit too tall (as there is a seemingly blank page following it).

enter image description here


Solution

  • After testing multiple configurations and searching for hours on SO and on other websites, I found a solution, not the perfect one I admit, but the best available right now.

    In your print media query, just put the following:

    @media print {
      body {
         border: 1px solid transparent;
      }
    }
    

    Complete code to run:

    window.print();
    /* apply a natural box layout model to all elements, but allowing components to change */
    html {
      box-sizing: border-box;
    }
    *,
    *:before,
    *:after {
      box-sizing: inherit;
    }
    
    html,
    body {
      padding: 0;
      margin: 0;
      height: fit-content;
    }
    
    .print-area {
      background-color: #ffffff;
      width: 105mm;
      height: 210mm;
      font-size: 12pt;
      display: none;
    }
    
    .page {
      display: block;
      height: 216mm;
      width: 111mm;
      justify-content: center;
      align-items: center;
      overflow: hidden;
      font-size: 0;
      margin: 0;
      padding: 0;
      border: 0;
      box-shadow: 0;
      /* page-break-after: always; */
    }
    
    #page-one {
      background-color: rgb(206, 135, 208);
      top: 0;
      left: 0;
    }
    #page-two {
      background-color: rgb(78, 73, 212);
    }
    #page-three {
      background-color: rgb(232, 227, 151);
    }
    #page-four {
      background-color: rgb(118, 196, 124);
    }
    
    @media print {
      body {
        border: 1px solid transparent;
      }
    }
    
    @page {
      size: 111mm 216mm;
      margin: 0 !important;
    }
    <div class="page" id="page-one">
      <div class="print-area">
        <h1>Hello from page 1</h1>
      </div>
    </div>
    <div class="page" id="page-two">
      <div class="print-area">
        <h1>Hello from page 2</h1>
      </div>
    </div>
    <div class="page" id="page-three">
      <div class="print-area">
        <h1>Hello from page 3</h1>
      </div>
    </div>
    <div class="page" id="page-four">
      <div class="print-area">
        <h1>Hello from page 4</h1>
      </div>
    </div>

    Undoubtedly this is a weird solution. However, this ensures that the (final) green slide won't overflow and thus you won't have a blank page at the end.