Load script when layout is known?

css

#1

Until recently I thought this was essentially equivalent to when the DOM is loaded. Then when using a script that resizes text, depending on container (Fitty), I started seeing a problem where the calculations were wrong. I initially opened an issue for Fitty. I then found that other scripts were doing similar things (with less dramatic results). Popper.js and Swiper were both getting calculations wrong. Resizing the viewport in all cases would trigger a recalculation, fixing the discrepancy. (This seems to be more of an issue in Firefox than other browsers.)

The only way I could get any of these scripts behaving reliably was to run them on window.onload. This feels a bit heavy handed, and also like it might be fixing the problem by way of an arbitrary delay. There is no need to wait for images to load in any of these cases (either there are none, or the layout isn’t effected by them).

So is there a way to say “run this when the bowser has loaded (and processed / calculated) the CSS”?


#2

You might be looking for the DOMContentLoaded event instead.


#3

That doesn’t wait for stylesheets to load, so is sort of the opposite of what I’m looking for, no?


#4

As the browsers only seem to have DOMContentLoaded and onload while loading the page, and one of them isn’t suitable, then using the other as you currently are doing looks to be the only other viable alternative.


#5

Well, no matter what, you’re going to get heavy handed with this.

The easiest method i can think of is to use Javascript to load the CSS. There’s no way to wait for ‘processed/calculated’, but it will mean #1 your script is loaded and #2 the CSS is loaded.

var css = document.createElement('link');
css.type = "text/css"; // set up the link's attributes...
css.rel = "stylesheet";
css.href = "http://mysite.com/css.css";
css.onload = () => { 
   //Do Your CSS Loaded Stuff Here.
}
document.getElementsByTagName('head')[0].appendChild(css);

#6

So taking a slight step backwards, are you confirming that just putting the script at the end of the document, and/or using defer is not enough to know that the CSS (linked in head) has loaded? I ask because that seems to be standard practice. I don’t think I’m talking about edge cases here, popper.js for example is widely used (it’s in Bootstrap).


#7

Most Javascript doesnt care if CSS has been loaded or not.

DOMContentLoaded’s relation to the CSS is ambiguous.
Externally loaded files should load in the order they area placed in the HTML, but practically is also ambiguous due to server response times etc.

AFAIK, nothing prevents Bootstrap from working whether the CSS has loaded yet or not. The browser should process calculations as per ‘new information received’. Do you have a working example of where this is going wrong?


#8

I haven’t had a chance to create a reduced test case, but I can give examples of where this was going wrong, before I put things inside window.onload functions (I don’t know how useful this is).

The drop-down under the RSS icon on my blog article pages uses popper.js, and didn’t work in Firefox. I’m guessing it was positioned off the screen.

The photo galleries on that site use Swiper. That script adds a width to the image wrapper. In Firefox the width would be incorrect (slightly smaller than it should be).

In both cases, resizing the browser would fix the problems, presumably because it was triggering recalculations. I’m speculating that the second calculation is correct because the CSS is now loaded, or perhaps because the browser has now interpreted the absolute position of the RSS link in the first example, and the size (relative to viewport) of the flexbox elements in the second example.


#9

Was your comment about DOMContentLoaded based on experience or something else?
Have you tried it yet in your application?


#10

It was based on the description on the page you linked to:

The DOMContentLoaded event fires when the initial HTML document has been completely loaded and parsed, without waiting for stylesheets, images, and subframes to finish loading.

I don’t think I tried it… Testing is slightly complicated by the fact that this problem doesn’t arise in my dev environment.


#11

I get identical loads on FF and Chrome of that site, or the difference is so small that I can’t visually identify it.

I see the same dropdown in the same position on both FF and Chrome.

Are you sure you havent got something loaded into FF that’s causing your issues?


#12

I look forward to a reduced test case that demonstrates the problem, for further investigation.


#13

@m_hutley unhelpfully you won’t see the problems, as they are “fixed” by the window.onload. Those descriptions are what happens without window.onload.


#14

Mkay…

But i’m failing to see how “run this when the bowser (sic) has loaded (and processed / calculated the CSS)” is any less “heavy handed” than window.onload?


#15

It’s waiting for images to load that feels wrong. Having to load images to see a dropdown, for example.


#16

So you want to load a script when the layout is known… but without knowing what the dimensions of images are that are going to be loaded.

I’m not sure this is as fully fleshed out of a logic path as you might think it is.


#17

Yeah. If you have an element absolutely positioned at the top of the page, as in the dropdown example, images loading (visually) below it do not determine where that element is going to appear (visually).

Even with the gallery example, the size of the element in question is the same (width of the viewport x height of the viewport minus fixed height of thumbnails), even if there are no images, because its determined by the CSS.


#18

“It’s determined by the CSS”
Except CSS can be overriden by later CSS, or by Javascript, or… or…

The browser cant make an assumption, or do calculations, until it has all of the relevant pieces of information.

I still dont see a value over window.onload, but… at this point anything you try and work around is going to be as, if not more, involved than that. shrug


#19

OK, so putting all scripts that manipulate size and/or position inside window.onload / window.addEventListener("load") is the reasonable thing to do, in your opinion?


#20

Yes, I would consider putting things that want to depend on things being loaded to wait for the load event. :slight_smile:

Are you anticipating your scripts to be loading images from a potato or something?