niklasvh / html2canvas

Screenshots with JavaScript
https://html2canvas.hertzen.com/
MIT License
30.11k stars 4.75k forks source link

Set the document clone iframe container's size via the style attribute #3097

Open 15joeybloom opened 11 months ago

15joeybloom commented 11 months ago

Summary

This PR fixes/implements the following bugs/features

Some sites I used html2canvas on have a CSS rule like

body>iframe {
    position: absolute;
    width: 0;
    height: 0;
    overflow: hidden;
}

This CSS rule takes precedence over the the width and height attributes of the html2canvas iframe container. As a result, the document clone is rendered with a width and height of 0, so I get a blank, all-white screenshot.

This PR also sets the width and height of the iframe within the style attribute. The style attribute will take precedence over any CSS rules.

Test plan (required)

When I tried to run npm test locally I got this error:

Traceback (most recent call last):
  File "/Users/joey/.nvm/versions/node/v12.13.1/lib/node_modules/npm/node_modules/node-gyp/gyp/pylib/gyp/common.py", line 499, in <module>
    class OrderedSet(collections.MutableSet):                                           
AttributeError: module 'collections' has no attribute 'MutableSet'

I'm on macos Ventura 13.4.1 using npm 6.12.1 and node v12.13.1

15joeybloom commented 11 months ago

For anyone else who might have come across this issue - a good workaround is to use the onclone callback:

      const canvas = await html2canvas(document.body, {
        x: window.scrollX,
        y: window.scrollY,
        width: document.documentElement.clientWidth,
        height: document.documentElement.clientHeight,
        onclone: (clonedDocument, _element) => {
...
          // This is a hack to fix a bug with html2canvas. When html2canvas is
          // rendering the element to screenshot, it actually adds the element
          // to the DOM inside an invisible iframe. The bug is that the
          // html2canvas iframe container uses the width and height attributes
          // instead of the style attribute to set the iframe's size.  Some
          // sites have a CSS rule that sets iframes' width and height to zero,
          // which takes precedence over the width and height attributes. To fix
          // this bug, we just copy the html2canvas iframe container's width and
          // height attributes into the style attribute.
          const container = document.querySelector('iframe.html2canvas-container');
          container.style.width = container.width + 'px';
          container.style.height = container.height + 'px';
...
        },
...
      });
Sharcoux commented 10 months ago

Can be tested in @cantoo/html2canvas