Welcome to WebmasterWorld Guest from 54.152.38.154

Forum Moderators: not2easy

Message Too Old, No Replies

Setting a stylesheet to ASYNC (not HTTP/2)

     
4:55 am on May 24, 2018 (gmt 0)

Senior Member

WebmasterWorld Senior Member 5+ Year Member Top Contributors Of The Month

joined:Mar 15, 2013
posts: 1095
votes: 103


I checked, and my server doesn't currently support HTTP/2 :-( I'm using CentOS 6, and to support HTTP/2 I need to upgrade to CentOS 7... which is going to be a nightmare >:-(

So for now, I'm stuck with hacks and workarounds.

I'm trying to find a way to make my stylesheet download ASYNC. I forget if someone here sent me this link or if I stumbled across it on my own, but there's a hack mentioned of:

<head>
<!--[if IE]>
<link rel="stylesheet" href="style.css"/>
<![endif]-->
</head>
<body>
<!--[if !IE]> -->
<link rel="stylesheet" href="style.css" lazyload="1"/>
<!-- <![endif]-->
</body>

[codepen.io...]

The hack suggests that putting the stylesheet in the body will make it download ASYNC! Apparently older versions of IE don't support that so you have to use a conditional statement in the head.

But his information is based on something written in 2011, so could easily be out of date by now.

I'm not sure how to test this on my own, but what do you guys think? Or, can you suggest how I might test it out?
3:24 am on May 25, 2018 (gmt 0)

Senior Member from US 

WebmasterWorld Senior Member keyplyr is a WebmasterWorld Top Contributor of All Time 10+ Year Member Top Contributors Of The Month

joined:Sept 26, 2001
posts:12913
votes: 893


You can just do it in the HTML:
<script src="example.js" type="text/javascript" async="true"></script>
People have done this well before HTTP/2.

Note: depending on your server config, you may need to use absolute path (this would apply to Cloudflare or other dynamic routing.)
3:40 am on May 25, 2018 (gmt 0)

Senior Member from US 

WebmasterWorld Senior Member lucy24 is a WebmasterWorld Top Contributor of All Time 5+ Year Member Top Contributors Of The Month

joined:Apr 9, 2011
posts:15640
votes: 796


his information is based on something written in 2011
Yeah, the Conditional Comments were kind of a dead giveaway. I especially like
[if !IE]
since no browser but MSIE ever recognized Conditional Comments, and even they abandoned the idea with MSIE 10.
7:00 am on May 25, 2018 (gmt 0)

Senior Member

WebmasterWorld Senior Member 5+ Year Member Top Contributors Of The Month

joined:Mar 15, 2013
posts: 1095
votes: 103


You can just do it in the HTML:

@keyplyr, I'm working on a CSS script, not Javascript :-) AFAIK, the async attribute only works on <script>.


Yeah, the Conditional Comments were kind of a dead giveaway. I especially like
[if !IE]
since no browser but MSIE ever recognized Conditional Comments, and even they abandoned the idea with MSIE 10.

@lucy24, I could be wrong here, but wouldn't [if !IE] specifically tell older IE to ignore it so it wouldn't load the file twice?

Regardless, it's really just a backup plan for older IE. Most people wouldn't care, but I have a surprising amount of older browser users on my site :-/
7:36 am on May 25, 2018 (gmt 0)

Senior Member

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month

joined:Sept 25, 2005
posts:2091
votes: 370


I'm on CentOS 6 as well, and HTTP/2 works just fine. It's possible, just a little more complex.

AFAIK, the async attribute only works on <script>.

For good reason, too :-) Why in the world would you want to load your stylesheet this way?

It's no replacement for HTTP/2 PUSH. How about inlining your CSS on the first request?
7:51 am on May 25, 2018 (gmt 0)

Senior Member from US 

WebmasterWorld Senior Member keyplyr is a WebmasterWorld Top Contributor of All Time 10+ Year Member Top Contributors Of The Month

joined:Sept 26, 2001
posts:12913
votes: 893


@csdude55 - right :)

