Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference in height of element at page load

As this question evolved, the proper title should actually be: Difference in body width at page load.. It also has to do with pictures being resized in the page. If we remove the pictures, the difference is gone.

Please note that this question does not require a practical solution (I could just delay the script execution with a setTimeout() and the problem would be solved). I am asking because I would like to understand the technical aspects of this behaviour.


While writing a script for an answer here, on SO, I discovered a weird difference in height of an element if calculated at page load or later on.

Here's the snippet:

document.initPictures = function() {
  $('.resizeMe').css({
    'height': $('#theContainer .col-sm-6').eq(1).height() + 6,
    'display': 'flex',
    'flex-direction': 'column',
    'transition': 'height .4s cubic-bezier(0.55, 0, 0.55, 0.2)'
  });
  $('.resizeMe img').each(function() {
    var src = $(this).attr('src');
    $('.resizeMe').append('<div style="flex-basis: 50%; background-image: url(' + src + '); background-size:cover; background-position: center center"' + '</div>');
    $(this).remove();
  })
};
document.resizePictures = function() {
  if ($('#theContainer').outerWidth() > 768) {
    $('.resizeMe').css({
      'height': $('#theContainer .col-sm-6').eq(1).height()
    });
  } else {
    $('.resizeMe').css({
      'height': $('.resizeMe').outerWidth()
    });
  }
};
$(window).resize(function() {
  document.resizePictures();
});
document.initPictures();
.main-img {
  width: 100%;
  height: auto
}
#theContainer {
  margin-top: 15px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">

<div class="row-fluid" id="theContainer">
  <div class="col-sm-6 resizeMe">
    <img class="filler" src="http://www.keenthemes.com/preview/metronic/theme/assets/global/plugins/jcrop/demos/demo_files/image1.jpg" />
    <img class="filler" src="http://www.keenthemes.com/preview/metronic/theme/assets/global/plugins/jcrop/demos/demo_files/image2.jpg" />
  </div>
  <div class="col-sm-6">
    <img class="main-img" src="http://joombig.com/demo-extensions1/images/gallery_slider/Swan_large.jpg" />
  </div>

You'll notice I'm making the images in the first div 50% of the height of the image in second div (that was the requirement). On page load, second div's image height comes up short 6px $('#theContainer .col-sm-6').eq(1).height() which I had to compensate for in the initPictures() function, but this compensation was not necessary in the resizePictures(), which happens on $(window).resize().

I'm using the latest version of Chrome, but I've also tested it in latest FF. Same behaviour.

I'd be really happy to understand what's up with this difference. Where does it come from? Does it have to do with Bootstrap, with jQuery? Or with what?

NOTE: When testing, I also tried to use innerheight() and outerHeight() hoping I could get around "the bug". They are all 6px short at that point.

Another NOTE: Just for testing purposes, I made a jsFiddle for this. When I load it normally, as a fiddle, it has the same bug and the compensation is necessary. When viewed in full screen mode the compensation is no longer necessary and it actually renders the left column 6px shorter because of the compensation.


Update: after some thorough testing using AvArt's idea of logging this, it came out it all started from bodys width. By default, for no particular reason, it's not 100vw when the page loads.

You could checkout this fiddle, if loaded at viewport widths above (768 - 17)px. For some reason, some of you never experience this "bug", but I'm assuming some did, since the question has been voted up. However, if you uncomment the last line of CSS, the bug vanishes.

So, with body having a different width for a short period of time at pageload, the width of .col-sm-6 was affected, affecting the auto height of the contained image, affecting the column height. The 6px difference (and sometimes 7) was resulting from the images' particular height/width ratio, but the starting difference in body's width was 17px.

Now, the question is still open: why does the body element have a 17px difference in width at pageload from the 100vw, which should be default, at widths above (768 - 17)px?

The funny thing is it has to do with the pictures, because if we remove the pictures from HTML, the difference is gone!

Anyone familiar enough with how browsers work and how CSS gets applied initially to shed some light on this behaviour?

Sorry for the lengthy explanations, it's just something I couldn't figure out for days, so I just had to ask and find out.


Updated jsFiddle here.

like image 689
tao Avatar asked Dec 07 '15 18:12

tao


2 Answers

The problem is the Javascript execution order. initPictures() must be executed before you check the body width. Fiddle

like image 55
Aureliano Far Suau Avatar answered Oct 12 '22 23:10

Aureliano Far Suau


The 17px difference you're seeing is the scrollbar width.

The document's width is unknown untill all assets are completely loaded, so it reserves some space for a possible scrollbar. In practice, this means that window.onLoad will only execute when all images are loaded. While as jQuery's ready event will fire as soon as the DOM is loaded.

I've created a new Fiddle (http://jsfiddle.net/u7zgz25u/3/) demonstrating this behaviour. (To clear the images from cache, just change 1 of the colors in their url's).

When looking at http://jsfiddle.net/o1g5x5m6/20/ (your example without images), the ready and window.onLoad events are executed at (almost) the same time, before the actual rendering takes place, hence the page dimensions are known to the browser.

PS: I've found an interesting Fiddle demonstrating the scrollbar width being taken into account by the browser rendering, despite a large enough padding-right being available: http://jsfiddle.net/9pAcp/2/

Update

Some browsers implement a rendering delay (e.g. Firefox documentation), hence the difference between the initial width and the width after the images have loaded. If the images are loaded before the initial rendering delay, or there are no images, the browser can calculate the correct height, however, if the images are not loaded yet, and they have no known dimensions, the browser needs to wait for the images to load before it can calculate their size. Hence the possible difference between the estimated document size (with space reserved for a scrollbar), and the actual document size after window.onLoad has been triggered.

See http://jsfiddle.net/u7zgz25u/4/ for a demo on what happens when you define a fixed height for the images in HTML. The 17px difference is not there anymore.

like image 43
Gerrit Bertier Avatar answered Oct 12 '22 22:10

Gerrit Bertier