openhtmltopdf icon indicating copy to clipboard operation
openhtmltopdf copied to clipboard

Absolute positioning fails in some common cases

Open stechio opened this issue 3 years ago • 2 comments

I noticed that absolute positioning has a few annoying defects in the way it deals with vertical lengths:

  1. anchoring to page bottom: anchoring an element to page bottom makes it leak to next page (obviously, it should stay entirely on the target page, see test cases 2 and 3 here below)
  2. wrong resolution of relative references to element height: element height in percentage is wrongly resolved (see test case 6 here below)

Test cases

No automated test suite here, just my observations from casual trials (made a bit more systematic to evaluate fringe cases). This is the code chunk used to generate the renderings:
try (OutputStream os = new FileOutputStream(new File("absolute.pdf"))) {
    try (PdfBoxRenderer renderer = new PdfRendererBuilder().withFile(new File("absolute.html"))
            .toStream(os).buildPdfRenderer()) {
        renderer.createPDF();
    }
}

And this is the source HTML body:

<body>
    <div class="element">
        1-Some contents to fill<br />-What?<br /> 2-Some contents to
        fill<br />-What?<br /> 3-Some contents to fill<br />-What?<br />
        4-Some contents to fill<br />-What?<br /> 5-Some contents to
        fill<br />-What?<br /> 6-Some contents to fill<br />-What?<br />
        7-Some contents to fill<br />-What?<br /> 8-Some contents to
        fill<br />-What?<br /> 9-Some contents to fill<br />-What?<br />
        10-Some contents to fill<br />-What?<br /> 11-Some contents to
        fill<br />-What?<br />
    </div>
</body>

NOTE: All the outputs are compared side-by-side with renderings by Chrome/Blink engine (print mode).

1. top-left at page top-left: OK

.element {
    position: absolute;

    left: 0;
    top: 0;
}

absolute_topleft.html.txt

absolute_topleft_ohtp absolute_topleft_chrome

absolute_topleft.pdf

2. bottom-left at page bottom-left: FAILED

The element wrongly leaks down to next page. It seems like a limit condition during the placement of last text line tested true despite the height of its containing div was purposely calculated to make enough room for it.
.element {
    position: absolute;

    left: 0;
    bottom: 0;
}

absolute_bottomleft.html.txt

absolute_bottomleft_ohtp absolute_bottomleft_chrome

absolute_bottomleft.pdf

3. bottom-right at page bottom-right: FAILED

The element wrongly leaks down to next page, same as test case 2.
.element {
    position: absolute;

    right: 0;
    bottom: 0;
}

absolute_bottomright.html.txt

absolute_bottomright_ohtp absolute_bottomright_chrome

absolute_bottomright.pdf

4. top-left at page center: OK

The element leaks down to next page as expected.
.element {
    position: absolute;

    left: 50%;
    top: 50%;
}

absolute_topleft-center.html.txt

absolute_topleft-center_ohtp absolute_topleft-center_chrome

absolute_topleft-center.pdf

5. bottom-right at page center: OK

The element leaks above the page to nowhere as expected.
.element {
    position: absolute;

    right: 50%;
    bottom: 50%;
}

absolute_bottomright-center.html.txt

absolute_bottomright-center_ohtp absolute_bottomright-center_chrome

absolute_bottomright-center.pdf

6. center at page center (transform): FAILED

Wrong element height calculated for vertical translation (element should move upwards by 50% of its height).
.element {
    position: absolute;

    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%)
}

absolute_center.html.txt

absolute_center_ohtp absolute_center_chrome

absolute_center.pdf

7. rotate around center (transform): OK

.element {
    position: absolute;

    left: 50mm;
    top: 50mm;
    transform: rotate(-45deg);
}

absolute_rotate-center.html.txt

absolute_rotate-center_ohtp absolute_rotate-center_chrome

absolute_rotate-center.pdf