I'm on CentOS 6 as well, and HTTP/2 works just fine

Then this would work?
<link rel="preload" as="stylesheet">
3:27 pm on May 25, 2018 (gmt 0)

Senior Member

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month

joined:Sept 25, 2005
posts:2091
votes: 370


It would have to be "style" (after the <style> element), not "stylesheet", but it wouldn't make much sense to me. By the time the browser reaches the <link> element to preload the stylesheet, it would also have reached the original stylesheet <link>, so you're not saving any time, and preload only fetches the file and doesn't make the CSS available to the current document. Preload is generally used for resources that are not directly visible to the browser, like a font referenced in a stylesheet, or a second script loaded by a first.

Sending a preload HTTP header could work, but probably not as effective as server push.

Still unclear why you'd want your stylesheet to load asynchronously with other resources.
3:57 pm on May 25, 2018 (gmt 0)

Junior Member

Top Contributors Of The Month

joined:May 1, 2018
posts:94
votes: 15


Move the srylesheet out of your head and it should download async. For more cross browser also add async = true. You can also use javascript.
6:46 pm on May 25, 2018 (gmt 0)

Senior Member

WebmasterWorld Senior Member 5+ Year Member Top Contributors Of The Month

joined:Mar 15, 2013
posts: 1095
votes: 103


Still unclear why you'd want your stylesheet to load asynchronously with other resources.

This is coming after a discussion with Travis about speeding things up. It's not going to have a HUGE impact or anything, but it should increase the initial page load by anywhere from 300 to 500ms. My mobile and dial-up users might see a bigger impact, though.

The logic is pushing off the HTTP requests until the end, so they're not blocking the rest of the page load.

<?php
$nocookie = false;

if (!isset($_COOKIE['first_time'])) {
echo "<style>\n";
include '/home/example/www/stylesheet_just_for_this_section.css';
echo "</style>\n\n";

echo "<script>\n";
include '/home/example/www/javascript_just_for_this_section.js';
echo "</script>\n\n";

$nocookie = 1;
setcookie('first_time', '1', time() + (86400 * 365), '/');
}

else
echo <<<EOF
<link rel="stylesheet" href="https://www.example.com/styles.css">
<script src="https://www.example.com/javascript.js"></script>
EOF;

// blah blah blah

// Footer
if ($nocookie)
echo <<<EOF
<link rel="stylesheet" href="https://www.example.com/styles.css">
<script async src="https://www.example.com/javascript.js"></script>

EOF;

echo <<<EOF
</body>
</html>
EOF;
?>
8:02 pm on May 25, 2018 (gmt 0)

Senior Member

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month

joined:Sept 25, 2005
posts:2091
votes: 370


Won't you be executing the Javascript twice?

I'm not sure what happens when you put <link rel="stylesheet"> in the <body>. Does the browser fetch the file? If so, does it do anything with the stylesheet? If it does, isn't that a costly re-paint? Have you tested it yet? I'm curious.

Inlining CSS/JS can certainly speed things up on the first request, but I think I'd defer loading the .css and .js file to after the page has finished loading (using preload or a simple GET request); right now they'll potentially be blocking other resources.
7:06 am on May 26, 2018 (gmt 0)

Senior Member

WebmasterWorld Senior Member 5+ Year Member Top Contributors Of The Month

joined:Mar 15, 2013
posts: 1095
votes: 103


Won't you be executing the Javascript twice?

Hmm, well, yeah, that's a good point. I did a quick Google and I don't think that would throw an error; technically speaking, the browser would run the second version, but since they would be the same then that wouldn't really matter in my case.

Can you think of a better way to load javascript.js in to the user's cache?


I'm not sure what happens when you put <link rel="stylesheet"> in the <body>. Does the browser fetch the file? If so, does it do anything with the stylesheet? If it does, isn't that a costly re-paint? Have you tested it yet? I'm curious.

I tried just moving it directly underneat <body> and everything seemed to work the same, but I'm not entirely sure if it loaded it ASYNC or not. I'm not 100% sure how CSS processes, though... would having a second class of the same name mean that every class runs twice, or does the second copy just overwrite the first like the Javascript function?

