dom-to-image icon indicating copy to clipboard operation
dom-to-image copied to clipboard

float:right multi-word text wraps last word in new line

Open InkyZima opened this issue 7 years ago • 13 comments

Use case: description, code

im floating right a <span class="u-pull-right">21.290 €</span>. This is how it looks in the DOM:

image

This is how it looks in the image (the € got wrapped to a new line):

image

The HTML:

<div class="twelve columns" id="sprice">
<h4>Gesamtpreis (inkl. MwSt. und NoVA)<span class="u-pull-right">21.290 €</span></h4>
</div>

The css is (not the problem i guess): .u-pull-right { float: right; } .twelve.columns { width: 100%; margin-left: 0; }

What i tried but didnt work:

  • trying different margins and paddings
  • not nesting the float:right span, e.g. the issue still occurs if i float:right the entire h4
  • playing with the enclosing div (margins, padding etc..)

What works/my current fix:

  • use \u00A0 (=no break space) instead of whitespace. so long as the text is only one word its ok (i.e. no wrapping to new line) Picture of image: image

Library version

current

Browsers

  • [x] Chrome 59+

InkyZima avatar Jul 22 '17 18:07 InkyZima

Got same issue. Have you found a workaround?

wildstyles avatar Jul 01 '18 07:07 wildstyles

as a hacky work around, adding a space character &nbsp; at the end fixes it for me

xaksis avatar Feb 10 '19 02:02 xaksis

The &nbsp; hack worked for me, I'm using it with react components and dangerouslySetInnerHTML. Also, specifying the width of the span didn't break the work to a second line.

sartios avatar Apr 13 '20 09:04 sartios

This issue has been chasing me for some time. I haven't been able to find the specific set of circumstances. It seems font and text dependent. I've tried to get a min repro. So this one isn't with float:right, but instead rests upon flexbox layout and non-default align-self I believe I have a localized repro that I've put into a codepen: https://codepen.io/papasnewbag/pen/wvGGxBQ

On the left is what you see in the browser, and on the right is the rendered image from dom-to-image. image It doesn't wrap until the export, and then it does.

I don't know if it's informative, but change that align-self from flex-start to flex-end and you can see how the text seems to be laid out assume it won't wrap, but then it renders with wrapping: image

Now if I happen to know the text shouldn't wrap, I can add white-space: nowrap;. But unfortunately I hit this issue in places where the text is sometimes single-line and sometimes multi-line.

  1. Does this sound like the same issue as reported here with float:right?
  2. Does anyone have any ideas about what could be going wrong and where to start investigating a fix? (If I know which direction to head I care about this issue enough to go spelunking)

chrisglein avatar Aug 16 '20 04:08 chrisglein

I have a theory about this, because I encountered a similar issue in another project, tried switching to dom-to-image, and found the same bug existed.

here's the problem. width and height and a bunch of other things are always set to explicit values when you check them in getComputedStyle. this is bad, because things that are flex-basis: auto behave differently when there's an explicit height or width set.

https://developer.mozilla.org/en-US/docs/Web/CSS/flex-basis

Then, that change was reverted in bug 1093316, so auto once again means "look at my width or height property"; and a new content keyword is being introduced to trigger automatic sizing. (bug 1105111 covers adding that keyword).

I would have liked to use flex-basis: content here, but so far only firefox has implemented that property.

here's the problem with getComputedStyle

https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle

The values returned by getComputedStyle are resolved values. These are usually the same as CSS 2.1’s computed values, but for some older properties like width, height, or padding, they are instead the same as used values. Originally, CSS 2.0 defined the computed values as the "ready to be used" final values of properties after cascading and inheritance, but CSS 2.1 redefined them as pre-layout, and used values as post-layout. For CSS 2.0 properties, getComputedStyle returns the old meaning of computed values, now called used values. An example difference between pre- and post-layout values includes the resolution of percentages for width or height, as those will be replaced by their pixel equivalent only for used values.

davidnegley avatar May 20 '21 10:05 davidnegley

