- [Instructor] Perceived performance plays a major role
in improving the user experience and for websites and apps,
the number one measure of perceived performance
is how fast something loads in the view port of the browser.
That means the goal is to load the content above the fold,
meaning in the user's view port as quickly as possible
and then load the rest afterwards,
so the user has the experience of the site loading faster
than it's actually loading.
One major blocker to this is CSS itself.
For a page to render, all the CSS has to be fully loaded
because CSS is a cascade and the rule sets at the bottom
of a style sheet may well impact the rules that's higher up.
If we serve the browser with a huge style sheet
with all the styles for the page,
it takes a long time to load that style sheet
on this content and the performance suffers.
To get around this problem, developers have come up
with a clever hack called critical CSS.
It works like this.
First, inline any styles impacting the content
above the fold in the HTML document itself as a style tag
in the head.
Then lazy load and defer the rest of the CSS,
using a clever JavaScript trick, so it only loads
when the page is fully loaded.
This works because the inline styles are loaded ahead
of the dom elements and the document
and therefore render right away,
while the rest of the CSS is applied
after the document load is complete.
The problem of course is figuring out what styles
should be inlined as critical CSS
and then automating the process, so you don't have
to manually copy and paste code every time
you update something.
Fortunately, web performance expert, Addy Osmani,
has solved this problem for us
in the form of a tool called critical.
It can run on its own or in existing tool chains
and build processes, including Webpack, grunt and gulp.
And it does all the heavy lifting for us.
Reads the HTML and CSS figures out what rule sets
should be inlined automatically inlines that CSS
into the HTML document, separates out the non-critical CSS
into a step separate style sheet
and then lazy loads on the first and non-critical CSS.
Because this tool is built into the tool chain,
it can be set up to take place at every build,
so you don't have to keep tabs on what styles are critical.
This tool also has a ton of options,
so you can fully customize exactly what happens
within the critical CSS,
both what happens to the index file or the HTML file.
What happens to the CSS, the view port you're targeting,
all this stuff can be configured.
Let me show you how this works in practice.
So here I've taken an example from previously in the course.
It doesn't really matter what the example is
cause we're just looking at how the index file
and the style sheet has changed.
So out of the gates,
we have a standard index document where the calls
for a style sheet.
Style sheet is here.
It's relatively large.
I've added in a style reset, the CSS remedy at the top
just so that we have extra styles that can be deferred.
And then finally we have the gulp file.
I'm using gulp here because gulp is a standard tool a lot
of people use for build processes.
But I'm also using it because critical is used
as is in gulps.
There's no critical plugin for gulp,
you just use critical as-is.
So this example that I'm showing you could be used
in any setup, not just gulp.
Alright, let's take a look at how this all fits together.
First, I call in critical and it's generate method.
This is what actually generates the critical CSS for us.
I set the inline property to true,
saying I want to inline the CSS
because you can choose to place the critical CSS
in a separate style sheet if you want to.
Then I define the base.
This is the base folder my build would live in.
That will be the build folder up here.
The source is the HTML file
that we'll be injecting content into.
And this is also the source that critical we'll use
as it renders out a page to figure out which CSS
is going to be critical.
So this is currently pointing at source index dot HTML,
which is the original index.
Then I define how I want to output the results to the file.
And here I've set up three targets.
The first target is CSS.
What happens when critical runs is it'll figure out
which styles need to be in line and critical
and then it places it in its own style sheet
for further use.
So that's what's defined here in the first property critical
and I've just given it the name critical CSS.
The next entry is HTML.
This is the output that critical will create.
So after it's processed everything,
it'll create a new HTML document for us.
And I call that document, index.HTML.
It'll land in the build folder.
And finally, uncritical defines the style sheet
that will contain uncritical CSS.
Everything we don't need for above the fold.
That's placed in its own style sheet and I've called
that style sheet, uncritical CSS.
You can change any of these names to whatever you want.
It'll still work the same way.
Then at the bottom here, I've sent minified to true
just so all the CSS has minified and optimized.
And then finally, I've defined the width and height
of the view port we're testing against.
Because what happens when you run critical
is critical actually spin up a browser
and then display the contents in the browser
in a defined view port size that we've defined.
And then look at what CSS is affecting the content
inside that view port and split that out
into this critical CSS file.
The view port that I'm targeting
is the smallest possible mobile device.
This is a feature phone on a slow network.
So 320 width, 480 height.
You can set this value to anything you want,
but I'm choosing to target the smallest phone
because that's where you'll see the most performance impact.
Like I said, there are a lot of options here.
You can play around with them.
There's a huge list of options on GitHub
that you can go through.
There are also some examples
of how to configure different types of environments.
All right, let's see what happens when I actually run this.
So I'll go into my console and just say, gulp,
a cryptic call CSS.
This process takes a bit of time
because a browser needs to be spun up
and everything needs to happen.
But because I have such a simple example,
the time isn't all that important.
So once critical CSS has finished,
you'll notice I have some new files up here
in the build folder.
So let's take a look at them.
First, I have index.HTML.
Now, look closely here and you'll see there's some changes.
We have a new style element.
And inside that style element, we have a ton of CSS.
So this is all the inline CSS that was created by critical.
You can see it's minified and it's injected directly in,
so that everything is working properly.
This is the critical inline CSS that will run
before the dom's even built.
So this will then define the content that's above the fold.
Then below we have our link elements,
but the link element now points at uncritical CSS.
And you'll notice the media property is set to print.
This is the JavaScript trick I was talking about.
So what happens now is a regular browser
will identify itself as screen.
For that reason, this style sheet will not be loaded
because it's set to only load for print.
Meaning when you're actually printing something.
Then, on load, which is an event that is triggered
when the page is fully loaded,
would change this media to all instead.
And at that point, once everything else is done,
this extra style sheet will be loaded.
We'll talk more about this approach on a couple
of other approaches for differing loading of CSS later,
but that's what's happening here.
We're inlining the critical CSS and then deferring loading
of the uncritical CSS until other things have completed.
There are two more files in my build now.
I have critical CSS, which is the same critical CSS
that's been in line is just sitting here in case we want
to refer to it.
And then uncritical CSS, which is a modified version
of all the CSS in the original style sheet
that has not been put in the critical CSS.
So as you can see, this build process now automatically does
all the work for me.
And as I build out this project,
change my HTML, change my CSS, change other things,
this process will ensure
that I always inline the correct critical CSS.