I'll do some speed tests both ways to see what I can determine... probably Sunday.


Inlining CSS/JS can certainly speed things up on the first request, but I think I'd defer loading the .css and .js file to after the page has finished loading (using preload or a simple GET request); right now they'll potentially be blocking other resources.

I could use the defer attribute for the JS... it's my understanding that it never really worked properly in the past, but modern browsers are doing OK with it. But if it's already inline and I'm just downloading this to the cache, would that really matter?

And if I have both at the bottom of the page, just before </body>, would they still potentially block other sources? I thought putting them at the end would fix that.
1:16 pm on May 26, 2018 (gmt 0)

Senior Member

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month

joined:Sept 25, 2005
posts:2091
votes: 370


You might be forcing a repaint of the document by requesting the stylesheet after you've already in-lined its contents, but I haven't ever tested this. As with blocking, the behavior is likely to vary with each browser.

The safest way to pull a file into the browser cache without actually using it, I think would be to send an AJAX GET request to the file (without using its contents) after the load event has fired.

(While it's not straightforward and a little harder to maintain, you can build httpd or nginx with a custom version of OpenSSL to get HTTP/2 to work on CentOS 6.)
6:22 pm on May 26, 2018 (gmt 0)

Junior Member

Top Contributors Of The Month

joined:May 1, 2018
posts:94
votes: 15


If you want to cache files for future use.. You should look into service workers . Service workers can do exactly as you describe to store files for future use
5:31 pm on May 27, 2018 (gmt 0)

Senior Member

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month

joined:Sept 25, 2005
posts:2091
votes: 370


Might be overkill to fire up a Service Worker only for the purpose of getting a few files into the browser's cache, and browser compatibility is still limited so you'd need a backup anyway. Having said that, it is certainly a very promising technique, for preloading/caching too.
7:33 am on May 30, 2018 (gmt 0)

Senior Member

WebmasterWorld Senior Member 5+ Year Member Top Contributors Of The Month

joined:Mar 15, 2013
posts: 1095
votes: 103


Alright, guys, I have some results for you.

For now, I've followed @robzilla's advice and used jQuery's $.get() to load the JS and CSS in to cache. So on the first load I'm using PHP's include() to import them directly to the page, then I set a cookie, then I load the separate files. Then on the second load, I just load the JS and CSS from cache.

Using Google Dev Tools for a speed test (which means it's relative to my ISP speed), I ran several speed tests at 3am, when the server demand is at its lowest. Instead of the homepage, I tested a page that's fairly heavy with content and is the second most popular entry point for my site.

The "normal" load, using an external JS and CSS sheet, had an average DOM load of 2.54s and Load of 4.77s.

Using include() to import them on to the page had an average DOM load of 1.53s and Load of 2.37s.

Then loading the JS and CSS from cache had a DOM load of 1.67s and Load of 1.89s.

So the FIRST page load had a significant improvement in load time. After that, of course, it was all the same. But that 2.4s of improved Load time might result in at least 1 more pageview per session for me, which can turn in to money :-D
9:03 am on May 30, 2018 (gmt 0)

Senior Member

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month

joined:Sept 25, 2005
posts:2091
votes: 370


Nice work! A 1 second improvement is awesome.

Is this a page with ads? The load times seem to vary so much. I tend to disable them for myself, based on my IP address or an admin session, so that they don't interfere with my audits.

The only downside is that you're blowing up your HTML with the embedded CSS and JS, increasing the download time of the initial request, but that should be off-set by the fact that there are no external dependencies required for the First Meaningful Paint. Also, bots are generally stateless so you'll probably waste some additional bandwidth on them.

Now see if you can find more improvements to get to <1s :-)
4:18 pm on May 30, 2018 (gmt 0)

Senior Member

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month

joined:Sept 25, 2005
posts:2091
votes: 370


Relevant: The future of loading CSS [jakearchibald.com] (expected in Chrome 69)
7:21 pm on May 30, 2018 (gmt 0)

Senior Member

WebmasterWorld Senior Member 5+ Year Member Top Contributors Of The Month

joined:Mar 15, 2013
posts: 1095
votes: 103


Nice work! A 1 second improvement is awesome.

Thank you very much :-)

