Kozea / WeasyPrint

The awesome document factory
https://weasyprint.org
BSD 3-Clause "New" or "Revised" License
7.03k stars 668 forks source link

Margins, borders and padding break column layout #555

Closed vikeen closed 6 years ago

vikeen commented 6 years ago

Background I have a web application that lets users create design PDFs. In this application, we provide the user a WYSIWYG editor in conjunction with a draft-js rich text editor.

In order to "mirror" the web applications editor content, I save off each page as a div to be rendered by my backend.

Example:

[
"<div class=\"page page--two-col page--odd\">...<div class=\"footnote\"></div><div class=\"page-number\">1</div></div>",
"<div class=\"page page--two-col page--even\">...<div class=\"footnote\"></div><div class=\"page-number\">2</div></div>"]

Description

When I render the html output in a browser it looks fine. Notice how the top and bottom of the page fit nicely with a 0.75in border around it.

screen shot 2017-12-31 at 8 30 47 pm

However, when this html is rendered by weasyprint the margins of the page get messed up. The top of the page has some blank space and the bottom looks like it's running off the page.

screen shot 2017-12-31 at 8 07 08 pm

HTML and CSS

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>The Forlorn Swamp</title>
    <link rel="stylesheet" href="/static/adventures/stylesheets/base.css"/>
    <style>
        .page {
            background-image: url('/static/images/themes/dnd-phb/background.png');
        }

        #Cover {
            background-image: url('https://s3.amazonaws.com/rpgauthor/production/users/1/images/2013f44d-1abd-45ab-bdd9-64076bf62659.png');
        }

        .footnote:before {
            content: 'The Forlorn Swamp';
        }
    </style>

    <link rel="stylesheet" href="/static/stylesheets/themes/dnd-5e-phb_theme.css"/>

<body class="theme--dnd-5e-phb">

<section id="Cover">
    <div id="TitleContainer">
        <h1 id="Title">The Forlorn Swamp</h1>
        <p id="Author">vikeen</p>
        <cite id="PoweredBy">
            <img src="/static/images/logo-full.png" alt="Powered By: RPG Author"/>
        </cite>
    </div>
</section>
<div class="page page--two-col page--odd"><h1>lorem ipsumlorem&nbsp;</h1>
<p>ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsum</p>
<h1>lorem&nbsp;</h1>
<p>ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem&nbsp;</p>
<p>ipsumlorem ipsumlorem ipsumlorem ipsumlorem&nbsp;</p>
<p>ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsum</p>
<p>lorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsum</p>
<h3>lorem ipsumlorem&nbsp;</h3>
<p><br></p>
<p>ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem&nbsp;</p>
<p>ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsum</p>
<p>lorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem&nbsp;</p><div class="footnote"></div><div class="page-number">1</div></div><div class="page page--two-col page--even"><h1><strong>lorem ipsumlorem&nbsp;</strong></h1>
<p>ipsuumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsum</p>
<h3><strong>lorem ipsumlorem&nbsp;</strong></h3>
<p>ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ips ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorempsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem umlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem umlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem ipsumlorem 
<p><br></p><div class="footnote"></div><div class="page-number">2</div></div>
</body>
</html>
body, html {
    margin: 0 !important;
    padding: 0 !important;
    color: #333333;
    font: normal 14px / 20px "Helvetica Neue", Helvetica, Arial, sans-serif;
}

*, *:before, *:after {
    box-sizing: border-box !important;
}

/*
 * Page
 ========================================================================== */

@page {
    size: 8.5in 11in !important;
    bleed: 0 !important;
    padding: 0 !important;
    margin: 0 !important;
}

.page {
    width: 8.5in !important;
    height: 11in !important;
    padding: 0.75in !important;
    background-position: center;
    background-size: 8.5in 11in !important;
    background-repeat: no-repeat;
    text-align: left;
    page-break-before: always;
    page-break-after: always;
    position: relative;

}

.page--two-col {
    column-count: 2;
    column-gap: 10mm;
    column-fill: auto;
}

/*
 * Cover
 ========================================================================== */

#Cover {
    padding: 0.75in 0 0.75in 0.75in;
    background-position: center;
    background-size: 8.5in 11in;
    background-repeat: no-repeat;
    margin: 0;
    height: 11in;
    width: 8.5in;
    position: relative;
}

#TitleContainer {
    padding: 20px;
    background: rgba(0, 0, 0, 0.75);
}

#Title {
    font-size: 2.5rem;
    line-height: 2.5rem;
    color: white;
    font-family: Tahoma, Geneva, Kalimati, sans-serif;
}

#Author {
    color: white;
}

#PoweredBy {
    position: absolute;
    bottom: 34mm;
    left: 0.75in;
}

#PoweredBy img {
    width: 200px;
}

figure {
    margin: 0;
}

img {
    max-width: 100%;
}

/* Headings
 ========================================================================== */
h1,
h2,
h3 {
    margin: 0 0 15px 0;
    font-family: Tahoma, Geneva, Kalimati, sans-serif;
    font-weight: normal;
}

/*
 * Margins
 */
* + h1,
* + h2,
* + h3 {
    margin-top: 25px;
}

/*
 * Sizes
 */
h1 {
    font-size: 36px;
    line-height: 42px;
}

h2 {
    font-size: 24px;
    line-height: 30px;
}

h3 {
    font-size: 18px;
    line-height: 24px;
}

.theme--dnd-5e-phb p,
.theme--dnd-5e-phb .paragraph {
    margin-top: 1em;
    margin-bottom: 1em;
}

