html2pdf.js: @media print (or @media not print) in Css ignored

When using @media print and @media not print in the CSS in order to get rid of color, images … the generated pdf will ignore these.

On https://jsfiddle.net/wb2tgm6f/l the generated pdf still includes the

as visible text

About this issue

  • Original URL
  • State: open
  • Created 6 years ago
  • Reactions: 5
  • Comments: 15 (1 by maintainers)

Commits related to this issue

Most upvoted comments

Okay, forgot it… I had to run the removal of class after html2pdf function had completely run.

var source = document.getElementById('body');
source.classList.add('print');
html2pdf(source, {
     filename: 'Test.pdf',
     image: { type: 'jpeg', quality: 1 },
     html2canvas: { scale: 2 },
     jsPDF: { unit: 'mm', format: 'A4', orientation: 'landscape', putOnlyUsedFonts: true }
}).then(function(){
     source.classList.remove('print');
});

It’s not perfect (there’s a little subtle change in layout, of course) but whatever… 😉

This isn’t printing, so the print media query won’t get triggered. The workaround I’ve used is through the css preprocessor I’m using, I duplicate the print styles on both @media print and body.print. Then I add the print class to the body right before triggering html2pdf, and then removing it right after.

Hello!

  1. Thanks for the suggestion @JVApen, I’ll look into adding the feature.
  2. Thanks for the workaround @cwallen!
  3. @mnelson4 yes, creating a PDF is like printing, and it would be best to support printing-related features. That said, if we want the feature then we have to implement it!

I’ve investigated and I think this is doable. It would require altering the stylesheets in html2canvas’s cloned document, which we can access with html2canvas’s onclone callback. In there, we could put something like:

// Function to remove a specified medium (e.g. 'print').
function deleteMedium(item, medium) {
    if (item.media && item.media.toString().toLowerCase().indexOf(medium) !== -1) {
        item.media.deleteMedium(medium);
    }
}

// Loop through each stylesheet.
Array.prototype.forEach.call(document.styleSheets, function (styleSheet) {
    // Remove any print rules on the stylesheet itself.
    deleteMedium(styleSheet, 'print');

    // Loop through each rule and remove any print rules.
    var rules = styleSheet.cssRules || styleSheet.rules;
    Array.prototype.forEach.call(rules, function (rule) {
        deleteMedium(rule, 'print');
    });
});

Needs testing in all relevant browsers. More info here - I stripped down the example code there to just what we would need.

Not sure if there’s any possible optimisation - two thoughts:

  1. The linked example doesn’t traverse the stylesheet if it has a media= value that doesn’t contain the desired medium (e.g. print). I don’t know enough about it to say whether that’s safe.
  2. Also, could skip the stylesheet entirely if it did have the desired medium (because why use @media print inside of a media="print" stylesheet?). But again, I don’t know all the details.

I’ll put this on the to-do list. I’m planning another change that will require tapping into html2canvas’s onclone, so I’ll attach this to that project.