最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

html - Elements do not find enough space inside body - JavaScript styling - Stack Overflow

programmeradmin3浏览0评论

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 pleteness, 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 peting 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>

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 pleteness, 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 peting 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>
Share Improve this question edited Apr 27, 2016 at 21:39 RaminS asked Nov 27, 2015 at 20:40 RaminSRaminS 2,2394 gold badges23 silver badges31 bronze badges 7
  • Have you set html, body {margin: 0; } and using box-sizing: border-box? – Asons Commented Nov 27, 2015 at 21:16
  • 2 Another tip, as you already use the percent to calc size, drop setting size to px, use % and you can skip calculate as browser will do that for you, which will increase performance. – Asons Commented Nov 27, 2015 at 21:23
  • 1 Another tip, use vh (viewport height) and vw (viewport width) which is equivalent to screen height and width. – Jan Franta Commented Apr 28, 2016 at 12:59
  • @JanNahody No, it is absolutely not the same. It might give you the same result, if the browser runs in maximized or theater mode though. – Asons Commented Apr 29, 2016 at 4:42
  • @LGSon You are right. Screen means device-size. I forgot. – Jan Franta Commented Apr 29, 2016 at 5:49
 |  Show 2 more ments

7 Answers 7

Reset to default 6 +100

Update after the question edit

The reason why your main gets pushed down under aside is because you have an invisible space, in your case the line break but can be a simple blank space as well, between your elements in your markup, which actually adds size along with the elements making it all exceed 100% width, hence create the scroll bar.

That space, which exist for inline elements (which is not positioned with absolute or fixed, or floated), needs to be taken into account together with the elements size, when calculating their width to fit their parents width (in this case the body/viewport).

Here you can read more about it and how to get rid of it or make it bee 0 in size (if to keep the elements inline).

  • https://www.w3/TR/2010/WD-css3-text-20101005/#white-space-collapsing
  • https://css-tricks./fighting-the-space-between-inline-block-elements/
  • How to remove the space between inline-block elements?

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 es to its set size pared 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 the white space (where the white space size actually depends on the set font size)

Sample display: flex (remended)

* {
  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 pletely 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>

The scrollbar hypothesis is right. Here is the solution: How to get screen width without (minus) scrollbar?. I tested it and using document.body.clientWidth solves the issue. The other problem is that inline-block elements need to be chained together without spaces or newlines (to avoid unwanted margins).

<body><aside></aside><main></main></body>

You problem is the white-space between your aside and main, taking some space since your are using inline-block for display.

The answer from @Shah Abaz Khan is right, You have to get rid of this white space.

This can be done by removing it, as suggested :

<aside></aside><main></main> 

But you want to keep your html indentation, you can also use html ments <!-- -->:

<aside>
    //stuff
</aside><!--

--><main>
    //other stuff
</main>

A nearly plete explanation:

The following works (but there are other ways to do it as well):

  • Change the font size of the body to 0 so that the spaces between the inline-block elements bee 0 (or use any other technique). This is thoroughly explained in other answers.

  • Give the body a fixed width. In this case screen.width. The reason to why this works is slightly plex. Note that if not specified, the body will take up the whole width of the browser (not necessarily the screen). There are two scenarios:

    • (Warning: This part is closer to a hypothesis than a proper answer.) When the browser is maximized (width of the screen and the browser are the same) the body will have the maximum width of screen.width (if needed), so the elements are not taking up too much space. However, since the body does not immediately know how wide it needs to be, it seems to not "be prepared", so the elements end up taking too much space after all. This is why giving the body its width in advance fixes this issue (there are also other ways around this - see other answers).

    • When the browser is not maximized, the maximum width of the body is the width of the browser window, and not the screen. The bined width of the elements is now larger than the width of the body, hence this behavior. Giving the body the fixed width of screen.width fixes this, but there are other solutions too (for example setting the white-space to no-wrap).


Here is the code after the suggested changes:

<!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";
  e.fontSize = "0";            //this line
  e.width = 100*w + "px";      //and this line have been added
</script>
</body>
</html>

I found the reason!

Change your html to

<aside></aside><main></main> 

No space in between the tags because apparently inline block elements do take a ghost space in between! Tackle that by removing spaces between them or adding blank ments in between.

This isn't a "bug" (I don't think). It's just the way setting elements on a line works. You want spaces between words that you type to be spaces right? The spaces between these blocks are just like spaces between words. That's not to say the spec couldn't be updated to say that spaces between inline-block elements should be nothing, but I'm fairly certain that is a huge can of worms that is unlikely to ever happen.

Read more here.

Here is a demo JS FIDDLE

This is a simple css solution

body {
     white-space: nowrap;
}

aside, main { 
     white-space: normal;
}

but since you are trying to avoid the use of style element pletely, alternatively, JavaScript equivalent style setters can be used.:

<!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.whiteSpace = "normal";
          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.whiteSpace = "normal";
          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.whiteSpace = "nowrap";
         /*additional precaution*/
          e.overflow = "visible";
          e.backgroundColor = "black";
        </script>
    </body>
</html>

However, I notice that your calculations are depending on the screen size value, which is most probably the source of the initial problem to begin with.

Regards.

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";

You should be aware that this is a special units for what you are dealing with :

  • vh : viewport height
  • vw : viewport width

Example

Note: you can ignore the section "Visual Stuff"

/* VISUAL STUFF */

aside {
  background-color: hsl(0, 85%, 65%);
}
main {
  background-color: hsl(180, 85%, 65%);
}

/* SIZING STUFF */

body {
  /* I guess you don't need it */
  margin: 0;
  /* prevent white space display */
  font-size: 0;
  /* better keep*/
  white-space: nowrap;
}

aside,main {
  /* your constraint */
  display: inline-block;
  /* Set font size back to normal */
  font-size: initial;
  /* if you want the height to fit sreen */
  /* this means "height = 100% of viewport's height" */
  height: 100vh;
}

aside {
  /* 14% of viewport's width */
  width: 14vw;
  /* and so on ... */
  margin-right: 0.5vw;
}

main {
  width: 85.5vw;
}
<!DOCTYPE html>
<html>

<body>
  <aside>aside</aside>
  <main>main</main>
</body>

</html>

发布评论

评论列表(0)

  1. 暂无评论