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).
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.
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.
Related Topics
Align Child Elements of Different Blocks
What Are the Differences Between Flex-Basis and Width
I Do Not Want to Inherit the Child Opacity from the Parent in Css
Bootstrap Align Navbar Items to the Right
How to Select the "Last Child" With a Specific Class Name in Css
Css Force Image Resize and Keep Aspect Ratio
Difference Between "Word-Break: Break-All" Versus "Word-Wrap: Break-Word" in Css
Fixed Position But Relative to Container
Margin on Child Element Moves Parent Element
Can CSS Detect the Number of Children an Element Has
Using CSS For a Fade-In Effect on Page Load
How to Remove the Border Highlight on an Input Text Element
Can Media Queries Resize Based on a Div Element Instead of the Screen
Hiding the Scroll Bar on an HTML Page
Custom CSS Scrollbar For Firefox
Safari: Media Query Not Firing At the Expected Width