niklasvh / html2canvas

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

Texts are shifted down #2775

Open Srn5333 opened 2 years ago

Srn5333 commented 2 years ago

Texts are shifted down!! $LVX)YX9X$5E2 YGFT (GX but: 1640274521(1)

Srn5333 commented 2 years ago

That seems to work GFK6D%$NS4X QNMTI55UW}B

webstager commented 2 years ago

That seems to work GFK6D%$NS4X QNMTI55UW}B

It still doesn't work for the input box. Reference link: https://github.com/niklasvh/html2canvas/issues/2769#issuecomment-1000985189

Srn5333 commented 2 years ago

That seems to work GFK6D%$NS4X QNMTI55UW}B

It still doesn't work for the input box. Reference link: #2769 (comment)

Try this https://codepen.io/ipphof/pen/qBaagPK

webstager commented 2 years ago

That seems to work GFK6D%$NS4X QNMTI55UW}B

It still doesn't work for the input box. Reference link: #2769 (comment)

Try this https://codepen.io/ipphof/pen/qBaagPK

Hello, after a try, the input placeholder text position will still change.

jayhoogle commented 2 years ago

Hi, I'm having this issue, too and I can't see how the line-height fix should actually work. All I'm trying to render is this and it keeps shifting down:

As an HTML element:

Screenshot 2022-01-19 at 21 33 58

As a screenshot:

Screenshot 2022-01-19 at 21 33 54

This is my code:

<div
  style={{
  padding: "1% 2%",
  display: "inline-block",
  position: "relative",
  background-color: "white",
  }}
>
  ABC
</div>
User6531 commented 2 years ago

Hi, I'm having this issue, too and I can't see how the line-height fix should actually work. All I'm trying to render is this and it keeps shifting down:

As an HTML element: Screenshot 2022-01-19 at 21 33 58

As a screenshot: Screenshot 2022-01-19 at 21 33 54

This is my code:

<div
  style={{
  padding: "1% 2%",
  display: "inline-block",
  position: "relative",
  background-color: "white",
  }}
>
  ABC
</div>

hello, i have the same problem, can you tell me, did you find any solution to fix this bug? I'll appreciate if you can share it with me.

worldstop commented 2 years ago

我也遇到了 有人解决了吗?

worldstop commented 2 years ago

给下载dome的根节点加 line-height:0.5 也可以 不用给整个body加

LoicKairon commented 2 years ago

Did you find a working fix?

janhaertel commented 2 years ago

I have a similar issue with a div which contains one svg that has foreignObject elements. If I set foreignObjectRendering to true, the div just disappears.

When I inspect the rendered html, I can see, that the computed line-height in the cloned element differs from the computed line-height in the original element.

TreeChart Canvas falsche line-height

StationSoen commented 2 years ago

I also encountered this issue and found that the problem was with Tailwind CSS's preflight. Specifically, the issue was with the reset code, which changed the display attribute of the img tag to block in preflight. To resolve this, I either removed preflight or restored the img tag's display attribute to inline-block in global.css.

Not doing preflight - In my case, tailwind layout was broken.

