I am trying to get a 100/100 score on Google Page Speed Insights. But it keeps telling me some css files are blocking content above the fold. How can I make sure those files are loaded after the main content is loaded? So that it doesn't show up anymore in Page Speed Insights.
I tried loading the files asynchronously using jquery, but this way the message still pops up at the page speed tool.
I tried the following:
<script>
var loadMultipleCss = function(){
//load local stylesheet
loadCss('myawesomestyle.css');
//load Bootstrap from CDN
loadCss('https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css');
//load Bootstrap theme from CDN
loadCss('https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css');
}
var loadCss = function(cssPath){
var cssLink = document.createElement('link');
cssLink.rel = 'stylesheet';
cssLink.href = cssPath;
var head = document.getElementsByTagName('head')[0];
head.parentNode.insertBefore(cssLink, head);
};
//call function on window load
window.addEventListener('load', loadMultipleCss);
</script>
With my own file paths ofcourse.
But for Google PageSpeed Insights this didn't work.
Can you share the link of the website you are optimizing?
Are you sure that your page is not cached somewhere?
There are two methods that worked for me:
A) You could just put the stylesheet tags after the closing </html> tag.
B) Another technique is to put following link tag into the head section:
<link rel="preload" id="stylesheet" href="/assets/css/below.css" as="style" onload="this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/assets/css/below.css"></noscript>
The drawback with method B is that not all browsers support rel=preload in the link tag and you will need to include the following polyfill:
<script>
/*! loadCSS. [c]2017 Filament Group, Inc. MIT License */
!function(a){"use strict";var b=function(b,c,d){function e(a){return h.body?a():void setTimeout(function(){e(a)})}function f(){i.addEventListener&&i.removeEventListener("load",f),i.media=d||"all"}var g,h=a.document,i=h.createElement("link");if(c)g=c;else{var j=(h.body||h.getElementsByTagName("head")[0]).childNodes;g=j[j.length-1]}var k=h.styleSheets;i.rel="stylesheet",i.href=b,i.media="only x",e(function(){g.parentNode.insertBefore(i,c?g:g.nextSibling)});var l=function(a){for(var b=i.href,c=k.length;c--;)if(k[c].href===b)return a();setTimeout(function(){l(a)})};return i.addEventListener&&i.addEventListener("load",f),i.onloadcssdefined=l,l(f),i};"undefined"!=typeof exports?exports.loadCSS=b:a.loadCSS=b}("undefined"!=typeof global?global:this);
/*! loadCSS rel=preload polyfill. [c]2017 Filament Group, Inc. MIT License */
!function(a){if(a.loadCSS){var b=loadCSS.relpreload={};if(b.support=function(){try{return a.document.createElement("link").relList.supports("preload")}catch(b){return!1}},b.poly=function(){for(var b=a.document.getElementsByTagName("link"),c=0;c<b.length;c++){var d=b[c];"preload"===d.rel&&"style"===d.getAttribute("as")&&(a.loadCSS(d.href,d,d.getAttribute("media")),d.rel=null)}},!b.support()){b.poly();var c=a.setInterval(b.poly,300);a.addEventListener&&a.addEventListener("load",function(){b.poly(),a.clearInterval(c)}),a.attachEvent&&a.attachEvent("onload",function(){a.clearInterval(c)})}}}(this);
</script>
I wrote an article about optimizing a page from pagespeed 59 to 100 and you can see the before and after on following branches:
Before: https://github.com/storyblok/storyblok-express-boilerplate/blob/unoptimized/views/layouts/main.hbs
After: https://github.com/storyblok/storyblok-express-boilerplate/blob/master/views/layouts/main.hbs
Related
I have the following JavaScript in the <head> of a simple static page, which specifies either a.css or b.css as the stylesheet to use depending on the result of some additional JavaScript (useA(), not shown here).
<head>
<script>
var ss = document.createElement("link");
ss.rel = "stylesheet";
ss.href = (useA() ? "a.css" : "b.css");
document.head.appendChild(ss);
</script>
</head>
This results in a flash of unstyled content (FOUC) when I load or refresh the page on both Firefox and Chrome.
Using a plain <link rel="stylesheet" ...> doesn't have this problem: CSS loaded in <head> using <link> is apparently render-blocking. Is there some way to get the same behavior for CSS injected stylesheets as well?
Constraints:
I can't change a.css or b.css so I'm not looking for a solution which involves loading both stylesheets, or a combined styleseet and setting an indicator class on a root element to effect the choice between the sheets. I'm also not looking for visibility:hidden or display:none tricks which delay any display until the page is fully loaded.
I am running django 2.0, which has jquery 2.2.3. I want to utilize this ImageViewer Javascript app https://github.com/s-yadav/ImageViewer with one of my admin pages. I added the js files and css file to the Media class within my ModelAdmin class, and collected all the static files. The files are loaded on the web page. I am following the app's example for Image Mode (http://ignitersworld.com/lab/imageViewer.html)
The page loads, but there is an error in the js console:
imageviewer.js:16 Uncaught TypeError: $ is not a function
at imageviewer.js:16
at imageviewer.js:789
(anonymous) # imageviewer.js:16
(anonymous) # imageviewer.js:789
The first few lines of the ImageViewer script - line 16 is the one with 'body'
/*
ImageViewer v 1.1.3
Author: Sudhanshu Yadav
Copyright (c) 2015-2016 to Sudhanshu Yadav - ignitersworld.com , released under the MIT license.
Demo on: http://ignitersworld.com/lab/imageViewer.html
*/
/*** picture view plugin ****/
(function ($, window, document, undefined) {
"use strict";
//an empty function
var noop = function () {};
var $body = $('body'),
$window = $(window),
$document = $(document);
The last line of the script is line 789, the source of the second error:
}((window.jQuery), window, document));
The header of my admin page:
<script type="text/javascript" src="/admin/jsi18n/"></script>
<link href="/static/imageviewer.css" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="/static/admin/js/vendor/jquery/jquery.js"></script>
<script type="text/javascript" src="/static/admin/js/jquery.init.js"></script>
<script type="text/javascript" src="/static/admin/js/core.js"></script>
<script type="text/javascript" src="/static/admin/js/admin/RelatedObjectLookups.js"></script>
<script type="text/javascript" src="/static/admin/js/actions.js"></script>
<script type="text/javascript" src="/static/admin/js/urlify.js"></script>
<script type="text/javascript" src="/static/admin/js/prepopulate.js"></script>
<script type="text/javascript" src="/static/admin/js/vendor/xregexp/xregexp.js"></script>
<script type="text/javascript" src="/static/imageviewer.js"></script>
<script type="text/javascript" src="/static/my_code.js"></script>
The html for my image in the admin page:
<div class="readonly"><div id="image-gallery-3" class="cf"><img src="/documents/bfa1a808-7412-46c0-9d68-1a1df98f5a9c_thumb.jpg" data-high-res-src="/documents/bfa1a808-7412-46c0-9d68-1a1df98f5a9c.jpg" alt="" class="pannable-image"></div></div>
And the my_code.js to make this thing work, as shown in the example:
$(function () {
$('.pannable-image').ImageViewer();
});
The only difference between the example page for ImageViewer and my code is that the my_code.js appears in the example page after the html for the image, and my_code.js appears before the html for the image. Does that make a difference?
I am not a js guy, and I have run into this same error before when trying to integrate a third party Javascript code with the django admin pages. I still don't have a solution to this problem, except not to try to use any custom js with the django admin pages!
I think there is some sort of interaction between the django jquery and third party js, which causes this error, but again, I am not a js guy! I have google the error and integrating third party js with the django admin, but have not found anything that works.
Thanks!
Mark
After some testing and more googling I found the following answer.
I had to add the line var jQuery = django.jQuery, $ = jQuery; at the top of the imageviweer.js file. The issues was the line django.jQuery = jQuery.noConflict(true); in jquery.init.js.
This image viewer allows one to zoom in on an image. So, there are really two images, the one that is loaded on the page, and the one that the imageviewer script manipulates for the zoom and pan. The image on my page seems to have been too small. Once I increased the size of that image, the zoom/pan worked.
Problem solved, and I hope this is a "universal" solution for future third party javascript plugins for the django admin pages.
Mark
I'm trying to increase my website performance by doing some tweaks, and i have found the google web fonts scripts to load fonts
asynchronously, the problem is that the fonts loads
asynchronously but not the script src link so i just moved the problem with css to js.
My actual code is that:
<script src="https://ajax.googleapis.com/ajax/libs/webfont/1.5.18/webfont.js"></script>
<script>
WebFont.load({
google: {
families: ['Oswald:400,300', 'Material+Icons']]
}
});
I've tried to use async and defer but on the script src but it didn't work (it eliminated the page block render but the fonts didn't loaded like the other scripts do with async).
So what's the best way to remove the script src link?
Try This.
<script>
WebFontConfig = {
google: { families: ['Oswald:400,300', 'Material+Icons'] }
};
(function(d) {
var wf = d.createElement('script'), s = d.scripts[0];
wf.src = 'https://ajax.googleapis.com/ajax/libs/webfont/1.6.26/webfont.js';
wf.async = true;
s.parentNode.insertBefore(wf, s);
})(document);
</script>
Here ya go, include this in the body, right before </body> and not the head tag
<link href="https://fonts.googleapis.com/css?family=Noto+Serif" rel="stylesheet" lazyload>
This makes the font load after everything above it.
But instead of Noto Serif, use Oswald font in your case.
Answered originally by user "Paddy" here:
https://stackoverflow.com/a/40624546/6283055
I'm testing out preloading and I'd like to know why including a preload link before a preload script is faster by a tenth of a second.
rel="preload" tells the browser to start downloading the stylesheet to not block loading. The script creates a stylesheet from the URL and applies it to the page. Why is the stand-alone-script not as performant?
<link rel="preload" href="https://unpkg.com/tachyons#4.8.0/css/tachyons.min.css" as="style" onload="this.rel='tachyons.min.css'">
<script type="text/javascript">
//<![CDATA[
if(document.createStyleSheet) {
document.createStyleSheet("https://unpkg.com/tachyons#4.8.0/css/tachyons.min.css");
}
else {
var styles = "#import url('https://unpkg.com/tachyons#4.8.0/css/tachyons.min.css');";
var newSS=document.createElement('link');
newSS.rel='stylesheet';
newSS.href='data:text/css,'+escape(styles);
document.getElementsByTagName("head")[0].appendChild(newSS);
}
//]]>
</script>
Preload + Script:
https://codepen.io/JulianNorton/full/GvxpVr/
Script only:
https://codepen.io/JulianNorton/pen/vJRLBK
The answer can be found in the MDN
preload has other advantages too. Using as to specify the type of content to be preloaded allows the browser to:
Prioritize resource loading more accurately.
The browser priorities this resource during pre-rendering, marking it as a "stylesheet" required for the critical rendering path, while the inline element's priority is lower.
I am trying to optimize the CSS delivery following the google documentation for developers https://developers.google.com/speed/docs/insights/OptimizeCSSDelivery#example
As you can see in the example of inlining a small CSS file the critical CSS in inlined in the head and the original small.css is loaded after onload of the page.
<html>
<head>
<style>
.blue{color:blue;}
</style>
</head>
<body>
<div class="blue">
Hello, world!
</div>
</body>
</html>
<noscript><link rel="stylesheet" href="small.css"></noscript>
My question regarding this example:
How to load a large css file after onload of the page?
If you don't mind using jQuery, here is a simple code snippet to help you out. (Otherwise comment and I'll write a pure-js example
function loadStyleSheet(src) {
if (document.createStyleSheet){
document.createStyleSheet(src);
}
else {
$("head").append($("<link rel='stylesheet' href='"+src+" />"));
}
};
Just call this in your $(document).ready() or window.onload function and you're good to go.
For #2, why don't you try it out? Disable Javascript in your browser and see!
By the way, it's amazing how far a simple google search can get you; for the query "post load css", this was the fourth hit...
http://www.vidalquevedo.com/how-to-load-css-stylesheets-dynamically-with-jquery
A little modification to the function provided by Fred to make it more efficient and free of jQuery. I am using this function in production for my websites
// to defer the loading of stylesheets
// just add it right before the </body> tag
// and before any javaScript file inclusion (for performance)
function loadStyleSheet(src){
if (document.createStyleSheet) document.createStyleSheet(src);
else {
var stylesheet = document.createElement('link');
stylesheet.href = src;
stylesheet.rel = 'stylesheet';
stylesheet.type = 'text/css';
document.getElementsByTagName('head')[0].appendChild(stylesheet);
}
}
This is how you do it using the new way, without using any 3rd party library or extra JS:
<link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="styles.css"></noscript>
link rel="preload" as="style" requests the stylesheet asynchronously.
The onload attribute in the link allows the CSS to be processed when it finishes loading.
"nulling" the onload handler once it is used helps some browsers avoid re-calling the handler upon switching the rel attribute.
The reference to the stylesheet inside of a noscript element works as a fallback for browsers that don't execute JavaScript.
In addition to Fred's answer:
Solution using jQuery & Noscript
<html>
<head>
<style>
.blue{color:blue;}
</style>
<script type="text/javascript" src="../jquery-1.4.2.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
if($("body").size()>0){
if (document.createStyleSheet){
document.createStyleSheet('style.css');
}
else {
$("head").append($("<link rel='stylesheet'
href='style.css'
type='text/css' media='screen' />"));
}
}
});
</script>
</head>
<body>
<div class="blue">
Hello, world!
</div>
</body>
</html>
<noscript><link rel="stylesheet" href="small.css"></noscript>
from http://www.vidalquevedo.com/how-to-load-css-stylesheets-dynamically-with-jquery
Using pure Javascript & Noscript
<html>
<head>
<style>
.blue{color:blue;}
</style>
<script type="text/javascript">
var stylesheet = document.createElement('link');
stylesheet.href = 'style.css';
stylesheet.rel = 'stylesheet';
stylesheet.type = 'text/css';
document.getElementsByTagName('head')[0].appendChild(stylesheet);
</script>
</head>
<body>
<div class="blue">
Hello, world!
</div>
</body>
</html>
<noscript><link rel="stylesheet" href="small.css"></noscript>
Try this snippet
The author claims it was published by Google's PageSpeed Team
<script>
var cb = function() {
var l = document.createElement('link'); l.rel = 'stylesheet';
l.href = 'yourCSSfile.css';
var h = document.getElementsByTagName('head')[0]; h.parentNode.insertBefore(l, h); };
var raf = requestAnimationFrame || mozRequestAnimationFrame ||
webkitRequestAnimationFrame || msRequestAnimationFrame;
if (raf) raf(cb);
else window.addEventListener('load', cb);
</script>
There is a simple way to load CSS asynchronously with only link tag
<link rel="stylesheet" href="/path/to/my.css" media="print" onload="this.media='all'">
media="print" tell browser to load CSS asynchronously that intended for print.
Onload set the link's media to all when it loaded.
Comapared to mahmoud answer, this approach doesn't prioritize fetching the css, which maybe not needed
More details are explained here
WARNING: body{background-image: url("http://example.com/image.jpg");} in css files will make your css files still render-blocking.
If you tried all the solutions above and you still get the render-blocking warning from PageSpeed insights then you probably have this style rule in your css files. After hours of tests it turns out that this rule is what making ALL of my css to be flagged as render-blocking resources at PageSpeed insights. I found the same issue has been discussed before.
I don't know why body{background-image: url(...) do this for all the css files!, although I have different images resources in the file for the buttons, icons, ...etc .
I fixed this by moving this rule from the .css file and put it in the inline styles. Unfortunately, you will have to break your css plan and put the rule in all of your layouts HTML files instead of being in 1 css file that is imported in all of your HTML layouts, but the 90s and green color in PageSpeed insights deserve it.
Fixed mine by introducing placing all css files at the bottom of the page, after the body tag. but this introduces a new problem, the page loads un-styled html for noticeable mili seconds before applying the style. For this I fixed by introducing a splash screen all styled on the page.