In the index.html page I put a .gif before all the tags that laod the files. Then, with JQuery, I removed that loader. But it didn't work. A blank page was shown, because it was waiting for load some .js files.
So, I created a script that load the files dynamically.
This is the html code:
<!doctype html>
<html ng-app="myApp">
<head>
...here I'm loading all css files
</head>
<body>
<!-- This is the loader -->
<div id="loader" style="background:url('URL_IN_BASE_64')"></div>
<div ng-cloak ng-controller="MyAppController">
<div ui-view></div>
</div>
<script>
(function () {
var fileList = [
"vendor/angular/angular.min.js",
"vendor/jquery/jquery.min.js",
"vendor/angular-aria/angular-aria.min.js",
....
]
function loadScripts(index) {
return function () {
var e = document.createElement('script');
e.src = fileList[index];
document.body.appendChild(e);
if (index + 1 < fileList.length) {
e.onload = loadScripts(index + 1)
} else {
var loader = document.getElementById("loader");
if (loader) {
loader.remove();
}
}
}
}
loadScripts(0)();
})();
</script>
</body>
</html>
Now, the problem is that the page first loads all the css files, then angular.min.js, then my gif, and then the other files. Why? How can I immediatly load the gif and, suddently, all other files?
Thank you!
The html parser is being blocked while waiting for your css and js files to load. The work around is to load your stylesheets and script files asynchronously. Do the following for all files that you load in your <head>, including table.min.css, ng-img-crop.css, and angular.min.css.
For css:
<link rel="stylesheet" href="css/styles.css" media="wait" onload="if(media!='all')media='all'">
<noscript><link rel="stylesheet" href="css/styles.css"></noscript>
For js:
<script async src="js/main.js"></script>
Fun fact: Google will actually punish web pages that block the parser from rendering elements while waiting for resources.
Try this
<!--Put this in head tag-->
<link rel="preload" href="link-to-image">
...
<img src="link-to-image">
Related
I have a simple one page website with bootstrap 5 set up using spring boot with thymeleaf.
On this page I want e.g. to use the bootstrap tooltip. The problem is that the function to initialize the tooltip fires before the bootstrap script has finished loading so there will be an error and the page will not load correctly.
<head>
... // css and meta omitted for brevity
<script th:src="#{/js/bootstrap.bundle.min.js}" async="true"></script>
</head>
<body>
... // page content
<script>
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl)
})
</script>
</body>
I tried to place the bootstrap script
in the head section
with async attribute
with defer attribute
a combination of the attributes
in the body section directly before the tooltip init script
but nothing prevents the second script to fire before the first script has finished loading.
I have read the HTML spec here but in the end I'm not sure if the loading of the script is truly the problem.
Has someone an idea to definitly prevent this error?
Finally solved this problem.
I put all the javascript code in a seperate js-file.
Then I load this file after the bootstrap file at the end of the body and everything works fine.
<head>
... //css and meta
</head>
<body>
... // page content
<script th:src="#{/js/bootstrap.bundle.min.js}"></script>
<script th:src="#{/js/myfunction.js}"></script>
</body>
I have an ASP.NET web application that makes use of a large Javascript file to enable front-end functionality. The issue is that since this web application is growing in size the Javascript file is growing in size along with it.
I want to remove some of my larger functions out of my main javascript file site.js and instead contain them inside a second file. My aim is to declutter the main JS file and increase readability etc.
If this were a normal web application I'm sure I'd be able to use JQuery to achieve this through use of the .getScript() however I've tried using this function to pull in a separate script with a simple alert function and I get a reference error saying that my alert function is undefined. I have included both scripts within my ASP.NET _Layout view, but still it doesn't work.
Below is what I am doing currently, what do I need to do to be able to call a JS function held inside another file from site.js?
site.js
$(function() {
$(document).ready(function() {
$.getScript("../site2.js");
sendAlert();
});
//... other js
});
site2.js
$(function() {
function sendAlert() {
alert("site2 file");
}
});
_Layout
<!DOCTYPE html>
<html>
<head>
<script src="~/js/site2.js"></script>
<script src="~/js/site.js"></script>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css" integrity="sha384-lKuwvrZot6UHsBSfcMvOkWwlCMgc0TaWr+30HWe3a4ltaBwTZhyTEggF5tJv8tbt" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.css" integrity="sha384-88btmYK8qOHy4Z2XuhkWZjUOHICKYe1eSDMwaDGOAy802OCu6PD6mwqY5OwnfGwp" crossorigin="anonymous">
<script defer src="https://use.fontawesome.com/releases/v5.1.0/js/all.js" integrity="sha384-3LK/3kTpDE/Pkp8gTNp2gR/2gOiwQ6QaO7Td0zV76UFJVhqLl4Vl3KL1We6q6wR9" crossorigin="anonymous"></script>
</head>
<body>
#RenderBody()
#RenderSection("Scripts", required: false)
</body>
</html>
I think that you can do this:
$(function() {
var script = document.createElement("script");
script.setAttribute("type", "text/javascript");
script.setAttribute("src", "../site2.js");
document.getElementsByTagName("head")[0].appendChild(script);
});
Cheers - Vinh
Because my webpages are a bit heavy, I decided to use a preloader. The purpose of a preloader is to show some content before the main content loads, engaging the user from the start. Therefore it is very important to show preloader ASAP.
There is a slight problem though. Browser will typically wait for all CSS to be loaded before attempting to display and render HTML. This can be problematic if the document contains several biggish stylesheets.
So, my solution was thus:
<!-- In the head: -->
<noscript>
<link rel="stylesheet" href="/big-css1.css">
<link rel="stylesheet" href="/big-css2.css">
<link rel="stylesheet" href="/big-css3.css">
</noscript>
<script>
function LoadCSS(path) {
var head = document.getElementsByTagName('head')[0],
link = document.createElement('link');
link.setAttribute('href', path);
link.setAttribute('rel', 'stylesheet');
link.setAttribute('type', 'text/css');
head.appendChild(link);
}
</script>
<style>
/*preloader CSS is here*/
</style>
...
</head>
<body>
<div id="preloader">
Some nice content here
</div>
<!-- Main content starts below: -->
<div id="wrapper">
<script>
//hide main content until its loaded
//use JS and not CSS to support those with JS disabled
var el_preloader = document.getElementById("preloader");
var el_wrapper = document.getElementById("wrapper");
el_preloader.style.display = "block";
el_wrapper.style.display = "none";
LoadCSS('/big-css1.css');
LoadCSS('/big-css2.css');
LoadCSS('/big-css3.css');
</script>
...
<!-- After jQuery has been loaded -->
<script>
jQuery(window).load(function() {
document.getElementById("wrapper").style.display = "block";
jQuery('#preloader').fadeOut(1000, function () {
jQuery('#preloader').remove();
});
});
</script>
So, basically, if the use supports JavaScript, then JavaScript handles loading of stylesheets, and if JS is turned off, then the stuff inside the <noscript> tag is parsed and thus stylesheets are loaded normally.
This setup works fine in modern browsers, however I am not sure what impact it will have on SEO, considering Google and others are now evaluating user experience on the websites, and for that they need to parse CSS. Are they smart enough to render the website correctly with this solution? ARe there any adverse impacts on SEO with preloaders in general?
Thanks.
I am using a jQuery plugin it has plugin.css and plugin.js as dependencies and code is in script.js. I cant have plugin.js and script.js merged because i am using plugin only on one webpage of my website.
In order to make sure plugin.css is loaded before execution of plugin.js and script.js, normally I have no option but to have plugin.css in <head> which causes render blocking(until all resources in head are loaded,
browser doesnt render html).
Normal Way: Having CSS in <head> and JS before </body>
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="/css/plugin.css">
</head>
<body>
// content goes here
<script type='text/javascript' src='http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js'></script>
<script src="/js/plugin.js"></script>
<script src="/js/script.js"></script>
</body>
</html>
Proposed Way: Load CSS and JS via ajax calls and inject them when all of them are loaded, using jQuery $.when promise
<!DOCTYPE html>
<html>
<head>
</head>
<body>
// content goes here
<script type='text/javascript' src='http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js'></script>
<script class="load-plugin">
$(document).ready(function(){
var loadPlugin = {
css : $.ajax({ url: $(".jquery-plugin-css").data("src") }),
js : $.ajax({ url: $(".jquery-plugin-js").data("src")}),
};
var scriptJs = $.ajax({ url: $(".script-js").data("src") });
$.when(loadPlugin.css, loadPlugin.js, scriptJs).then(function(){
loadPlugin.css.done(function(data){
$(".jquery-plugin-css").html(data);
});
loadPlugin.js.done(function(data){
$(".jquery-plugin-js").html(data);
});
scriptJs.done(function(data){
$(".script-js").html(data);
});
});
});
</script>
<style class="jquery-plugin-css" data-src="/css/plugin.css"></style>
<script class="jquery-plugin-js" data-src="/js/plugin.js"></script>
<script class="script-js" data-src="/js/script.js"></script>
</body>
</html>
This improved my first render time from 3.4 secs to 2.4 secs and total page load time from 8.5secs to 8secs.
But this has some limitations:
Publicly hosted urls cant be used because the urls inside the plugin files like background-images inside css files if mentioned relative to their directory then the path changes after code is pasted into html.
As the injected code is not part of the source files or external scripts they cant be debugged in developer tools.
This way of lazyloading plugins has pros and equal amount of cons. Can anyone suggest is it worth it to do it this way or any better way to do things.
What I would try is:
Combine the JS files so that the dependent code is after plugin.js
Insert a script at the bottom of the page to dynamically load the CSS first and the combined JS second. If you need example code, you might look at https://github.com/filamentgroup/loadJS/ and https://github.com/filamentgroup/loadCSS/.
Using this approach, neither the CSS nor the JS blocks rendering. The CSS is appended to the DOM, so there should be no problems with relative URLs.
I used to build my websites based on the HTML5 Boilerplate: styles and modenizr in the head, jQuery (google CDN or hosted file) and scripts before the closing body tag. Something like that:
<!DOCTYPE html>
<!-- modernizr conditional comments here -->
<html class="no-js">
<head>
<link rel="stylesheet" href="css/normalize.css">
<link rel="stylesheet" href="css/main.css">
<script src="js/vendor/modernizr-2.6.2.min.js"></script>
</head>
<body>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/vendor/jquery-1.10.2.min.js"><\/script>')</script>
<script src="js/plugins.js"></script>
<script src="js/main.js"></script>
</body>
</html>
Now I want to remove all render-blocking below-the-fold css and js as suggested by Googles PageSpeed Insight.
How do I defer the css and js files including the jQuery library loaded from google?
What should I do about modernizr?
To remove this particular warning you need to do the following:
defer the load of all external CSS until after page onload
defer the load of all external JS until after page onload
In practice that means you need to do the following:
split your CSS into that required to avoid the "flash of unstyled content" (FOUC) and the rest
split your javascript likewise
inline the CSS and JS that is required
defer the load of the other CSS and JS until after page onload.
Using build tools is the only sane way of doing this. You can do it with various Grunt tools, or with the ant-based H5BP Build Script.
The basic method of deferring loads is as follows:
(function () {
// Load jQuery after page onload
function loadJS() {
var url = "https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js";
var n = document.createElement("script");
n.src = url;
n.onload = loadJS1;
document.body.appendChild(n);
}
// Load some JS after jquery has been loaded.
function loadJS1() {
var url = "js/main.js";
var n = document.createElement("script");
n.src = url;
// Continue chaining loads if needed.
//n.onload = loadJS2;
document.body.appendChild(n);
}
// Check for browser support of event handling capability
if (window.addEventListener) {
window.addEventListener("load", loadJS, false);
} else if (window.attachEvent) {
window.attachEvent("onload", loadJS);
} else {
window.onload = loadJS;
}
})();