offsetWidth and offsetHeight adding an extra 10px+ on every other window resize

210 Views Asked by At

I have a parent element and a child element. On window resize event, the child element has its width and height set to the parents' offsetWidth and offsetHeight, however on every other resize both the width and height are off by 12px on Firefox and 15px on Edge.

Here's the code, when you resize the page, there's a white gap on the right:

const parent = document.getElementById("parent");
const child = document.getElementById("child");

const matchDimensions = () => {
    child.style.width = parent.offsetWidth + "px";
    child.style.height = parent.offsetHeight + "px";
};

matchDimensions();
window.addEventListener("resize", matchDimensions);
html, body, #parent {
    width: 100%;
    height: 100%;
    margin: 0;
}

#child {
    background: red;
}
<div id="parent">
    <div id="child"></div>
</div>

Weirdly, it only happens if I scale the page down but not if I scale it up. Also, removing margin: 0 stops this from happening but I need it in order to have the parent fill the entire page.

The reason I'm using JS to match the child to the parent is because in reality the child is a canvas which doesn't automatically resize with the parent with just CSS.

4

There are 4 best solutions below

1
BeKind-Rewind On

Possible the browser has some default styling getting in the way since it changes behavior with the size of the viewport.

You could try a css reset (one example) or normalize to see if that solves the issue.

0
Ferris On

Referring to my comment, i updated your Javascript code to calculate the srollbar width, add the result to child.style.width and so get rid of the gap.

const parent = document.getElementById( "parent" );
const child = document.getElementById( "child" );

/* Create a temporary element to calculate
   the scrollbar width; then delete it.
*/
const scrollBarWidth = () => {
  let el, width;
  el = document.createElement( "div" );
  el.style.cssText = "position:absolute; visibility:hidden; overflow:scroll;";
  document.body.appendChild( el );
  width = el.offsetWidth - el.clientWidth;
  el.remove();
  return width;
}

const matchDimensions = () => {
  child.style.width = parent.offsetWidth + scrollBarWidth + "px";
  child.style.height = parent.offsetHeight + "px";
};

matchDimensions();
window.addEventListener( "resize", matchDimensions );
html, body, #parent {
    width: 100%;
    height: 100%;
    margin: 0;
}

#child {
    background: red;
}
<div id="parent">
    <div id="child"></div>
</div>

0
Vishal On

The issue here is most likely caused by how browsers handle subpixel rendering, which can result in minor fluctuations in element size. To solve this problem, use the Math.round() function to round the width and height values to the nearest whole number. Here's how to change the matchDimensions() function to accomplish this:

JavaScript:

const matchDimensions = () => {
  child.style.width = Math.round(parent.offsetWidth) + "px";
  child.style.height = Math.round(parent.offsetHeight) + "px";
};

This should help to eliminate the white gap on the right that appears in Firefox and Edge. Additionally, if you need to maintain the margin on the parent element, you can add a box-sizing rule to include the margin in the calculation of the element's total width and height:

CSS:

html, body {
  margin: 0;
  height: 100%;
}

#parent {
  width: 100%;
  height: 100%;
  margin: 0;
  box-sizing: border-box;
}

#child {
  background: red;
  width: 100%;
  height: 100%;
}

With these modifications, the child element should resize dynamically to match the parent element's dimensions without any gaps or off-by-pixel issues.

0
svilen On

I think I figured it out. The simple fix is adding overflow: hidden to the parent, which actually makes some sense. Since the child has a fixed width, when the page is resized the first thing to change is the parent, however because of the fixed width the child can't move and so it overflows outside the body which adds a scrollbar. The event then gets triggered with the scrollbar and because the width of the parent is now much less, the child inherits it which stops it from overflowing so the scrollbar disappears. Obviously, this happens very quickly which is why it's not noticeable. It also explains why it only happens when shrinking the window and not expanding it, since expanding wouldn't cause an overflow.