Anyway, it is time now, so we're going to start.
Before I start, though, I think we should address the elephant in the room, which is my
hair.
Obviously, you might be wondering what's going on with that.
Well, for a long time now, I have become what is typically called follically challenged.
Okay?
I've been going quite bald.
And like many men in my situation, I just decided to go to Turkey to get a hair transplants.
Now, little bit, I know that the clinic that I chose, not part of the gang.
Little bit, I know that the clinic, the hair transplants clinic that I chose, only use
this hair, donated by browser developers.
I don't really like Zen AI, but for this kind of thing, I like to make an exception,
just get everything so wrong.
Am I trying to say that all browsers developers are clowns?
No.
Okay?
They sometimes do seem to do some clowning things, though.
Okay?
Case in point, what we're going to talk about today is that some of the browsers do
with I, it's called a two phase or a two step loading process, where they don't load
everything on the page at once, they load one part, and when that's done, they start
loading the second batch of resources.
Because of this, you get rear situations like this, where we have three very different
waterfalls in the tree browsers for the exact same HTML page.
Same HTML, and it's a very simple one we're going to show it later.
All HTML still loads radically different in all the three main browsers.
Now you tell me, that is not a bunch of clowns trying to take on their audience with
superjumps, okay?
So what I'm going to try to do today is try to explain why this happens, why these loading
behaviors are there, and then maybe also give some ways to try and combat these inconsistencies
between browsers.
So let's start with the Y, and it turns out that it's not the browser developers who
are the clowns, it's usually more the server developers, okay?
You wouldn't believe the weird stuff that servers do.
This one, for example, send back, I requested images in one, two, three order, it send
back in, three, two, one, okay?
And in this case, the first image that's up on there was my largest contentful paint
image, so the most important image on the page, and when a Google looks for a looks
out for SEO things, so that was delayed behind these two other less important images.
It's not just these simple examples either, this is a more complex one, where a very
important JavaScript on top, and some important fonts also were being delayed by a bunch
of images, these purple things in the middle.
A ton of images that I really didn't need at that point, I really wanted to JavaScript
first, but the server was sending me other stuff than I had requested.
Now, you might think, Robin, how is that the server's fault?
How is the server supposed to know what it needs to send?
Well, because the browser literally tells the server what it needs to send when, this
is only called the prioritization system, so the browser is basically going to assign
a priority, a level of importance to each type of resource it's discovers.
For example, when they're blocking CSS in the head, super important, highest priority.
Partial blocking JavaScript is also important, high priority.
The third JavaScript, if you add the third, that means that the browser can execute
this JavaScript after the main page is done loading, so it doesn't really have to execute
or download immediately, so it gets a low priority.
Then you have things like preloads, things that the browser knows it might need, but
not discoverable right now, might get a medium priority.
The browser actively tries to guess which things are most important when, and it communicates
this to the server.
The way the data does this are difficult to explain, most modern browsers you can now see
this in a request header.
There's literally a priority request header that tells you when which resource should
be coming in.
This is very important, especially for HTTP 2 and 3, because they use a single underlying
TCP or quick connection to send the resources on.
They have one connection for many different things, and if they get the order wrong,
there's not going to be room on that connection for the more important stuff if you keep
sending me low priority images server.
So it is important if we get these orders straight, and again it's a server who often
make mistakes in this.
This is research I did a couple of years ago.
The top is what the browser sends, this is the browser is expecting to see that.
You can see a lot of some very well-known servers, get it nearly right, Apache, not quite
right, and then completely wrong, no chase.
The thing is this last one is actually one of the worst possible cases for but performance.
If you send your resource like this, your page is going to take a very, very long time
to load.
You might say Robin, oh, the research you did a couple of years ago, since then we have
HTTP 3, everything is much better, right, right.
I did research again last year, this is very fresh, looked at a ton more, very well-known
companies in hosting the virus only 2, 2 out of all of these, get this right, it's not
that everyone else gets it completely wrong, okay, there's a lot of great area in there,
but still only 2 of these actually do what they're supposed to do and listen to what
the browser is telling it, okay.
So with that in mind, imagine that you are one of these people, okay.
One of the browser developers, how would you deal with this, right?
You have a browser you see in your analytics coming in, a lot of servers are not listening
to us, they're doing very weird stuff.
How can we protect ourselves against that if the server isn't even listening, okay?
And one of the ways they do that is a thing that I mentioned before, this two-phase loading.
The idea there is, let's say you have a web page with 100 resources, if you request
all 100 of them at the same time, which you could, it's allowed in HTTP 2 and 3, should
be possible, if you do 100 at the same time, the server has a 100 different ways to
mess it up.
However, if you only request the top 10, or maybe top 20, most important resources first,
and you delay the 80 other ones until those are done, then yes, the server is still going
to mess up those 10 to 20, but at least only those at the beginning, you're not going
to be delaying your JavaScript for very low priority images down the line, right?
So that's kind of one of the main reasons that we have this set up, so browsers trying
to protect themselves against Rome servers, not the only reason this is still around,
but one of the main reasons that we have it.
And because of that, it's one of the main reasons that we get these very different waterfalls,
because of course, of course, none of the browsers agree on how to best do this to face
loading thing, okay?
All of them have a different opinion on how to best do that.
And when I started, it was very frustrating, because almost none of this was documented
at all.
The only thing that we had was a Google Doc from one of the chromium developers that had
a very short description of what this was doing, we're going to look at it soon, very short
description, and that was it, super vague, super difficult to interpret, there was nothing
for Safari, nothing for Firefox.
This has since slightly improved with a couple of articles, may or may now be due to some
of my nagging to be honest, but still it's very under documented what this does and how
it does it, so that's why I'm doing this talk today.
Because of this, because of the under documentation, I had to do a lot of my own research,
so I've been spent a lot of weeks, setting up different types of sites, trying out
them in the different browsers to get this working.
So I'm going to present to you my research now, and because I know that the academics
like that, I'm going to try to change it to a bit more formal wear, like this, to get
the mic going, there we go, very nice.
So let's talk about the results.
I'm going to talk about Chrome first, because it has the most complex and most evolved
system in here, so we can get all of the concepts from Chrome, and then we can look
at Safari and Firefox next.
So again, Chrome, for a long time, all we had was literally these four lines in that Google
doc, that's all you got, and we're going to read them now, they're not very intelligible.
So Chrome loads resources in two phases.
Tight mode is the initial phase and constraints loading lower priority resources, so
it delays lower priority resources until the body is attached to the document, until the
body is attached to the document.
I have no clue what he's saying, luckily the writer anticipated my stupidness, they actually
added another line to say, what does that mean?
It means essentially after all blocking scripts in the head have executed, so all blocking
JavaScript in the head has to be done executing before tight mode can exit.
Keep that in the back of your mind, that's going to be important.
Last sentence is, in tight mode, low priority resources are only loaded if there are less
than two in flight requests at the time that they are discovered.
I'm not going to explain that one, we're going to see a couple of examples of that later,
but I hope you can agree with me, this was not clear at all what the browser was trying
to do.
So I had to put on my academic where.
First thing we need to understand is what do these lower priority resources mean?
It delays lower priority resources, what does that mean?
Well, Chrome has a specific way of giving priorities to resources, HTML and CSS are going
to be highest priority, JavaScript in the head, so the synchronous blocking JavaScript is
going to be high.
One kind of depends, asynchronous and defer JavaScript is obviously going to be less important
because it executes later in the pace load, so Chrome gives it a low priority, similar
to images in the body, they also get a low priority.
Now, when the document says low word priority, it actually means medium, low and lowest.
So during tight mode, that first initial phase only highest and high resources will
be loaded, everything else Chrome intentionally delays until that is done.
And I can very easily illustrate that with this very simple page.
These are just two rendered walking JavaScript, so synchronous JavaScript in the head and
then 10 images.
And I've intentionally delayed those JavaScript, the server waits two and a half seconds
until it starts replying.
So you go clearly see that while the browser has discovered all 12 resources at the same
time, it waits requesting the images until the two JavaScript are done.
Wait to requesting them, not even downloading them, requesting them until the two JavaScript
are completely done loading, clearly showing that there is this tight-moting going on.
Now, this is what you would have seen in Chrome about a year and a half ago.
If you do this now, you will see something more like this.
There are suddenly five of those images are being loaded in that tight mode at first
phase as well.
And this is because about a year and a half ago Chrome made a change to its priority system,
where it says the first five images on the page are not the default low priority, they
are now the medium priority.
The idea being that that largest commonful pain image is probably one of those first
five, so if they make this change at a browser level, they might improve LCP times where
the internet as a whole, that was the idea behind this.
You might be still be confused because medium is still not allowed in tight-mote, but
still they were downloading in tight-mote.
So they also update the tight-mote logic saying that from this point on, tight-mote
can also load two medium priority resources at a time.
That explains what we saw then, so we have the two JavaScript's tight-mote, and then
there are two medium at the time, so the first five images, the first two can start.
When those are done, we have allowance for two more, two slots open up, those and then
there's one just left over, gets loaded.
And then we again have to wait until the end of tight-mote before requesting the next
images.
So that's the basics of this.
So let's get to that weird, lost sentence of that paragraph that I showed before.
Low priority resources are only loaded if there are less than two other in flight requests.
So what I've done here is the same page, but I've just delayed the first JavaScript a bit
less.
It already returns after, I guess, a second and a half, but the other one keeps running.
So what you have from the point that the first JavaScript completes, there is only one
high priority resource in flight, that JavaScript, which means we can now start loading one
lower priority resource as well, which is the first image.
So that one gets done, again, a slot opens up for a low priority image, the next one,
the next one, the next one, the next one, that's one so forth until tight-mote is done.
So that's what that second sentence means.
How does that still make sense?
Because from now on, it's gloves off.
Something that I found very surprising is that tight-mote really is only while they're
blocking scripts being downloaded, not CSS.
This is a very similar page, just without JavaScript and just three CSS files in the
head.
And even though the CSS files were rendered blocking, there is no tight-mote.
Everything gets requested at the same time, because tight-mote is only triggered by scripts
in the head.
Very surprising to me was even surprising to browser developers at Chrome that I talked to,
because they thought it was included.
Fantastic.
So now that you guys all know the basics, it's time to put that to the test.
I'm going to ask you to think a little bit for yourself.
You don't have to shout out anything just think for yourself.
Given this page, what is that going to look like in a waterfall?
And why?
How is this going to get loaded?
So we have two rendered blocking javascripts of high priority, two deferred javascripts,
which in Chrome are going to be low priority.
And then we have our 10 images again, first five, or medium, and then we have five
lows.
10 seconds, imagine what the waterfall is going to look like.
Now we realize this is a bit difficult to really do this, you kind of need a nose for
these kinds of things.
So let's see.
What basically happens is we first download those two high javascripts, I priority javascript
images in tide mode, along with the five medium priority images.
And then after tide mode is done, only then do we request the deferred javascript and the
rest of the images.
Now I hope this is somewhat obvious given the explanation I did just now.
It just followed these priorities.
That's what it does.
To me, when I started out web development, and even a couple of years ago, this would not
have made any sense.
I would have thought things in the head of the page should be much more important than
anything in the body, that's why we have the head versus the body, right?
This is clearly no longer the case.
And this might be obvious for some of you here, I can pretty much guarantee that,
especially for newer programmers, newer developers, this might come as quite a shock.
When they first discover this.
So this is Chrome, Chrome really follows the priorities to determine tide mode.
Let's talk about Safari.
Yeah.
For those in the know that it's not very polar, by the way, that's someone else.
Safari, very interesting, I did the exact same test.
So Chrome is on top Safari on bottom.
You can immediately see two clear things.
Once Safari clearly has that tide mode.
It is still delaying requesting those images until the JavaScript is done.
So it has a tide mode.
Second thing, it doesn't do that medium priority thing for the first five images
that Chrome does.
It's still basically what Chrome is doing up until you're in half a go.
It also does that weird.
You can download lower priority things if there are only one other thing in flight at the same
time.
That's also the same as Chrome, very clear.
Again, here are the similarities and everything goes in different directions.
For example, I just told you that Chrome doesn't really care about CSS in the head for
tide mode, only scripts.
Well, Safari does, because of course it does.
And Safari, if you have CSS in the head, it is going to trigger tide mode and it is going
to delay images or more priority stuff until the CSS is downloaded.
Very, very clear difference between it too.
Then I decided, let's look at what happens if I move my JavaScript outside of the head.
Because again, Chrome says only blocking stuff in the head.
So if I put the same exact same JavaScript on top of the body, which by the way is still
partial blocking is still going to stop rendering the page, same effect, but Chrome doesn't
really care.
It says, oh, it's not on the head.
I don't need tide mode, I'm just going to request everything at the same time.
Safari does not.
Safari indeed says, this is a blocking JavaScript, everything after it should be blocked.
And I thought, okay, that's going to be everything after it, so I wanted to verify that,
so I put everything on the bottom of the page, you can indeed see Safari seems to do what
I thought it does.
Nothing before the JavaScript are being blocked, so just to be sure, just to cover all
my bases, I had to go ahead, I had to do it and put the JavaScript in the middle of the
page.
I mean, at least Chrome is consistent.
Safari, I tried, I really tried to find out what the hell it is doing.
I couldn't find the logic that they're doing sometimes.
They do block stuff before, sometimes not, sometimes even block things after.
It's very inconsistent, but it is clear that they do some more advanced logic and Chrome
when it comes to resources in the body, okay.
So slightly more difficult exercise, exact same HTML people, exact same, I didn't change
anything about the HTML.
What is this going to look like in Safari?
So let's see, Safari obviously has time mode, what is requested in time mode, the
high priority JavaScript, but also the deferred JavaScript as well, right, and I tested
this further, even if there is no synchronous JavaScript, what's going to happen, Safari
is not going to trigger type mode for deferred asynchronous JavaScript, so by itself it
won't trigger type mode, if it's not going on, but if type mode is in effect, they will
get requested during type mode, just to make things easy for web developers.
And again, to reinforce, this is what it looks like, Chrome, very, very different in Safari
because they fundamentally treat these things differently.
So for Chrome, I kind of can't know what's going on now, it's kind of what the dog says.
Safari, I'm still a bit in the dark, I have the high level things that they do, but they still
have some weird characteristics going on there like with Async and Defer that I don't know
why they're there, what the logic is behind them, or how consistently they're being applied.
Okay.
That's Chrome and Safari, let's go to Firefox.
This is a little bit dangerous for me right now because there are a ton of resilience
in the room.
Please don't kill me.
For Firefox, I can actually be quite short, it doesn't do type mode at all.
Whatever you put on your page, Firefox is very happy to just request it all at the same
time.
Thank you very much.
That's a server development.
It's a way the most pure of the three browsers because it trusts in the standards, it trusts
in the networking algorithms that they will get it right.
Now I did this talk a couple of months ago and I didn't explain this further and it
talked up post it to YouTube and I got a lot of views including some of the Firefox
fine club.
Apparently these guys have a lot of very passionate, very vocal fans who believe that
Firefox is the best browser and they kind of misinterpreted what I was saying.
They thought that I said, oh, it doesn't do type mode, which means it is somehow the
worst browser or the slower browser of the three, that's not what I was trying to say
at all.
In fact, you could argue that for servers that do it correctly, Firefox should be a little
bit faster because every thing, the server can correctly prioritize things and it can
start filling caches, start pulling things in the room and origin if you're a CDN.
So it should actually be faster for proper servers and even on servers that make mistakes,
it's highly going to depend on what the server is doing and the web page, if that actually
matters that much in practice.
So I'm not trying to say the far from somehow the worst browser for not doing type mode,
the main message again I'm trying to bring is it's crazy that all three browsers handle
the same simple HTML page in such different ways.
It is very confusing and very annoying if you try to make a web page that will perform
well in all the three browsers.
And for a long time, it was even more annoying even more confusing because there was actually
no way that you could manipulate the browser so you could tweak the behavior there was no
way to do that.
Let's say the browser gets it wrong and there's something in type mode that should be not
or vice versa.
There was no way for you to manipulate that and you were stuck with the browser was doing.
Now luckily over time people got the message that we needed some kind of mechanism to
improve this, to be able to deal with these browser consistency.
We needed a weapon of our own in the fights against the browsers and this used to be a balloon
sword but the radiators are way too warm.
That's a popping you've heard at the beginning.
So let me use my backup, let's go on the katana, let's see that.
The weapon that we eventually ended up with is something called fetch priority.
You can now add fetch priority to just about anything like a ton of things can now be manipulated
with fetch priority and that directly influences that priority that the browser decides to
be given resource.
You don't set the priority directly.
You can only do fetch priority high or low, not highest or lowest or medium, that's all
where it works.
What you're basically telling is the browser, it should be a little bit higher than what
you might think it should be or lower than what the browser thinks, not the fixed priority.
We're going to see that creates issues of its own.
But with that, that is a very powerful tool to indeed try and move some things around
in the page loading process.
For example, if you have something in the second phase that you want to get in the
tight mode, that's very easy to do in Chrome because, again, it's all priority based.
So far, it's slightly more difficult because it has other heuristics and practice
I only found this to work for images.
But that is the most important use case anyway, which is trying to put fetch priority
high on your LCP image.
So you're going to just come up with a page image that one image that Google looks at
for its metrics.
If that is in the second phase, it's going to be slow.
Which fetch priority high you can bring this into the tight mode phase, so it loads much
earlier.
Both in Safari and in Chrome, yes, I kept the slide in.
It's slightly more difficult to see in Chrome because it has weirder waterfalls.
But here again, the fifth image there will get requested at high priority early on because
it is the LCP image.
That's one way you can get things into tight mode, then you might also want to get things
out of tight mode.
The browser is too eager.
You know that you won't need this resource early on, so you're explicitly telling
the browser, please back off a little bit.
Again, Chrome works very well, fetch priority low works very well, and it's a variety of
use cases.
Safari, I tried, I couldn't find a single one.
The main use case I wanted to use this for was what we had before, right?
You have your defer JavaScript that I know won't be needed.
I don't want to load my defer JavaScript that early on.
I want an out of tight mode into the second phase, there's no way to do that.
I can put fetch priority low on it, and it lowers it from high to medium, but it doesn't
shift it out of tight mode, other characteristics to determine what it should look like.
Chrome and Safari, the use tight mode, Firefox does use tight mode at all, which means
that fetch priority is a super powerful mechanism in Firefox, because you have very fine
grain control over how to order resources at the server, which is why it's slightly ironic
guys that Firefox was the last browser to actually shift this, but I'm very happy to say
that they shift this a couple of months ago.
That's now available in all the browsers, very nice.
And Firefox's implementation is actually quite good.
It's quite flexible, it's quite advanced, you have a lot of control over all the things
that you want to do.
And they even add a documentation page for it.
In 2025, can you imagine that?
Amazing.
But seriously, thank you.
The problem is, even with this, even though we can now very fine grain control Firefox,
that's not enough, because if we optimize everything for Firefox, we might still make things worse
in the other two browsers, because you guessed it priorities are not consistent along the browsers.
I always like to use the font example, because it's so weird, for fonts, normal fonts
are going to be highest priority in Chrome and low priority in Firefox, almost complete opposite.
And if you don't preload the fonts, so preload is basically the font is probably going to be in another CSS file,
but I know you're going to need it, so maybe you could start requesting it earlier.
That's how preload does.
browsers take it as a very different signal.
Firefox says, oh, you're telling me about a new resource.
I'm going to bump it in priority, it goes from low to medium.
And Chrome says, oh, you're telling me about this resource, that must mean you don't like it at all.
I'm going to move from highest to high.
Let's make it worse, let's add fetch priority.
fetch priority high, Chrome does not care about your fetch priority high, okay?
It wasn't high, it was going to stay at high.
Safari and Firefox are going to bump it one, so for medium time, fetch priority low.
Chrome and Firefox make it minus two, because minus one is so douchewa, you know?
Why not go for minus two to really give a kick?
What's the Safari just goes for minus one, obviously, right?
So they're very inconsistent, this is a problem because bumping these things around will impact
other resources that are their own priorities.
And they also have other inconsistent ways of distributing this.
So you end up not knowing what the order of priorities is going to be in all the other browsers,
if you optimize for, say, Firefox.
And the best example of that that I found for today is that there is no way in Firefox
to get that LCP image to load before your default JavaScript.
So let's say we have, on top, we have a default JavaScript and then an image without fetch priority high.
By default, you would load the JavaScript first and then the image.
That's a default, occasionally, behavior in all the browsers.
In Chrome and Safari, as you can tell, if you add fetch priority high,
the image is now going to get a higher priority than the JavaScript,
and it's going to be loaded before the JavaScript.
When or without type mode, this is even, uh, have to do with type mode anymore.
When or without type mode, your image is going to come in before your JavaScript, as you probably
want, because this is your LCP image.
In Firefox, you can't do that, because for some reason, Firefox images begin at ultra low priority.
That's one step below lowest. I had to invent that just for Firefox.
Okay, everyone else is low. Firefox is at ultra low.
So yes, doing fetch priority high bumps, it two steps from ultra low to low,
but that's still the same as the D for JavaScript.
So there's no way to get your, um, to get your LCP image on top of your D for JavaScript.
Without also marking the D for JavaScript as fetch priority low.
Okay. Now, pre-empting the Firefox Fan Force 5 Club.
Okay, I'm not saying this makes Firefox a worse browser.
Okay. In fact, I could have easily shown examples where, um,
the other browsers don't allow you to do things. In fact, I did show some examples of that, right?
It's not the Firefox or any of the other as worse or faster.
And again, mainly talking about how frustrating it is that they all do things in so many different ways.
Okay. This means that for me as a developer,
it is almost impossible to create a web page that performs,
that has good web performance and consistent performance on all three of the browsers.
Almost impossible in today's ecosystem.
And I could forgive this if this was just tight mode and if it was just a priority.
Maybe. But of course, I looked at tons of other stuff as well. I didn't have time today.
Believe me, none of these things are consistent along the browsers.
And they can have very big impacts on how resources are loaded and when things get drawn on the screen.
Right? It is not just one or two things. It is the whole ecosystem. It's very difficult to do.
And that brings me to the original inspiration for today's talk, which is this meme.
If you're a new web developer starting now, even if you follow the standards,
even if you use one of the big known platforms and CDNs,
you cannot be sure that your thing is going to be loading well in all the browsers and all the environments.
It's not really the fault of the developers either.
You know, we have been trained to look at just what I like to call the Chrome web titles.
Not the core of the titles, the Chrome web titles.
Even though, as we said, Firefox is doing an excellent job in catching up there.
Safari, of course, is not. People look at this. People mostly test in Chrome.
And they think whatever works well in Chrome is also going to do well in Firefox.
And Safari, and as I just try to explain, that's absolutely not the case.
And because these metrics are missing for the other browsers and some tools are missing for the other browsers.
People typically don't test, don't verify.
So a lot of sites, I think, are much slower on Safari and Firefox than they could be or should be.
What I think we need, I'm not sure that the browsers need to be more consistent with each other.
It's very difficult to know which browser is doing it right. It's very difficult to know which is the foster approach.
I would settle for having this all well documented.
Having this properly on, you know, something like Web.deph, which is way too Google focused for me,
even though it's a great resource, even on something like MDN, which is way too focused on the standards for me.
It doesn't actually explain things that are not regulated by standards like everything it's talked about today.
We need more documentation.
We need more people to be aware of this so that they can actually test for these outliers.
So I'm hoping to contribute with my talk today.
I'm going to finish now because I'm all out of time with the best analogy, the best analogy
I've ever found for how an HTTP3 connection works.
Thank you very much.