bubkoo / html-to-image

✂️ Generates an image from a DOM node using HTML5 canvas and SVG.
MIT License
5.4k stars 505 forks source link

Inline style lost when cloneChildren in Chrome browsers earlier than 88 #381

Open progerchai opened 1 year ago

progerchai commented 1 year ago

Using toPng in chrome browser earlier than 88, the inline style get lost, and cause the element lose style witch only has inline style, but the inline style can be obtained through dom attribute node.style.cssText

Expected Behavior

The inline style is not lost !!!

Current Behavior

See...

export async function cloneNode<T extends HTMLElement>(
  node: T,
  options: Options,
  isRoot?: boolean,
): Promise<T | null> {
  if (!isRoot && options.filter && !options.filter(node)) {
    return null
  }

  return Promise.resolve(node)
    .then((clonedNode) => {
// ************ add console. ************
      // eslint-disable-next-line no-console
      console.log(
        'before cloneSingleNode',
        node,
        clonedNode,
        clonedNode?.style?.cssText,
      )
      return cloneSingleNode(clonedNode, options) as Promise<T>
    })
    .then((clonedNode) => {
// ************ add console. ************
      // eslint-disable-next-line no-console
      console.log(
        'before cloneChildren',
        clonedNode,
        clonedNode?.style?.cssText,
      )
      return cloneChildren(node, clonedNode, options)
    })
    .then((clonedNode) => decorate(node, clonedNode))
    .then((clonedNode) => ensureSVGSymbols(clonedNode, options))
}

And the console is that: Through we can get inline style, but it not work image image

Possible Solution

And now I have tried to pick inline style up to class style manually to solve the problem


import _ from 'lodash';
import { v4 as uuidv4 } from 'uuid';

/** chuck inline style to class style
 * @param node 
 * @returns string
 */
function handleChildrenInlineStyle<T extends HTMLElement>(node: T): string {
  const children = [...node.childNodes];
  return children.reduce((previousValue: string, currentNode: ChildNode) => {
    const cssText = _.get(currentNode, 'style.cssText', null);
    let uuid = '';
    if (cssText) {
      uuid = `_${uuidv4()}`; 
      (currentNode as HTMLElement).classList.add(uuid);
      previousValue += `.${uuid}{${(currentNode as HTMLElement).style.cssText}}`;
    }
    const childStyle = handleChildrenInlineStyle(currentNode as T);

    return previousValue + childStyle;
  }, '');
}
/** Insert style
 * @param node
 * @returns HTMLElement
 */
export function handleChildren<T extends HTMLElement>(node: T): HTMLElement {
  const customStyle = document.createElement('style');
  const packInlineStyle = handleChildrenInlineStyle(node);
  customStyle.innerHTML = packInlineStyle;
  node.appendChild(customStyle);
  return node;
}

Steps To Reproduce

  1. ...
  2. ...
  3. ...
Error Message & Stack Trace

```txt ```

Additional Context

Your Environment

vivcat[bot] commented 1 year ago

👋 @progerchai

Thanks for opening your first issue here! If you're reporting a 🐞 bug, please make sure you include steps to reproduce it. To help make it easier for us to investigate your issue, please follow the contributing guidelines.

We get a lot of issues on this repo, so please be patient and we will get back to you as soon as we can.