Gendarme Gendarme - 6 months ago 11
HTML Question

Elements do not find enough space inside body - JavaScript styling

Relevant information:



The page contains two elements:


  • An
    <aside>
    to the left.

  • A
    <main>
    to the right.



(Note: Throughout this post, heights are mentioned for the sake of completeness, but are irrelevant to producing this problem.)

All heights, widths, and margins are set with respect to
var w = screen.width/100;
(and
var h = screen.height/100;
) so that the page essentially looks the same in any display resolution. And they are set so that the width of
<aside>
and
<main>
, and the margin between them all add up to
screen.width
.

For example:

var w = screen.width/100;
document.getElementsByTagName('main')[0].style.width = 85.5*w + "px";
document.getElementsByTagName('aside')[0].style.width = 14*w + "px";
document.getElementsByTagName('aside')[0].style.marginRight = 0.5*w + "px";


(85.5 + 14 + 0.5 = 100)

The problem:



The
<main>
gets pushed down below the
<aside>
for unknown reasons. I can only think of a half-sensible hypothesis to somewhat explain this behavior.

However, if I set the font size of the body to 0 and zoom out (so that the elements take less space) and zoom back in, this gets fixed (I don't know why, and don't ask me how I found this out).

What is the reason for this behavior, and what is the proper fix?

The hypothesis (can be skipped):




The browser seems to think "What would happen if I display the scrollbars even though they are not needed?", and then notices that the scrollbars have a width > 0, which means that
<aside>
and
<main>
are taking more space than available (since they are set to take up 100% of the screen width, and now there is a scrollbar competing for the space). The browser therefore decides to reposition the
<main>
below the
<aside>
and ruin the design.

And now since
<main>
is under
<aside>
the elements no longer fit inside the screen and the scrollbars are actually needed now and therefore stay, even though they are the cause of their own existence (as far as this hypothesis goes).


Additional information:




  • I am not using any CSS-stylesheet: all my styling is done by JavaScript (for the simple reason that I want the sizes to depend on
    screen.width
    and
    screen.height
    ).

  • The elements have
    display = "inline-block";
    . Using
    float
    produces horrendous behavior when the browser is anything but max size.



Here is the code to reproduce the problem:

<!DOCTYPE html>
<html>
<body>

<aside></aside>

<main></main>

<script>
var h = screen.height/100;
var w = screen.width/100;

var e = document.getElementsByTagName("aside")[0].style;
e.display = "inline-block";
e.backgroundColor = "lightblue";
e.width = 14*w + "px";
e.height = 69*h + "px";
e.marginRight = 0.5*w + "px";

e = document.getElementsByTagName("main")[0].style;
e.display = "inline-block";
e.backgroundColor = "green";
e.width = 85.5*w + "px";
e.height = 69*h + "px";

e = document.getElementsByTagName("body")[0].style;
e.margin = e.padding = "0";
e.backgroundColor = "black";
</script>
</body>
</html>

Answer

Update after the question edit

The reason why your main gets pushed down under aside is because of a white space inline elements have. An inline element (which is not positioned with absolute or fixed) has that space and there is several ways to get rid of it.

Here you can read more about it and how to get rid of it (if to keep the elements inline).

Other ways to line up elements side-by-side is to use display: flex or display: table-cell, both with a similar behavior as inline elements (in the meaning of stacking horizontal in opposite to block elements, which stacks vertical), though doesn't suffer from the white space in the same way when it comes to its set size compared to actual size.

To clarify, i.e. if a width is set to 14.5% on a flex item, it takes 14.5% and no more, in opposite to an inline, which will be 14.5% plus its white space (where the white space size actually depends on the set font size)

Sample display: flex (recommended)

* {
  box-sizing: border-box;
}
html, body {
  margin: 0;
  height: 100%;
}

body {
  display: flex;
  height: 100%;
}
aside {
  width: 14%;
  margin-right: 0.5%;
  background-color: #f66;
}
main {
  width: 85.5%;  
  background-color: #66f;
}
<aside>
  aside
</aside>
<main>
  main
</main>

Sample display: table-cell (for older browsers)

* {
  box-sizing: border-box;
}
html, body {
  margin: 0;
  height: 100%;
}

body {
  display: table;
  width: 100%;
  height: 100%;
}
aside {
  display: table-cell;
  width: 14%;
  background-color: #f66;
}
main {
  display: table-cell;
  width: 85.5%;
  background-color: #66f;
}
.margin {
  display: table-cell;
  width: 0.5%;
}
<aside>
  aside
</aside>

<div class="margin"></div>

<main>
  main
</main>

Note:

Other ways to create a margin between the aside and main when using display: table, is to use cell padding, border width etc.


With your existing code, and since you don't use normal flow, absolute positioning could be an option.

<!DOCTYPE html>
<html>    
<body> 

<aside></aside>

<main></main> 

<script>
  var h = screen.height/100;
  var w = screen.width/100;

  var e = document.getElementsByTagName("aside")[0].style;
  e.position = "absolute";                                     /*  changed  */
  e.backgroundColor = "lightblue";
  e.width = 14*w + "px";
  e.height = 69*h + "px";
  e.marginRight = 0.5*w + "px";

  e = document.getElementsByTagName("main")[0].style;
  e.position = "absolute";                                     /*  changed  */
  e.backgroundColor = "green";
  e.width = 85.5*w + "px";
  e.height = 69*h + "px";   
  e.left = 14.5*w + "px";                                      /*  added  */
  
  e = document.getElementsByTagName("body")[0].style;
  e.margin = e.padding = "0";
  e.backgroundColor = "black";
  
</script>
</body>
</html>


Update 2

The problem with your code is it runs before the DOM is completely finished, hence create scroll bars. Try below sample, where I added a delay, and you'll see it works (when browser runs maximized).

<!DOCTYPE html>
<html>
<script>

  function runOnLoad() {

  setTimeout(function() {

  var h = screen.height/100;
  var w = screen.width/100;

  var e = document.getElementsByTagName("aside")[0].style;
  e.display = "inline-block";
  e.backgroundColor = "lightblue";
  e.width = 14*w + "px";
  e.height = 69*h + "px";
  e.marginRight = 0.5*w + "px";

  e = document.getElementsByTagName("main")[0].style;
  e.display = "inline-block";
  e.backgroundColor = "green";
  e.width = 85.5*w + "px";
  e.height = 69*h + "px";   

  e = document.getElementsByTagName("body")[0].style;
  e.margin = e.padding = "0";
  e.backgroundColor = "black";
  e.fontSize = "0";

  }, 200)

  }
</script>

<body onload="runOnLoad();"> 

<aside></aside>

<main></main> 

</body>
</html>

Comments