17

I seem to have stumbled onto a bug in IE where the scrollWidth is off by 1px compared to the offsetWidth. The trigger to this seems to be dependent on the length of the text/characters in the element and only happens when overflow is set to something other than visible.

For context on why I am checking them against each other see this question: HTML - how can I show tooltip ONLY when ellipsis is activated

For an example of the issue see: http://jsfiddle.net/w5cwhjbf/2/

.base{
    font-size: 16px; 
    overflow: hidden;    
}

.wrapper{
    float: left;  
}
<div class="wrapper">
    <div id="div1" class="base">
        Why is my scrollWidth wrong in IE?
    </div>
</div>
<br style="clear: both;">
<br>
<button id="btn1" onclick="fnCheckScroll(div1,btn1)">Calculates Wrong</button>
<br>
<br>
<br> 
<div class="wrapper">
    <div id="div2" class="base">
        Why is my scrollWidth right in IE?
    </div>
</div>
<br style="clear: both;">
<br>
<button id="btn2" onclick="fnCheckScroll(div2,btn2)">Calculates Correctly</button>
<br>
<br>
<br>
Issue seems to be based on the character widths/font size resulting in I would assume a fractional value that in one case gets rounded up and the other rounded down.  The issue however does not ever cause scroll bars to appear (if overflow is auto).  Issue doesnt happen with overflow: visible.
  
        
<script type="text/javascript">
function fnCheckScroll(div, btn)
{    
   var iScrollWidth = div.scrollWidth;
   var iOffsetWidth = div.offsetWidth;
   var iDifference = iScrollWidth - iOffsetWidth;
   btn.innerHTML = ("Width: " + iOffsetWidth + "px  |  scrollWidth: " + iScrollWidth + "px  |  Difference: " + iDifference + "px"); 
}
</script>

You will notice in the example, though the first item has room to grow to whatever size it wants, its width is set 1px too short, or the scrollWidth reported is 1px too big, as well as the fact that no scrollbar is thrown (when CSS explicitly set to overflow: auto), IE knows somewhere in its code it is not actually overflowing.

Question is, what would be your suggested fix or workaround for this issue, as it seems like it randomly happens based on the characters/font/font-size in the div?

Community
  • 1
  • 1
Chris Janssen
  • 298
  • 2
  • 10
  • Hey, have you come across a good workaround for this? – David Perlman Feb 14 '17 at 10:41
  • 1
    Sadly no, we had to put in the 1px grace in the javascript check for the IE versions effected and deal with the occasional issue where the tooltip didnt show up due to the miscalculation. – Chris Janssen Feb 27 '17 at 18:49
  • yeah, did the same.. sucks – David Perlman Feb 27 '17 at 19:11
  • Update: Logged a bug on Edge, and Microsoft has already fixed it, so this should be a non issue soon for that browser however you will still see the issue in IE: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/11689089/ – Chris Janssen Apr 19 '17 at 20:30
  • Anyone has good workaround other than the above? – JGV Oct 30 '17 at 17:25
  • @VimalanJayaGanesh I added an answer that provides a work around for my use case. You can likely use something similar if your use case is different to verify that ie is correctly rounding the scrollwidth. – Chris Janssen Nov 08 '17 at 02:12
  • @ChrisJanssen, thank you for the info. – JGV Nov 08 '17 at 18:33

3 Answers3

2

It's hard to give the best solution without knowing how this applies to your specific problem with this bug. That being said, you could:

  • Use a javascript bug-fix to adjust the attributes/styles/etc. if the two elements are different sizes.

    if(iDifference != 0) { /* make adjustments. */ }

  • Use a tolerance check between the two elements; if the difference is less than or equal to 2px, then don't worry about it and process everything as normal.

    if(Math.abs(iDifference) <= 2) { /* no problem here! */ }

  • Use the outer element for all computations, since that has the true width of the container.

  • Use the inner element for all computations, since that will never cause an overlap with the outer element.

  • Do nothing! Why fix it if it isn't broken?

It all depends on what you're trying to do and how the 1px gap is causing a problem.

Siphon
  • 1,041
  • 8
  • 17
  • Siphon, I see I forgot to include the link to the specific use case of why I am using the check. It is now included above. – Chris Janssen Jun 17 '15 at 19:45
  • Then I would suggest you use the inner container width. You might even want to trim a few pixels off the width for some padding, if needed. Worrying about 1 px seems like a trivial thing to worry about if you use 5px to 20px for padding. – Siphon Jun 17 '15 at 20:31
  • 1
    Siphon, per the use case, we are using the calculation to determine if the text-overflow: ellipsis is happening. (it only triggers in the same cases a scrollbar shows up). In this case, in IE due to this issue you cannot tell the difference between it is 1px overflowing and has the ellipsis, vs it is reporting 1px off but isnt overflowing and doesnt need the tooltip. By ignoring the issue, you get a tooltip all the time. By giving a 1px grace to the calculation, you get situations where the text is cutoff (ellipsis) but no tooltip with full text is shown. In either case the UX suffers. – Chris Janssen Jun 19 '15 at 20:01
  • Would you benefit from using a fixed table layout (check out `table-layout: fixed;` in relation with `text-overflow: ellipsis`)? It sounds like using a CSS solution would solve a lot of your problems. Check out: http://stackoverflow.com/questions/10209831/detect-if-text-overflowellipsis-is-active-on-input-field – Siphon Jun 22 '15 at 15:48
  • No, table-layout: fixed wouldn't solve the issue, as the whole point is to have Divs (or other elements) that are dynamically sized/resized based on the window. As they resize, text may now overflow (causing an ellipsis). Dynamically adding a tooltip allows a way for user to see full text, even when viewing at smaller window sizes. Using the mouseenter + javascript calculation keeps everything light and keeps it from overloading the browser. The linked suggestion has the issue that you must transfer all inherited CSS correctly, which can be extremely difficult and not as light as srollWidth – Chris Janssen Jun 23 '15 at 17:39
  • At this point, there isn't much else I can do/suggest without seeing the actual code. All I have to work with are related examples that do not let me see the code giving you problems. – Siphon Jun 24 '15 at 13:42
2

Found a workable workaround for the issue that would work in ie9+. Requires checking the elements getBoundingClientRect() width in addition to the scroll and offset width.

var boundingClientRectWidth = element.getBoundingClientRect().width;
var iScrollWidth = div.scrollWidth;
var iOffsetWidth = div.offsetWidth;

var amIOverflowing = (iScrollWidth > iOffsetWidth) && (boundingClientRectWidth == iOffsetWidth);

By check in IE if the boundingClient is forced to be the same size as the iOffsetWidth (instead of having a fractional width) we can ensure that we don't use the incorrect scroll width that is rounding up instead of down e.g. 273.36...

See this jsfiddle: http://jsfiddle.net/gskfke6L/1/

Chris Janssen
  • 298
  • 2
  • 10
1

Try to set the padding-right: 1px; for the class .base.

.base{
    font-size: 16px; 
    overflow: hidden;
    padding-right: 1px;    
}