JAKE: All right, so I think
I might do the intro as part of this rather than just
picking up a random intro, but we'll see. SURMA: Give me one sec. JAKE: We'll see how it goes-- see how it goes. Are you ready, Surma? SURMA: Needed a
quick emergency sip. Yeah, let's go. [MUSIC PLAYING] JAKE: Hello, Surma. SURMA: Hello, Jake. JAKE: You've seen this before. SURMA: Don't I know it. JAKE: Yeah, this
is the HTML spec. This is the full
version of the spec. This is the 12 megabytes-- SURMA: Eight megabytes? 12? Wow. JAKE: 12 now-- they keep
adding to it, it turns out. SURMA: Oh, damn. JAKE: I actually measured
how high this is. This is 1.7 million pixels
high at this rough size. It's a big document-- a pretty big document. SURMA: It's got a
lot of APIs to cover. JAKE: Yes, it takes
ages to fully load, and it is janky all of the
time that it is loading. The bottleneck here
is layout, as you can see from this bit
of Chrome DevTools here. It takes over 50
seconds' worth of layout, and that is on a
high-end MacBook Pro. So yeah, don't do that-- SURMA: Yeah, don't do that on-- JAKE: --on a phone. SURMA: --on an Android go phone. That's going to take-- JAKE: It will melt
through the table, and you'll never see it
again-- melt straight through to the core of the
Earth and will kill us all. So definitely don't do that. But what if I told you with less
than five minutes of effort I made it into 400 milliseconds-- 50 seconds down to
400 milliseconds. SURMA: Two orders
of magnitude less. JAKE: Is that right? Yes. SURMA: I think so. JAKE: Yes, I suppose it is. And I didn't cheat. I didn't delete anything. I actually-- I did some stuff. I didn't break
Control-F or Command-F like searching in the document. I didn't break linking. I didn't break SEO. And I didn't even
write any JavaScripts, and I'm going to show
you how I did that. So, OK, all I did to achieve
this is some minor HTML changes and a little bit of CSS. Specifically, these
two bits of CSS, which are new in Chrome 85-- and it's only in Chromium
browsers right now. But the changes I made don't
break things in other browsers. They just don't get
the optimization. SURMA: And so you're just
applying this to whatever because the HTML spec
totally uses whatever. JAKE: I will show
you the correct class name I used in a minute. Steady on. SURMA: All right, fine. JAKE: I could have
used whatever because I don't think it uses whatever
already in the HTML spec. Maybe-- I don't know. I don't know. But before I tell
you the class name I did use, that can be--
that's the hook that's going to keep everyone, isn't it? Like, they're eager to see what
class name I actually used. It's going to be disappointing. But before we go
into detail, I'm going to show you a
little bit of background. The browser tries to be smart,
like when it displays a page, it doesn't paint everything. It just paints the
stuff you can see. SURMA: It seems like a
pretty sensible assumption. JAKE: Yeah, it's great. And that means it saves
loads of CPU, GPU, and memory by just
painting stuff as you get to it
in the viewport-- as you scroll up and
down the document. But in order to figure out
what's inside the viewport it needs to know the
layout of the page. And CSS is great, right. You can do anything in CSS. One of the things you
can do is take something that's right at the
end of the document, and make it appear
at the very top. You can take something
which is nested in 100 divs, or
elements, or whatever, and you can move it
outside of those elements. So generally, you need
to do all of the layout before the painting. SURMA: Even if you figure
out that a box is completely outside the viewport,
it doesn't mean that you can make any
assumptions about the children inside that box. JAKE: Yeah. Exactly. Yes, it's difficult to
lay out just a small bit of the documents-- until now. We have a solution for it now. Here's the HTML spec in
terms of how it looks-- in terms of HTML. It's pretty flat. It's a pretty flat document. There are 22 H2 headings. Here's the bit you
wanted to know, Surma. You want to know
that class name. Here it comes. I wrapped each section in an
element, and gave it a class. There it is. Enjoy it. And that's all I did. And of course, I used
a regular expression to do this because it's a
quick hack, but it worked. It's fine. SURMA: So I was saying you
parsed HTML with regex. JAKE: Yeah. Yeah-- SURMA: Dun dun dun. JAKE: I just search for those
start headings and those end headings, and I did a-- I did the start and the
end tag at the same time, and then just went and deleted
the first end tag because it doesn't-- Yeah, you know, it's easy. It's fine. It's OK. It's a hack, but it works and
that's the important thing. And then it's the CSS. All I added is
content-visibility auto. This is one of those new bits. And what this says--
this says the-- it's like a
declaration that says the inner layout of this
element can be deferred until this is in the viewport-- until the parent
element's in the viewport. And that comes with
a few restrictions. It means you can't-- SURMA: I wish they
call it deferred now-- content-visibility is deferred. JAKE: Yes, that would
make sense, wouldn't it? Because we already have
deferred for scripts and things like that. SURMA: Oh, well. JAKE: Or actually for things
that enter the viewport, we call it lazy,
so I guess it would be content-visibility lazy. SURMA: That would also be good. I like it. JAKE: If we're going to have a
spec meeting now, let's do it. Let's change the whole thing. Let's unship it. We'll fix it. We'll fix that one word. OK, yeah, fair enough. The word is auto
that it shipped with. And, yeah, that comes
with some restrictions. It means you can't paint
outside the elements, which you'll be familiar
with if you've used overflow hidden before. And it also means that layout
can't escape the elements. So you know CSS has
collapsing margins. This means you can't use those. It's basically like,
that's position-- that's overflow hidden as well. SURMA: Yeah, so by me,
the developer, saying, I'm giving this element
content visibility auto, I'm basically opting
in or guaranteeing that there is no
escaping elements that would make these layout
calculations actually difficult. JAKE: Yes. Yeah-- SURMA: Gotcha. JAKE: So that means that if this
parent element is going to be at the end of the document,
that declaration means that the browser knows that something
inside it can't drift its way to the top of the document
and be in the viewport when the parent isn't. So, yeah, that that's
the sort of guarantee that you give the browser
and it enforces that-- very similar to overflow hidden. This often leaves the
elements at 0 height-- like the height of an element
with no children elements. And that's a problem. Because that means
all of our sections are going to scroll into
view at the same time because they're all just stacked
on top of each other, 0 height. Which is not good,
because that means they're all going to
layout at the same time. So to work around that-- SURMA: Because now they're
back in view with 0 pixel. OK. JAKE: Yes, this is
contain-intrinsic-size, which, I don't know, it's-- SURMA: It's a mouthful. JAKE: --a difficult one to
remember because I always think the first word is content
because the other thing is content. Anyway, doesn't matter. What this lets you do is
set the width and height of the content of the elements
while the layout is deferred. So it's like a fallback
width and height, but you are setting the size of
the content, not the elements. And this is something
that took me a while to get my head around. So it's as if it has a single
child element of this size. SURMA: Well, that would
only make a difference when you have padding, right? Otherwise it would be the same. JAKE: No. No, so it's different
in this case because I've given it in a
inner width of 1 pixel there, but it's still going to
be a full-width element because that's how
block-level layout works. SURMA: Because it's
display block-- right. OK. JAKE: So that's why I
put one pixel in there. Thought, well, it
doesn't matter. And for the height
I just guessed. It was the biggest number I
could think of at the time, so I just put that in. It doesn't matter much
because it's just a fallback. So when it does
the proper layout, it's not going to use
those numbers anymore. It will give it
the correct number. SURMA: All right,
so you basically-- let's say you start at
the start of the HTML spec and you have a table
of contents in view. That means all the actual
top-level sections will be empty boxes with a height of
5,000 outside of the viewport, and the browser
can skip layouting all the actual children. Because you know
what, don't bother. Just assume that once you've
layed out the children, 1 pixel by 5,000
pixel is the result. And now when you scroll
towards the next upcoming section that's where
the browser goes, wait this is now actually
very close in viewport. I'm going to the
actual layout, but just for this one following box. Which might mean that
this section could be larger or smaller than this
1 pixel by 5,000 pixels, right? JAKE: Yes. Yeah, the actual
layout could be-- yeah, it could go either way. SURMA: So could
that cause problems? JAKE: There is one
side effect of that, and I will come to it in
a minute, but largely no. It's OK. But yes, like you're
saying, the browser can keep the layout
really, really simple. And it isn't till the
user starts scrolling, and then it goes, oh, I'm
going to add that more layout because they're
getting close to that element. And it just defers
all of that work. But yeah, that's literally
all I did with the HTML spec-- just those small changes. And that is what took the
layout time of the spec from 50 seconds down
to 400 milliseconds-- 0.6% of the original. And like I said,
it doesn't break Control-F. That still works. SURMA: That's a big deal. It reminds me a bit
of infinite scrollers where, for example, Twitter
has these things where you have the tweets
in the viewport and a couple of tweets
outside either end. When you start scrolling
the things at the top will get recycled to
be reused at the bottom to keep your DOM count low
and keep layout costs low. But those implementations are
A, JavaScript-driven, and B, break Control-F. Which
I've run into where you try to find a tweet you
just saw on your timeline, but because it's
scrolled out of the view and has since then
been recycled, Control-F won't find it anymore. JAKE: Exactly, yeah,
I've run into that, too. When you do Control-F on
the HTML spec demo I built for this, it does slow
down, because you need-- When you do Control-F, you're
not just searching the markup. You're not even just searching
the text in the document. It depends on style calculation. It might depend on
some layout as well. So it has to go and
do a lot of that. And it could do it in phases. It could do it deferred a bit. But to tell you how
many matches there are in a document it's
going to have to go and do a lot more work than
it would do if you were just regular scrolling. But it works, and that's
the important thing. And it doesn't break
linking either. If you link to an
element that's inside one of these deferred layout
things, it will figure it out, or at least it will soon. In the making of this demo,
I found a bug with that. I filed it. And it's been fixed. So maybe by the
time this episode goes out it will all be-- SURMA: That's actually an
interesting point, though, because things like
display none will affect Control-F and
other things as well. That style
calculations will still affect the entire document,
and will become more expensive the bigger your document is. It's really
[INAUDIBLE] layout that gets cheaper with
content visibility. Is that right? JAKE: Yes. Yes, it's just layout. Layout's the only
thing it saves. But, yeah, with
searching for text you can have two elements which
are right next to each other in the source-- there's no space between
them-- but because they're both block level there is no,
as far as humans are concerned, line break between them
that isn't in source. Whereas if those
two were inline, then there's no
space between them. So, yeah, there's a lot
of layout information that you need to think of to
actually effectively search for text in the document. But, yeah, it's all just taken
care of, which is just great. Here's a live demo. Now, you were
asking me what might be the problem with me just
putting 5,000 as the box size. Watch the scroll bar
in the top right. So as I scroll down,
there's a little jump there. The scroll bar jumped down. And as I scroll
further, and further, and further eventually you
get to another section. And it jumps up. And this is it switching from
its imagined fallback layout to its actual layout. And it has to adjust the scroll
bar to the account for that. But that happens
on mobile platforms already for the same reasons-- that you guess the height
of certain elements and the scroll bar moves
around and adjusts itself as it figures stuff out. I think it's fine. SURMA: Yeah, it's
really a question how much scroll bar consistency
or inconsistency in this case is a big deal. Because infinite scrollers have
the same problem to an extent. And I guess it becomes
a lot weirder when you load a page with an
anchor that you start in the middle of the
document, and you scroll up and the scroll bar
jumps back down. And I guess it still works
if you click and drag. It doesn't break clicking and
dragging the scroll bar itself. That still works. It probably behaves a bit
weird, but it should still work. JAKE: Yeah, it
still jumps around, but it doesn't break
the mouse interaction. It just looks a bit weird. But, yeah, that already
happens on mobile platforms. One other thing in that demo-- I don't know if you noticed
over the Hangouts call we're on now-- but
there was a bit where it was a flash of white. Well, not a flash of white. It scrolled into a white area
and it took a while for it to draw a bit. And that's because,
like I said, there's 12 headings in this
massive document. So I only have 12 sections. And so I scrolled into
an area where it actually had to do quite a lot of layout
work to be able to render it. And you could see that. I could fix this by just
making smaller chunks. So that's one thing to think
of as a developer with this is the number of chunks. More is generally better. If you have too
many at the start, then you increase the
upfront layout work where it figures out where
all those chunks are. But if you have
too few, then you risk that thing where
scrolling to a particular area is still going to
be quite expensive. Another effect-- SURMA: Could you nest
content-visibility? Now you have the
top level H2s that are now all content-visibility
auto with their intrinsic size. Could you now apply the same
mechanism to the H3 headings, so that the stuff
inside the H2 in itself again uses content-visibility
to create those smaller chunks? JAKE: Yes, you can do that,
and it all just works. SURMA: Great. JAKE: But that's why
it's complicated. And that's why we
had a bug when it came to linking to a specific
anchor through the document, because it knows that
anchor is inside this box. So it scrolls to that box,
but then it has to layout. And then it realizes, oh, no,
that anchor is now somewhere else, so it scrolls again. And then it might have
to re-layout because of all of these boxes
becoming visible that weren't visible before. And that's the bit
that we hadn't done. That's the bug we
had is we were only scrolling to the
fallback box and it was-- SURMA: The initial position. Yeah, OK. JAKE: Exactly. Another nice effect for
this is the time resizing. So resizing here is super
smooth because there's not a lot of layout work to do. So it's nice and
quick, and that will be quick on mobile, desktop. We compare it to
the real HTML spec. And this is an extreme example,
but it's taking over 10 seconds sometimes to figure out the
new layout for the new width. It really lags behind. SURMA: I mean, you say
it's an extreme example, but using this bigger
document on a fast machine like you're using
is probably somewhat representative of a normal-ish
document on a low-end phone where you go from
portrait to landscape. That could still happen,
and there would still be benefits to making
those operations faster. JAKE: Yes. Yeah, and even in some cases-- popping open a
keyboard in and out is going to change the
viewport size to some extent. So, yeah, this is
an extreme example. But have a look at
your site, and have a look at the layout time. And if you're hitting a
large-ish layout time-- I'm not saying like 50 seconds. If you have three
seconds of layout time, and if a lot of that is
content that's out of view of the viewport then there's
a quick win right here. And you might not even have
to change any of your HTML because you might have those
sections all boxed up already. So you're just adding
like two lines of CSS, and you can knock
seconds off your layout, and even if you're knocking
just a few milliseconds off. It's almost free to do it. We've had sort of
CSS containment stuff in the browser for years. You've been able to
do some of this stuff, but it's been such a
lot of manual work. But now, couple of
lines of CSS, job done. SURMA: I actually would love
to see this in more blog templates-- just
built in by default-- where this seems to be
the perfect application. Which is when you have a lot of
text content potentially, just don't layout the
stuff out of view. It's magic. It's great. JAKE: Yeah, and not just blogs. We'd see, particularly the
news sites that have lots of-- especially on their home pages-- lots of complicated
layout stuff going on-- quick win right there. SURMA: Right there. Free performance. JAKE: And that's all I've got. SURMA: Well, thank you, Jake. JAKE: You're welcome, Surma. It's been a pleasure
and an honor. And we're out.