// tailwind.config.js
module.exports = {
module.exports = {
  corePlugins: {
    preflight: false,
  },
  content: ["./src/**/*.{js,jsx,ts,tsx}"],
  ...
}

Restore img tag's display attribute - I choose this solution.

/* global.css */
@tailwind base;
@layer base {
  img {
    @apply inline-block;
  }
}
@tailwind components;
@tailwind utilities;

I hope it helped you a lot.

popejhonpaul commented 1 year ago

Does somebody have a solution for this already? I can't make it work.

boompikachu commented 1 year ago

Since html2canvas append div tag to body to get some metrics, we can do the following:

const downloadPdf = () => {
    const style = document.createElement('style');
    document.head.appendChild(style);
    style.sheet?.insertRule('body > div:last-child img { display: inline-block; }');

    html2canvas(element).then(canvas => {
      style.remove();
    });
  };

This will keep image as block

maiconcarraro commented 1 year ago

@boompikachu I used your solution and worked great!

DivineDemon commented 1 year ago

I encountered this problem too, and in my case, the problem was the Tailwind CSS's preflight. In particular, the problem was reset code, which changed the display attribute of the img tag in Preflight to block. It could be solved by not doing preflight, or by doing restore img tag's display attribute to inline-block in 'global.css'.

Not doing preflight - In my case, tailwind layout was broken.

// tailwind.config.js
module.exports = {
module.exports = {
  corePlugins: {
    preflight: false,
  },
  content: ["./src/**/*.{js,jsx,ts,tsx}"],
  ...
}

Restore img tag's display attribute - I choose this solution.

/* global.css */
@tailwind base;
@layer base {
  img {
    @apply inline-block;
  }
}
@tailwind components;
@tailwind utilities;

I hope it helped you a lot.

Yes, this worked for me, kudos!

KID-joker commented 1 year ago

1.4.1 still has this error

mleister97 commented 1 year ago

Waiting for fix

coke-fairy commented 1 year ago

Waiting for fix

gurleensethi commented 1 year ago

Will this be fixed?

LeonelCabrera19 commented 1 year ago

I found this solution:

@layer base {
  img {
    @apply inline-block;
  }
}

The above piece of code should be added after the @tailwind base

here is the original reference

AmitDigga commented 1 year ago

Restore img tag's display attribute - I choose this solution.

/* global.css */
@tailwind base;
@layer base {
  img {
    @apply inline-block;
  }
}
@tailwind components;
@tailwind utilities;

I hope it helped you a lot.

I was not getting expected result even after suggested fix, though there were some improvements. I have to turn on foreign object rendering

From

const generateCanvasFromElementId = async (elementId) => {
  const elementToCapture = document.getElementById(elementId);
  const canvas = await html2canvas(elementToCapture);
  return canvas;
};

To

const generateCanvasFromElementId = async (elementId) => {
  const elementToCapture = document.getElementById(elementId);
  const canvas = await html2canvas(elementToCapture, {
    foreignObjectRendering: true,
    scrollY: -(
      elementToCapture.getBoundingClientRect().top +
      document.documentElement.scrollTop
    ),
    scrollX: -(
      elementToCapture.getBoundingClientRect().left +
      document.documentElement.scrollLeft
    ),
  });
  return canvas;
};
  1. Turn on foreignObjectRendering
  2. scrollX and scrollY because the object was in parent having position : fixed
zharletc commented 8 months ago

I also encountered this issue and found that the problem was with Tailwind CSS's preflight. Specifically, the issue was with the reset code, which changed the display attribute of the img tag to block in preflight. To resolve this, I either removed preflight or restored the img tag's display attribute to inline-block in global.css.

Not doing preflight - In my case, tailwind layout was broken.

// tailwind.config.js
module.exports = {
module.exports = {
  corePlugins: {
    preflight: false,
  },
  content: ["./src/**/*.{js,jsx,ts,tsx}"],
  ...
}

Restore img tag's display attribute - I choose this solution.

/* global.css */
@tailwind base;
@layer base {
  img {
    @apply inline-block;
  }
}
@tailwind components;
@tailwind utilities;

I hope it helped you a lot.

You so cool bro. It's worked as well !

joaopedromatias commented 8 months ago

I also encountered this issue and found that the problem was with Tailwind CSS's preflight. Specifically, the issue was with the reset code, which changed the display attribute of the img tag to block in preflight. To resolve this, I either removed preflight or restored the img tag's display attribute to inline-block in global.css.

Not doing preflight - In my case, tailwind layout was broken.

// tailwind.config.js
module.exports = {
module.exports = {
  corePlugins: {
    preflight: false,
  },
  content: ["./src/**/*.{js,jsx,ts,tsx}"],
  ...
}

Restore img tag's display attribute - I choose this solution.

/* global.css */
@tailwind base;
@layer base {
  img {
    @apply inline-block;
  }
}
@tailwind components;
@tailwind utilities;

I hope it helped you a lot.

It worked!!

SHAFINSHAMUHAMMED commented 7 months ago

Did you find a working fix?

if you are using tailwind css add this in index.css @layer base { img { @apply inline-block; } }

thomasliew commented 6 months ago

Since html2canvas append div tag to body to get some metrics, we can do the following:

const downloadPdf = () => {
    const style = document.createElement('style');
    document.head.appendChild(style);
    style.sheet?.insertRule('body > div:last-child img { display: inline-block; }');

    html2canvas(element).then(canvas => {
      style.remove();
    });
  };

This will keep image as block

Thx Bro~ It worked

peidLuo commented 6 months ago

Since html2canvas append div tag to body to get some metrics, we can do the following:

const downloadPdf = () => {
    const style = document.createElement('style');
    document.head.appendChild(style);
    style.sheet?.insertRule('body > div:last-child img { display: inline-block; }');

    html2canvas(element).then(canvas => {
      style.remove();
    });
  };

This will keep image as block

great!!!

hsynerkl commented 5 months ago

Ben de bu sorunla karşılaştım ve sorunun Tailwind CSS'nin ön kontrolünde olduğunu gördüm. Özellikle sorun, ön kontrolde img etiketinin görüntüleme özelliğini bloke edecek şekilde değiştiren sıfırlama koduyla ilgiliydi. Bunu çözmek için ya ön kontrolü kaldırdım ya da img etiketinin display özelliğini global.css'deki inline-block'a geri yükledim.

Ön kontrol yapmıyor - Benim durumumda arka rüzgar düzeni bozuldu.

// tailwind.config.js
module.exports = {
module.exports = {
  corePlugins: {
    preflight: false,
  },
  content: ["./src/**/*.{js,jsx,ts,tsx}"],
  ...
}

imgEtiketin özelliğini geri yükle display- Bu çözümü seçiyorum.

/* global.css */
@tailwind base;
@layer base {
  img {
    @apply inline-block;
  }
}
@tailwind components;
@tailwind utilities;

Umarım size çok yardımcı olmuştur.

Thanks bro, I didn't want to deal with this mistake

shiroringo commented 3 months ago

Since html2canvas append div tag to body to get some metrics, we can do the following:

const downloadPdf = () => {
    const style = document.createElement('style');
    document.head.appendChild(style);
    style.sheet?.insertRule('body > div:last-child img { display: inline-block; }');

    html2canvas(element).then(canvas => {
      style.remove();
    });
  };

This will keep image as block

解决了!!感谢大佬!!!!!!!Thank you very much!

kachkaev commented 2 months ago

I was struggling to render inputs and textareas – the text was shifted and trimmed. As a workaround, I managed to create a clone of the element I want to capture and replace all input/textarea elements with spans. This helped!

import html2canvas from 'html2canvas';

const cloneWithReplacedInputsAndTextAreas = <T extends HTMLElement | ChildNode>(node: T): T => {
  if (node instanceof HTMLInputElement || node instanceof HTMLTextAreaElement) {
    const span = document.createElement('span');
    span.textContent = node.value;
    span.className = node.className;
    span.setAttribute('style', node.getAttribute('style') ?? '');
    span.style.width = `${node.offsetWidth}px`;
    span.style.height = `${node.offsetHeight}px`;
    return span as T;
  }

  const clone = node.cloneNode(false) as HTMLElement;

  node.childNodes.forEach((child) => {
    clone.appendChild(cloneWithReplacedInputsAndTextAreas(child));
  });

  return clone as T;
};

export const exportElementAsImage = async ({
  downloadFileName,
  element,
}: {
  downloadFileName: string;
  element: HTMLElement;
}): Promise<void> => {
  const containerForClone = document.createElement('div');

  try {
    const clonedExport = cloneWithReplacedInputsAndTextAreas(element);

    containerForClone.style.pointerEvents = 'none';
    containerForClone.style.position = 'fixed';
    containerForClone.style.left = '10000px';
    containerForClone.style.top = '10000px';
    containerForClone.style.width = `${element.offsetWidth}px`;
    containerForClone.style.height = `${element.offsetHeight}px`;

    containerForClone.appendChild(clonedExport);
    document.body.appendChild(containerForClone);

    const canvas = await html2canvas(containerForClone);

    const image = canvas.toDataURL('image/png');
    const link = document.createElement('a');
    link.href = image;
    link.download = downloadFileName;
    link.click();
  } finally {
    containerForClone.remove();
  }
};
killernova commented 1 month ago

I also encountered this issue and found that the problem was with Tailwind CSS's preflight. Specifically, the issue was with the reset code, which changed the display attribute of the img tag to block in preflight. To resolve this, I either removed preflight or restored the img tag's display attribute to inline-block in global.css.

Not doing preflight - In my case, tailwind layout was broken.

// tailwind.config.js
module.exports = {
module.exports = {
  corePlugins: {
    preflight: false,
  },
  content: ["./src/**/*.{js,jsx,ts,tsx}"],
  ...
}

Restore img tag's display attribute - I choose this solution.

/* global.css */
@tailwind base;
@layer base {
  img {
    @apply inline-block;
  }
}
@tailwind components;
@tailwind utilities;

I hope it helped you a lot.

By using this method in Vue3, the texts shifted up...