/* ============================================================
 *
 * Editor
 *
 *
 * ============================================================ */
.theme--dnd-5e-phb,
#EditorContentWrapper.theme--dnd-5e-phb {
    font-family: BookSanity;
    font-size: 12px;
    color: #000000;
    line-height: 16px;
}

.theme--dnd-5e-phb #EditorContent {
    border-bottom: none;
}

.theme--dnd-5e-phb .footnote {
    position: absolute;
    left: auto;
    right: 80px;
    bottom: 32px;
    z-index: 150;
    width: 200px;
    font-size: 12px;
    color: #c9ad6a;
    text-align: right;
}

.theme--dnd-5e-phb .page-number {
    position: absolute;
    left: auto;
    right: 2px;
    bottom: 22px;
    width: 50px;
    font-size: 12px;
    color: #c9ad6a;
    text-align: center;
}

/* ============================================================
 *
 * Page
 *
 * 1. support frontend editor for now
 * ============================================================ */
.theme--dnd-5e-phb.page:after,
.theme--dnd-5e-phb .page:after {
    content: "";
    position: absolute;
    bottom: 0;
    left: 0;
    z-index: 100;
    height: 50px;
    width: 100%;
    background-image: url("/static/images/themes/dnd-phb/footer.png");
    background-size: cover;
}

.theme--dnd-5e-phb.page.page--even:after,
.theme--dnd-5e-phb .page.page--even:after {
    transform: scaleX(-1);
}

.theme--dnd-5e-phb.page.page--even .footnote,
.theme--dnd-5e-phb .page.page--even .footnote {
    left: 80px;
    text-align: left;
}

.theme--dnd-5e-phb.page.page--even .page-number,
.theme--dnd-5e-phb .page.page--even .page-number {
    left: 2px;
    right: auto;
}

/* ============================================================
 *
 * Headings
 *
 * ============================================================ */
.theme--dnd-5e-phb h1,
.theme--dnd-5e-phb h2,
.theme--dnd-5e-phb h3 {
    margin-top: .2em;
    margin-bottom: .2em;
    font-family: MrJeeves;
    font-weight: 800;
    color: #58180D;
}

.theme--dnd-5e-phb h1 {
    font-size: 24pt;
}

.theme--dnd-5e-phb h2 {
    font-size: 20pt;
}

.theme--dnd-5e-phb h3 {
    font-size: 15pt;
    border-bottom: 2px solid #c9ad6a;
}

/* ============================================================
 *
 * Prose
 *
 * ============================================================ */

.theme--dnd-5e-phb .prose {
    margin: 20px 0;
    padding: 5px 10px;
    background-color: #faf7ea;
    font-family: ScalySans;
    border: 2px solid #58180D;
    border-top: none;
    border-bottom: none;
    box-shadow: 0 0 6px #faf7ea;
}

/* ============================================================
 *
 * Note
 *
 * ============================================================ */

.theme--dnd-5e-phb .note {
    margin: 20px 0;
    font-family: ScalySans;
    box-sizing: border-box;
    padding: 5px 10px;
    background-color: #e0e5c1;
    border: 2px solid #000000;
    border-left: none;
    border-right: none;
    box-shadow: 1px 4px 14px #888;
}

/* ============================================================
 *
 * Table
 *
 * ============================================================ */
.theme--dnd-5e-phb table {
    margin: 20px 0;
    width: 100%;
    font-size: 8.5pt;
    padding-left: 0;
    padding-right: 0;
}

.theme--dnd-5e-phb caption {
    color: #000000;
    font-family: ScalySansSmallCaps;
    font-size: 11pt;
    font-weight: bold;
    border: none;
    padding: 0;
    text-align: left;
}

.theme--dnd-5e-phb tbody tr:nth-child(odd) {
    background-color: #e0e5c1;
}

.theme--dnd-5e-phb td,
.theme--dnd-5e-phb th {
    text-align: center;
}

.theme--dnd-5e-phb td:first-child,
.theme--dnd-5e-phb th:first-child {
    text-align: left;
}

The issue probably lies with how I'm trying to "reset" the printed page and use my page div. What do you think?

liZe commented 6 years ago

Hi!

There are multiple problems and solutions to your problem, but the main problem is that column layout is experimental in WeasyPrint and it's obviously buggy with padding and margins. I'll try to fix it during the next day.

vikeen commented 6 years ago

@liZe, thank you. Is there anything I can help with?

liZe commented 6 years ago

@liZe, thank you. Is there anything I can help with?

Yes! I've committed 7361966 that should fix your problem, you can try and tell me if it's better this way.

Column layout is currently experimental, related code needs some love :heart:. It's also really really slow, especially when blocks around columns have extra spacing. Reporting real life bugs is really helpful! If you're interested in improving this feature and have some Python + CSS skills, you can take a look at the columns_layout in blocks.py.

vikeen commented 6 years ago

@liZe, thanks. Checking the commit out now.

Weasyprint is one of a few critical services to my application. I would be more than happy to give you a hand improving it. As you said, performance is a bit of an issue, but I can overcome that with async rending and emailing the pdf when it's done. That isn't a big deal for me at the moment.

I'll take a look at the block.py and spend some time learning.

vikeen commented 6 years ago

@liZe, worked like a charm! - adventure.pdf

Thanks for the quick turn around! The ability to specify exact page dimensions while controlling all aspects of the page html gives me immense control.