8. rotate around top-left (transform): OK

.element {
    position: absolute;

    left: 50mm;
    top: 50mm;
    transform-origin: 0 0;
    transform: rotate(-45deg);
}

absolute_rotate-topleft.html.txt

absolute_rotate-topleft_ohtp absolute_rotate-topleft_chrome

absolute_rotate-topleft.pdf

9. rotate around bottom-right (transform): OK

.element {
    position: absolute;

    left: 50mm;
    top: 50mm;
    transform-origin: 100% 100%;
    transform: rotate(-45deg);
}

absolute_rotate-bottomright.html.txt

absolute_rotate-bottomright_ohtp absolute_rotate-bottomright_chrome

absolute_rotate-bottomright.pdf

10. size relative to page (partial and full): OK

.element {
    position: absolute;

    left: 0;
    top: 0;
    width: 50%;
    height: 50%;
}

absolute_size-relative.html.txt

absolute_size-relative_ohtp absolute_size-relative_chrome

absolute_size-relative.pdf

.element {
    position: absolute;

    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
}

absolute_size-relative-full.html.txt

absolute_size-relative-full_ohtp absolute_size-relative-full_chrome

absolute_size-relative-full.pdf

stechio avatar Mar 13 '21 23:03 stechio

I came across the same issue as described in “6. center at page center (transform)”. Here are a few more observations.

  • Percentage y component parameters to translate seems to be interpreted relative to element width.
  • Parameters to translate (at least the y component) seem to be interpreted as percentage even if absolute values are given.
<!DOCTYPE html>
<html lang="en">
<head>
    <style>
        @page {
            size: 297mm 210mm;
        }
        .box {
            position: relative;
            width: 50mm;
            height: 50mm;
            border: 1pt solid black;
        }
        .label {
            position: absolute;
            left: 50%;
            top: 50%;
            border: 1pt solid red;
            line-height: 1.5em;
        }
        .label.percentage {
            transform: translate(-50%, -50%);
        }
        .label.em-1 {
            transform: translate(-50%, -1.5em);
        }
        .label.em-2 {
            transform: translate(-50%, -50em);
        }
        .label.mm {
            transform: translate(-50%, -5mm);
        }
    </style>
</head>
<body>
<table>
    <tr>
        <td>
            <div class="box">
                <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 50 50">
                    <path stroke="black" stroke-width=".1pt" d="M 0,0 l 50,50 M 0,50 L 50,0" />
                </svg>
                <span class="label percentage">Label</span>
            </div>
        </td>
        <td>
            <div class="box">
                <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 50 50">
                    <path stroke="black" stroke-width=".1pt" d="M 0,0 l 50,50 M 0,50 L 50,0" />
                </svg>
                <span class="label percentage">Long Label</span>
            </div>
        </td>
        <td>
            <div class="box">
                <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 50 50">
                    <path stroke="black" stroke-width=".1pt" d="M 0,0 l 50,50 M 0,50 L 50,0" />
                </svg>
                <span class="label em-1">Long Label</span>
            </div>
        </td>
        <td>
            <div class="box">
                <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 50 50">
                    <path stroke="black" stroke-width=".1pt" d="M 0,0 l 50,50 M 0,50 L 50,0" />
                </svg>
                <span class="label em-2">Long Label</span>
            </div>
        </td>
        <td>
            <div class="box">
                <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 50 50">
                    <path stroke="black" stroke-width=".1pt" d="M 0,0 l 50,50 M 0,50 L 50,0" />
                </svg>
                <span class="label mm">Long Label</span>
            </div>
        </td>
    </tr>
</table>
</body>
</html>

Chrome:

image

Open HTML to PDF:

image

devopsix avatar Nov 29 '21 18:11 devopsix

Hi All, for the issues with position absolute at the bottom(left-bottom, right-bottom) -> Did you fix them?

DoHue97 avatar Mar 03 '23 03:03 DoHue97