How to Make a HTML Page in A4 Paper Size Page(S)

How to make a HTML Page in A4 paper size page(s)?

Ages ago, in November 2005, AlistApart.com published an article on how they published a book using nothing but HTML and CSS. See: http://alistapart.com/article/boom

Here's an excerpt of that article:

CSS2 has a notion of paged media (think sheets of paper), as opposed to continuous media (think scrollbars). Style sheets can set the size of pages and their margins. Page templates can be given names and elements can state which named page they want to be printed on. Also, elements in the source document can force page breaks. Here is a snippet from the style sheet we used:

@page {
size: 7in 9.25in;
margin: 27mm 16mm 27mm 16mm;
}

Having a US-based publisher, we were given the page size in inches. We, being Europeans, continued with metric measurements. CSS accepts both.

After setting the up the page size and margin, we needed to make sure there are page breaks in the right places. The following excerpt shows how page breaks are generated after chapters and appendices:

div.chapter, div.appendix {
page-break-after: always;
}

Also, we used CSS2 to declare named pages:

div.titlepage {
page: blank;
}

That is, the title page is to be printed on pages with the name “blank.” CSS2 described the concept of named pages, but their value only becomes apparent when headers and footers are available.

Anyway…

Since you want to print A4, you'll need different dimensions of course:

@page {
size: 21cm 29.7cm;
margin: 30mm 45mm 30mm 45mm;
/* change the margins as you want them to be. */
}

The article dives into things like setting page-breaks, etc. so you might want to read that completely.

In your case, the trick is to create the print CSS first. Most modern browsers (>2005) support zooming and will already be able to display a website based on the print CSS.

Now, you'll want to make the web display look a bit different and adapt the whole design to fit most browsers too (including the old, pre 2005 ones). For that, you'll have to create a web CSS file or override some parts of your print CSS. When creating CSS for web display, remember that a browser can have ANY size (think: “mobile” up to “big-screen TVs”). Meaning: for the web CSS your page-width and image-width is best set using a variable width (%) to support as many display devices and web-browsing clients as possible.

EDIT (26-02-2015)

Today, I happened to stumble upon another, more recent article at SmashingMagazine which also dives into designing for print with HTML and CSS… just in case you could use yet-another-tutorial.

EDIT (30-10-2018)

It has been brought to my attention in that size is not valid CSS3, which is indeed correct — I merely repeated the code quoted in the article which (as noted) was good old CSS2 (which makes sense when you look at the year the article and this answer were first published). Anyway, here's the valid CSS3 code for your copy-and-paste convenience:

@media print {
body{
width: 21cm;
height: 29.7cm;
margin: 30mm 45mm 30mm 45mm;
/* change the margins as you want them to be. */
}
}

In case you think you really need pixels (you should actually avoid using pixels), you will have to take care of choosing the correct DPI for printing:

  • 72 dpi (web) = 595 X 842 pixels
  • 300 dpi (print) = 2480 X 3508 pixels
  • 600 dpi (high quality print) = 4960 X 7016 pixels

Yet, I would avoid the hassle and simply use cm (centimeters) or mm (millimeters) for sizing as that avoids rendering glitches that can arise depending on which client you use.

Simulate A4 page in HTML

HTML assumes that the screen is 96 DPI, or that 1 pixel is 1/96 of an inch.

On hardware with a very high resolution, it uses the concept of logical pixels, which are units that are close to 1/96 of an inch, and each of which consists of multiple device pixels. This is true for printers, but also for phones and other devices with high res screens.

So, if you want a rectangle the same size an an A4 (21 × 29.7 cm), you should use 794 × 1122 pixels, or in CSS, width:794px; height:1122px. But you can also use physical units, width:21cm; height:29.7cm if you don't want to worry about these logical pixels.

CSS to set A4 paper size

I looked into this a bit more and the actual problem seems to be with assigning initial to page width under the print media rule. It seems like in Chrome width: initial on the .page element results in scaling of the page content if no specific length value is defined for width on any of the parent elements (width: initial in this case resolves to width: auto ... but actually any value smaller than the size defined under the @page rule causes the same issue).

So not only the content is now too long for the page (by about 2cm), but also the page padding will be slightly more than the initial 2cm and so on (it seems to render the contents under width: auto to the width of ~196mm and then scale the whole content up to the width of 210mm ~ but strangely exactly the same scaling factor is applied to contents with any width smaller than 210mm).

To fix this problem you can simply in the print media rule assign the A4 paper width and hight to html, body or directly to .page and in this case avoid the initial keyword.

DEMO

@page {
size: A4;
margin: 0;
}
@media print {
html, body {
width: 210mm;
height: 297mm;
}
/* ... the rest of the rules ... */
}

This seems to keep everything else the way it is in your original CSS and fix the problem in Chrome (tested in different versions of Chrome under Windows, OS X and Ubuntu).

A4 page like layout in html

Your 2nd problem:

You have to set the body margin and padding to zero. You also need to remove box shadow, margin, width and height from the A4 class in order to print multiple pages.

.A4 {
background: white;
width: 21cm;
height: 29.7cm;
display: block;
margin: 0 auto;
padding: 10px 25px;
margin-bottom: 0.5cm;
box-shadow: 0 0 0.5cm rgba(0, 0, 0, 0.5);
overflow-y: scroll;
box-sizing: border-box;
}

@media print {
.page-break {
display: block;
page-break-before: always;
}

size: A4 portrait;
}

@media print {
body {
margin: 0;
padding: 0;
}

.A4 {
box-shadow: none;
margin: 0;
width: auto;
height: auto;
}

.noprint {
display: none;
}

.enable-print {
display: block;
}
}

Your first problem:

You could try to create a pagination feature by calculating the scrollheight, and keep removing elements from the pages untill the scollheight is smaller than the page itself.

