Lucascvs
Lucascvs

Reputation: 31

Css border smaller than 4px @300dpi using wkhtmltopdf

I'm generating an auto-filled PDF, cloned from an inDesign layout that I was given. This layout uses tables, with 0.5pt borders on tables. Those borders aren't rendered properly when using wkhtmltopdf, since webkit doesn't want lines thinner than 0.8pt/1px.

I tried to use workarounds such as 0.8px (no display at 100% on screen, correct height at 400%), directly 0.5pt, or using 1px box shadows, none of this seem to give me the correct thickness, since sub-1px or sub-0.8pt lines aren't rendered into my PDF file, and 1px box-shadows give me the same issue.

Edit: The command I'm using to generate my PDF: wkhtmltopdf.exe -T 0 -B 0 -L 0 -R 0 --dpi 300 --disable-smart-shrinking <input> <output>

I'm not against an optical workaround. Here's a preview of my issue:

Thank you in advance!

Upvotes: 1

Views: 2765

Answers (4)

Scott Norman
Scott Norman

Reputation: 21

My workaround for the time-being is to use box-shadow instead of border.

box-shadow: 1px 1px black

It's not perfect, but it is the only work-around I have found that avoids the thick borders in tables when converting html to pdf using wkhtmltopdf.

Upvotes: 1

user3033467
user3033467

Reputation: 1188

Setting a body width in CSS did it for me.

I had to set a width of 800px at 100 dpi to get 1px borders

Upvotes: 0

Mike Skinner
Mike Skinner

Reputation: 341

The workaround I found was to scale all pixel values in the document by 2, then apply a css transform to scale it all down again to the correct size.

//original

body{ width: 210mm; }
p{ font-size:12px; }
.bordered{ border-width: 0.5px; ) //didn't work

//hacked

body{ width: 420mm; transform: scale(0.5); transform-origin: 0 0; }
p{ font-size:24px; }
.bordered{ border-width: 1px; }

The rendering engine must parse all values and round to the nearest integer before it performs the css transforms.

Obviously this works if you need a 0.5px line (whatever that means in the real world of print!). More granular control would require a larger scale ratio, which I haven't tried yet.

In theory it'd be fairly easy to set the body font size to some multiple of a normal value, then use rems to make the css easier on the eye and quicker to scale.

Edit:

I can confirm that scaling by 10x and then transforming down works really well to produce borders / lines accurate to 0.1px. Here's some scss:

$final_width: 210mm;
$final_height: 297mm;
$scale_factor: 10;

$page_width: #{$scale_factor * $final_width};
$page_height: #{$scale_factor * $final_height};

html{
    padding: 0;
    margin: 0;
    font-size: #{$scale_factor*10}px;
}

body{
    transform: scale(#{1/$scale_factor});
    transform-origin: 0 0;
    width: $page_width;
    height: $page_height;
    margin: 0;
    margin-bottom: -$page_height;

...

The define all your layout sizes in rems: e.g. border: 0.05rem (0.5px end result, as 1rem = 10px in this case)

Upvotes: 1

Lucascvs
Lucascvs

Reputation: 31

Solved. Impossible to do with CSS in case it's processed by wkhtmltopdf.

The first workaround I found was to render the page with zoom:1.41 in an A3 paper size, then render it at zoom:1/(1.41) in an A4. That was quite bloated.

So, I replaced my borders with using a SVG sprite, with an height/width of 0.2mm. It allows me to skip the A4->A3->A4 conversion, and still use the --disable-smart-shrinking option, even if my markup is now ugly.

Upvotes: 2

Related Questions