block-size and inline-size are two other properties that affect the flex layout if they're set explicitly, which will happen if you clone the style using getComputedStyle

davidnegley avatar May 20 '21 10:05 davidnegley

I can reproduce something similar by using flexbox.

function App() {
  const print = useRef(null);

 function exportAsImage() {
    domtoimage.toPng(print.current).then(function (dataUrl) {
      var img = new Image();
      img.src = dataUrl;
      document.body.appendChild(img);
    }).catch(function (error) {
        console.error('oops, something went wrong!', error);
    });
  }

  return (
    <div style={{width: 400}}>
      <div ref={print} style={{ display: 'flex', justifyContent: "space-between", alignItems: "center"}}>
        <span style={{fontWeight: "bold", paddingBottom: 30}}>Some-Test not left</span>
        <span style={{fontWeight: "bold", paddingBottom: 30}}>Some-Test not right</span>
      </div>

      <br />
      <button onClick={exportAsImage}>click</button>
      <div style={{marginTop: 30}}>Result img: </div>
    </div>
  );
}

export default App;

With the following output

Screenshot 2021-05-18 at 11 54 27 AM

Seems to happen when I'm using flexbox, display: inline-block, or when wrapping the text with a div or span tag. The line break goes away when I add a fixed width with some extra space to the span.

Screenshot 2

budaaaa avatar May 20 '21 16:05 budaaaa

I have same issue. i have a "flex" and span tag, but not use explicitly value for span.

how can i fix it? anybody help me~

pouu69 avatar Sep 03 '21 06:09 pouu69

I'm having the same issue here: https://github.com/1904labs/dom-to-image-more/issues/58

BrunoQuaresma avatar Dec 29 '21 15:12 BrunoQuaresma

I had the same issue. Even when I was declaring no-wrap in my CSS it was still happening.

I was also having problems with the font I was using having side-bearings that were extending out of the content box of the containing element which caused the characters on the end to be cut off.

I made a compensation variable that takes an integer that represents the number of pixels to add to the width of the captured element. I couldn't find a way to compute this because it is dependent on the font used and the size of the text.

Here is how I fixed my problem:

    // The Element needs to be visible to create an image of it
    if (el.style.opacity === "0") {
      el.style.opacity = 1;
    }

    // Get the width and height from the bounding client rect and get an integer instead of float
    const rect = el?.getBoundingClientRect ? el.getBoundingClientRect() : this.getBoundingClientRect();
    const rectWidth = Math.ceil(rect.width);
    const rectHeight = Math.ceil(rect.height);
    const elStyles = getComputedStyleObject(el);

    // Need to declare a set of default styles to overwrite the
    // ones that are generated by domtoimage that cause issues.
    // ! Need to use Bracket Accessor to overwrite the properties properly
    const overwrite = {};
    overwrite["margin-block"] = "0"; // margins were applied in the SVG
    overwrite["white-space"] = "nowrap"; // Fixes unwanted text nodes wrapping

    // User will have to figure their own font compensation amount
    const compensation = this.fontCompensation;

    domtoimage
      .toSvg(el, {
        width:
          rectWidth +
          parseInt(elStyles.marginRight.replace("px")) +
          parseInt(elStyles.marginLeft.replace("px")) +
          compensation,
        height: rectHeight,
        style: Object.assign(elStyles, overwrite),
      })

getComputedStyleObject is a utility function I made to convert the passed elements computed style object into a regular object that I could merge my overwrites with and pass to dom-to-image-more.

Clive-Ward-Cron avatar Mar 24 '22 18:03 Clive-Ward-Cron

Facing the same

maiconcarraro avatar Nov 12 '23 18:11 maiconcarraro

Facing the same issue in 2024. Any new ideas on how to fix this?

jeffreybello avatar Mar 04 '24 16:03 jeffreybello

Facing the same issue in 2024. Any new ideas on how to fix this?

I migrated to html-to-image: https://github.com/bubkoo/html-to-image

chrisglein avatar Mar 09 '24 22:03 chrisglein