Example: https://jsfiddle.net/tk8rwnav/31/

var max_pages = 100;
var page_count = 0;

function snipMe() {
page_count++;
if (page_count > max_pages) {
return;
}
var long = $(this)[0].scrollHeight - Math.ceil($(this).innerHeight());
var children = $(this).children().toArray();
var removed = [];
while (long > 0 && children.length > 0) {
var child = children.pop();
$(child).detach();
removed.unshift(child);
long = $(this)[0].scrollHeight - Math.ceil($(this).innerHeight());
}
if (removed.length > 0) {
var a4 = $('<div class="A4"></div>');
a4.append(removed);
$(this).after(a4);
snipMe.call(a4[0]);
}
}

$(document).ready(function() {
$('.A4').each(function() {
snipMe.call(this);
});
});

This example breaks on every element. The paragraphs don't break on words, but you can implement this, but that will get complicated very fast.

how to print whole HTML page as A4

Try tweaking those margin values in the CSS snippet you used. Start from:

@page {
size: 7in 9.25in;
margin: 0mm 0mm 0mm 0mm;
}

… and increase those "0mm" values until you're happy, i.e. 1mm, 2mm, etc.

Those 4 values (all currently 0mm in my example) represent the top margin, right margin, bottom margin and left margin of the printed page, in order.

So if you only want to increase the margin from the bottom of the page, you'd change the third 0mm in that line.

HTML+CSS A4 page with automatic page breaks

If I understand your question correctly, you might want to use page margins instead of the padding on body.
Make sure to set the page margins to the default value in the print dialog. If you don't, your custom page margins (as specified in CSS) will be overridden and don't have an effect.

Your stylesheet would look something like this:

@page {
size: A4 portrait;
margin: 20mm;
}

body {
width: 210mm;
height: 297mm;
}

Specifying size on html element and showing page in A4 paper format

I had some similiar challenges recently when designing a print stylesheet for my resume :-)

Yes, it is possible. Although you might need to tinker a bit before it works.
(I worked with the Print preview of my web browser for now - but the resulting PDF will be inaccessible and loose all semantics).

Some resources to get you started:

  • https://www.smashingmagazine.com/2015/01/designing-for-print-with-css/
  • https://www.sitepoint.com/css-printer-friendly-pages/
  • https://www.smashingmagazine.com/2018/05/print-stylesheets-in-2018/

Regarding your second question: I'd go with a <div class="wrapper"></div> as only child of <body> and use a reset stylesheet. I met too many quirks otherwise.

If you want to learn more, Geoff Graham wrote about it a couple years ago.

print from html pages in A4

Try using the CSS media attribute to specify different CSS for printing.

You also need to bear in mind that each browser will implement printing in its own way (just like CSS rendering).

How to split HTML Page in A4 size in Angular 9

It is all about dividing the given content to fit into the give page size.

We can create a component that will handle the dividing functionality for us. here is a StackBlitz Demo.

And here is a brief explanation.

Use the ContentChildren decorator to observe the change in content. every time the content changes we will run the page creation logic.

import {
AfterContentInit,
AfterViewInit,
Component,
ContentChildren,
ElementRef,
Input,
OnInit,
QueryList,
ViewChild
} from "@angular/core";

@Component({
selector: "app-paginated-view",
templateUrl: "paginated-view.component.html",
styleUrls: ["paginated-view.component.scss"]
})
export class PaginatedViewComponent implements AfterViewInit {
@Input() pageSize: "A3" | "A4" = "A4";

@ViewChild("paginatedView") paginatedView: ElementRef<HTMLDivElement>;

@ViewChild("contentWrapper") contentWrapper: ElementRef<HTMLDivElement>;

@ContentChildren("pageContent", { read: ElementRef }) elements: QueryList<
ElementRef
>;

constructor() {}

ngAfterViewInit(): void {
this.updatePages();

// when ever childs updated call the updatePagesfunction
this.elements.changes.subscribe(el => {
this.updatePages();
});
}

updatePages(): void {
// clear paginated view
this.paginatedView.nativeElement.innerHTML = "";

// get a new page and add it to the paginated view
let page = this.getNewPage();
this.paginatedView.nativeElement.appendChild(page);

let lastEl: HTMLElement;
// add content childrens to the page one by one
this.elements.forEach(elRef => {
const el = elRef.nativeElement;

// if the content child height is larger than the size of the page
// then do not add it to the page
if (el.clientHeight > page.clientHeight) {
return;
}
// add the child to the page
page.appendChild(el);

// after adding the child if the page scroll hight becomes larger than the page height
// then get a new page and append the child to the new page
if (page.scrollHeight > page.clientHeight) {
page = this.getNewPage();
this.paginatedView.nativeElement.appendChild(page);
page.appendChild(el);
}
lastEl = el;
});

//bring the element in to view port
lastEl.scrollIntoView({ behavior: "smooth", block: "nearest" });
}

getNewPage(): HTMLDivElement {
const page = document.createElement("div");
page.classList.add("page");
page.classList.add(this.pageSize);
return page;
}
}

We can use this component in an application like this.

<app-paginated-view [pageSize]="'A4'">
<h1 #pageContent>Hello World!!</h1>
<p #pageContent>This content will be displayed in an A4 size page</p>
</app-paginated-view>

We have to provide the template variable #pageContent so that we can select them using @ContentChildren in our PaginatedViewComponent.

Note that we are using native dom APIs here to change the dom structure. it will only move the dom node from one place to another so if you have any event listener added or have any property binding to the content children they will work as it is.

Edit:
I have also updated your stackblitz
https://stackblitz.com/edit/angular-ivy-zjf8rv



Related Topics



Leave a reply



Submit