Is this a page with ads? The load times seem to vary so much. I tend to disable them for myself, based on my IP address or an admin session, so that they don't interfere with my audits.

I disabled Google DFP for the test, but not jQuery, jQuery mobile, and Analytics... doing a one-time test right now (at 3pm, near peak time), all of them combined (loading from disk cache) take about 600ms, then there's another file related to Analytics called "collect" (that doesn't load from disk cache) that takes another 229ms, and a "collect" GIF that adds another 662ms. So those are pretty significant, even when loading from cache :-/

I should probably disable all of them for a better test, now that I think about it...

The only downside is that you're blowing up your HTML with the embedded CSS and JS, increasing the download time of the initial request, but that should be off-set by the fact that there are no external dependencies required for the First Meaningful Paint. Also, bots are generally stateless so you'll probably waste some additional bandwidth on them.

Excellent point, and I was concerned that it might affect search engine placement negatively by pushing the real content lower down the page. That USED to be a concern, but I don't know if it's really relevant anymore?

Plus, I'm not sure if any "good" bot will take a cookie... if not then every page would have the CSS and JS inline.

If it's really not relevant to search engines, then in theory I would still save 0.14s from the DOM load by running them all inline instead of from cache.

Now see if you can find more improvements to get to <1s :-)

This is a little bit off topic, but I'm curious about your thoughts...

I've taken a lot of smaller widgets that aren't critical for the page (like locally sold ads) and moved them to a separate file loaded via Ajax, so they load last. It makes the main content of the page usable faster, but they do add to the overall load time.

Am I right in understanding that DOM load refers to when the page is usable, and "Load" refers to when the images and Ajax scripts are loaded?

Relevant: The future of loading CSS [jakearchibald.com] (expected in Chrome 69)

I do like the idea of having multiple stylesheets and only loading them as needed! I spent several years cutting out as many HTTP requests as possible (eg, using sprites instead of multiple small images), but it looks like things are swinging back in the other direction again.
11:25 am on May 31, 2018 (gmt 0)

Senior Member

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month

joined:Sept 25, 2005
posts:2091
votes: 370


I was concerned that it might affect search engine placement negatively by pushing the real content lower down the page. That USED to be a concern, but I don't know if it's really relevant anymore?

Apparently it's still a concern ;-) Since you're not changing the actual page in any way, only the code, it shouldn't affect your rankings in any way. Maybe back in the day when HTML comment spam was a thing, I don't know. That is not to say you can't go overboard with this. I wouldn't inline the full jQuery library, but not so much from an SEO perspective.

I'm not sure if any "good" bot will take a cookie... if not then every page would have the CSS and JS inline.

Right, that's what I meant with the wasted bandwidth. ("Stateless" is the word used to describe a bot that doesn't store anything, like session cookies, between requests.) I suppose you could add a condition that excludes the important bots from this technique, which is user-oriented after all.

Am I right in understanding that DOM load refers to when the page is usable, and "Load" refers to when the images and Ajax scripts are loaded?

"The DOMContentLoaded event is fired when the initial HTML document has been completely loaded and parsed, without waiting for stylesheets, images, and subframes to finish loading. A very different event load should be used only to detect a fully-loaded page. It is an incredibly common mistake to use load where DOMContentLoaded would be much more appropriate, so be cautious." DOMContentLoaded [developer.mozilla.org]

it looks like things are swinging back in the other direction again

Yes, but you'll still benefit from those old tricks for as long as you don't support HTTP/2. Unfortunately, the performance cost of HTTPS is only offset by the performance benefits of HTTP/2.
 

Join The Conversation

Moderators and Top Contributors

Hot Threads This Week

Featured Threads

Free SEO Tools

Hire Expert Members