I am trying to optimise my loading of CSSS files as I am loading some large CSS files on pages where they aren't used. Is there any way for me to enqueue them only if an element is present with a class on that page.
I've tried the following however, it does not work:
jQuery(document).ready(function($) {
//Script Checkers
var wowJS = $('.wow');
if (wowJS.length > 0) {
$.getScript('/wp-content/themes/gowebsites/gw-addon/js/wow.js', function() {
new WOW().init();
});
var head = document.getElementsByTagName('head')[0];
var cssNode = document.createTextNode("link");
cssNode.href = "/wp-content/themes/gowebsites/gw-addon/css/animations.css";
cssNode.rel = "stylesheet";
//console.log("CSS Node: "+cssNode); = [object Text]
head.appendChild(cssNode);
}
});
I have seen functions that work for adding css files to the head however, none of them allow the ability to make it conditional.
EDIT: I've since just used the getScripts() jQuery function however, I am still in need of knowing how to add css to the header only if required.
EDIT: For future reference for anyone, this is the final working code:
jQuery(document).ready(function($) {
//Script Checkers
var wowJS = $('.wow');
if (wowJS.length > 0) {
$.getScript('/wp-content/themes/gowebsites/gw-addon/js/wow.js', function() {
new WOW().init();
});
var head = document.getElementsByTagName('head')[0];
var cssNode = document.createElement("link");
cssNode.href = "/wp-content/themes/gowebsites/gw-addon/css/animations.css";
cssNode.rel = "stylesheet";
head.appendChild(cssNode);
}
});
Create the nodes first then append then using the appendChild() method, like :
var scriptNode = document.createElement("script");
scriptNode.src = "/wp-content/themes/gowebsites/gw-addon/js/wow.js";
var cssNode = document.createElement("link");
cssNode.href = "/wp-content/themes/gowebsites/gw-addon/css/animations.css";
cssNode.rel = "stylesheet";
head.appendChild(scriptNode);
head.appendChild(cssNode);
You should use insertAdjacentHTML
head.insertAdjacentHTML("afterend",'<script language="javascript" src="/wp-content/themes/gowebsites/gw-addon/js/wow.js"></script>');
head.insertAdjacentHTML("afterend",'<link href="/wp-content/themes/gowebsites/gw-addon/css/animations.css" rel="stylesheet">');
Is it possible to import css stylesheets into a html page using Javascript? If so, how can it be done?
P.S the javascript will be hosted on my site, but I want users to be able to put in the <head> tag of their website, and it should be able to import a css file hosted on my server into the current web page. (both the css file and the javascript file will be hosted on my server).
Here's the "old school" way of doing it, which hopefully works across all browsers. In theory, you would use setAttribute unfortunately IE6 doesn't support it consistently.
var cssId = 'myCss'; // you could encode the css path itself to generate id..
if (!document.getElementById(cssId))
{
var head = document.getElementsByTagName('head')[0];
var link = document.createElement('link');
link.id = cssId;
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = 'http://website.example/css/stylesheet.css';
link.media = 'all';
head.appendChild(link);
}
This example checks if the CSS was already added so it adds it only once.
Put that code into a JavaScript file, have the end-user simply include the JavaScript, and make sure the CSS path is absolute so it is loaded from your servers.
VanillaJS
Here is an example that uses plain JavaScript to inject a CSS link into the head element based on the filename portion of the URL:
<script type="text/javascript">
var file = location.pathname.split( "/" ).pop();
var link = document.createElement( "link" );
link.href = file.substr( 0, file.lastIndexOf( "." ) ) + ".css";
link.type = "text/css";
link.rel = "stylesheet";
link.media = "screen,print";
document.getElementsByTagName( "head" )[0].appendChild( link );
</script>
Insert the code just before the closing head tag and the CSS will be loaded before the page is rendered. Using an external JavaScript (.js) file will cause a Flash of unstyled content (FOUC) to appear.
If you use jquery:
$('head').append('<link rel="stylesheet" type="text/css" href="style.css">');
I guess something like this script would do:
<script type="text/javascript" src="/js/styles.js"></script>
This JS file contains the following statement:
if (!document.getElementById) document.write('<link rel="stylesheet" type="text/css" href="/css/versions4.css">');
The address of the javascript and css would need to be absolute if they are to refer to your site.
Many CSS import techniques are discussed in this "Say no to CSS hacks with branching techniques" article.
But the "Using JavaScript to dynamically add Portlet CSS stylesheets" article mentions also the CreateStyleSheet possibility (proprietary method for IE):
<script type="text/javascript">
//<![CDATA[
if(document.createStyleSheet) {
document.createStyleSheet('http://server/stylesheet.css');
}
else {
var styles = "#import url(' http://server/stylesheet.css ');";
var newSS=document.createElement('link');
newSS.rel='stylesheet';
newSS.href='data:text/css,'+escape(styles);
document.getElementsByTagName("head")[0].appendChild(newSS);
}
//]]>
Element.insertAdjacentHTML has very good browser support, and can add a stylesheet in one line.
document.getElementsByTagName("head")[0].insertAdjacentHTML(
"beforeend",
"<link rel=\"stylesheet\" href=\"path/to/style.css\" />");
If you want to know (or wait) until the style itself has loaded this works:
// this will work in IE 10, 11 and Safari/Chrome/Firefox/Edge
// add ES6 poly-fill for the Promise, if needed (or rewrite to use a callback)
let fetchStyle = function(url) {
return new Promise((resolve, reject) => {
let link = document.createElement('link');
link.type = 'text/css';
link.rel = 'stylesheet';
link.onload = () => resolve();
link.onerror = () => reject();
link.href = url;
let headScript = document.querySelector('script');
headScript.parentNode.insertBefore(link, headScript);
});
};
Usage:
fetchStyle(url)
.then(
() => console.log("style loaded succesfully"),
() => console.error("style could not be loaded"),
);
Use this code:
var element = document.createElement("link");
element.setAttribute("rel", "stylesheet");
element.setAttribute("type", "text/css");
element.setAttribute("href", "external.css");
document.getElementsByTagName("head")[0].appendChild(element);
In a modern browser you can use promise like this. Create a loader function with a promise in it:
function LoadCSS( cssURL ) {
// 'cssURL' is the stylesheet's URL, i.e. /css/styles.css
return new Promise( function( resolve, reject ) {
var link = document.createElement( 'link' );
link.rel = 'stylesheet';
link.href = cssURL;
document.head.appendChild( link );
link.onload = function() {
resolve();
console.log( 'CSS has loaded!' );
};
} );
}
Then obviously you want something done after the CSS has loaded. You can call the function that needs to run after CSS has loaded like this:
LoadCSS( 'css/styles.css' ).then( function() {
console.log( 'Another function is triggered after CSS had been loaded.' );
return DoAfterCSSHasLoaded();
} );
Useful links if you want to understand in-depth how it works:
Official docs on promises
Useful guide to promises
A great intro video on promises
I know this is a pretty old thread but here comes my 5 cents.
There is another way to do this depending on what your needs are.
I have a case where i want a css file to be active only a while. Like css switching. Activate the css and then after another event deativate it.
Instead of loading the css dynamically and then removing it you can add a Class/an id in front of all elements in the new css and then just switch that class/id of the base node of your css (like body tag).
You would with this solution have more css files initially loaded but you have a more dynamic way of switching css layouts.
Have you ever heard of Promises? They work on all modern browsers and are relatively simple to use. Have a look at this simple method to inject css to the html head:
function loadStyle(src) {
return new Promise(function (resolve, reject) {
let link = document.createElement('link');
link.href = src;
link.rel = 'stylesheet';
link.onload = () => resolve(link);
link.onerror = () => reject(new Error(`Style load error for ${src}`));
document.head.append(link);
});
}
You can implement it as follows:
window.onload = function () {
loadStyle("https://fonts.googleapis.com/css2?family=Raleway&display=swap")
.then(() => loadStyle("css/style.css"))
.then(() => loadStyle("css/icomoon.css"))
.then(() => {
alert('All styles are loaded!');
}).catch(err => alert(err));
}
It's really cool, right? This is a way to decide the priority of the styles using Promises.
To see a multi-style loading implementation see: https://stackoverflow.com/a/63936671/13720928
Here's a one line example, that uses plain JavaScript to inject a CSS link into the head element based on the filename portion of the URL:
document.head.innerHTML += '<link rel="stylesheet" href="css/style.css">';
Most browsers support it. See the browser compatibility.
There is a general jquery plugin that loads css and JS files synch and asych on demand.
It also keeps track off what is already been loaded :)
see: http://code.google.com/p/rloader/
Here's a way with jQuery's element creation method (my preference) and with callback onLoad:
var css = $("<link>", {
"rel" : "stylesheet",
"type" : "text/css",
"href" : "style.css"
})[0];
css.onload = function(){
console.log("CSS IN IFRAME LOADED");
};
document
.getElementsByTagName("head")[0]
.appendChild(css);
Below a full code using for loading JS and/or CSS
function loadScript(directory, files){
var head = document.getElementsByTagName("head")[0]
var done = false
var extension = '.js'
for (var file of files){
var path = directory + file + extension
var script = document.createElement("script")
script.src = path
script.type = "text/javascript"
script.onload = script.onreadystatechange = function() {
if ( !done && (!this.readyState ||
this.readyState == "loaded" || this.readyState == "complete") ) {
done = true
script.onload = script.onreadystatechange = null // cleans up a little memory:
head.removeChild(script) // to avoid douple loading
}
};
head.appendChild(script)
done = false
}
}
function loadStyle(directory, files){
var head = document.getElementsByTagName("head")[0]
var extension = '.css'
for (var file of files){
var path = directory + file + extension
var link = document.createElement("link")
link.href = path
link.type = "text/css"
link.rel = "stylesheet"
head.appendChild(link)
}
}
(() => loadScript('libraries/', ['listen','functions', 'speak', 'commands', 'wsBrowser', 'main'])) ();
(() => loadScript('scripts/', ['index'])) ();
(() => loadStyle('styles/', ['index'])) ();
var elem = document.createElement('link');
elem.rel = ' stylesheet'
elem.href= 'style.css';//Link of the css file
document.head.appendChild(elem);
This function uses memorization. And could be called many times with no conflicts of loading and running the same stylesheet twice. Also it's not resolving sooner than the stylesheet is actually loaded.
const loadStyle = function () {
let cache = {};
return function (src) {
return cache[src] || (cache[src] = new Promise((resolve, reject) => {
let s = document.createElement('link');
s.rel = 'stylesheet';
s.href = src;
s.onload = resolve;
s.onerror = reject;
document.head.append(s);
}));
}
}();
Please notice the parentheses () after the function expression.
Parallel loading of stylesheets:
Promise.all([
loadStyle('/style1.css'),
loadStyle('/style2.css'),
// ...
]).then(() => {
// do something
})
You can use the same method for dynamic loading scripts.
I'd like to share one more way to load not only css but all the assets (js, css, images) and handle onload event for the bunch of files. It's async-assets-loader. See the example below:
<script src="https://unpkg.com/async-assets-loader"></script>
<script>
var jsfile = "https://code.jquery.com/jquery-3.4.1.min.js";
var cssfile = "https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css";
var imgfile = "https://logos.keycdn.com/keycdn-logo-black.png";
var assetsLoader = new asyncAssetsLoader();
assetsLoader.load([
{uri: jsfile, type: "script"},
{uri: cssfile, type: "style"},
{uri: imgfile, type: "img"}
], function () {
console.log("Assets are loaded");
console.log("Img width: " + assetsLoader.getLoadedTags()[imgfile].width);
});
</script>
According to the async-assets-loader docs
Answer from future.
In 2022, we have import assertions api for import css file.
import mycss from "./style/mycss.css" assert { type: "css" };
document.adoptedStyleSheets = [sheet];
shadowRoot.adoptedStyleSheets = [sheet];
Browser support:
till september 2022, only chromium based browsers supported.
Read more at:
v8 import assertions post
tc39 github
t39 import assertions proposal
var fileref = document.createElement("link")
fileref.setAttribute("rel", "stylesheet")
fileref.setAttribute("type", "text/css")
fileref.setAttribute("th:href", "#{/filepath}")
fileref.setAttribute("href", "/filepath")
I'm using thymeleaf and this is work fine. Thanks
use:
document.getElementById("of head/body tag")
.innerHTML += '<link rel="stylesheet" type="text/css" href="style.css">';
This piece of code adds images to the DOM after dragging them into a div-element.
var showImage = function (ev) {
var file = ev.target.file;
var thumb = new Image(100,100);
thumb.src = ev.target.result;
thumb.className = 'thumbFoto';
thumb.title = file.name;
thumb.alt = file.name;
var anchor = document.createElement('a');
anchor.className = 'thumbLink';
anchor.href = ev.target.result;
anchor.rel = 'album1';
anchor.title = file.name;
anchor.appendChild(thumb);
dropZone.appendChild(anchor);
}
This code is linked to the page using
<script type="text/javascript" src="js/code.js"></script>
After the images are added to the webpage, I would like preview them using Fancybox.
When the page is loaded (before I dragged any image onto it), this script is executed in the html-header:
<script type="text/javascript">
$(document).ready(function() {
/* Apply fancybox to albums */
$("a.thumbLink").fancybox();
});
</script>
Now how do I make sure I can preview the recently added images using Fancybox?
I assume you use jQuery UI draggable object, you can call your fancybox on stop() event of your draggable object, like this:
$( ".selector" ).draggable({
stop: function( event, ui ) {
$("a.thumbLink").fancybox();
}
});
EDIT:
Based on your code you can simply put your fancybox caller in function of showFileInList, like this:
var showFileInList = function (ev) {
var file = ev.target.file;
if(document.getElementById("fileDropText")){
var textToBeRemoved = document.getElementById("fileDropText");
var imageToBeRemoved = document.getElementById("fileDropImg");
textToBeRemoved.parentElement.removeChild(textToBeRemoved);
imageToBeRemoved.parentElement.removeChild(imageToBeRemoved);
}
var thumb = new Image(100,100);
thumb.src = ev.target.result;
// var thumb = createThumb(ev.target.result);
thumb.className = 'thumbFoto';
thumb.title = file.name;
thumb.alt = file.name;
var anchor = document.createElement('a');
anchor.className = 'thumbLink';
anchor.href = ev.target.result;
anchor.rel = 'album1';
anchor.title = file.name;
// anchor.addEventListener("click", showImagePreview, false);
anchor.appendChild(thumb);
// fileList.insertBefore(anchor, dropZone);
dropZone.appendChild(anchor);
// show fancybox
$("a.thumbLink").fancybox({type: "inline", href: "#fileDrop"});
}
See working code HERE
Try routing all of your DOM changes through a single object using the "Chain of Responsibility" pattern. That way the object can keep track of any changes to the dom. Then I would use ConversationJS to fire a function that does whatever you want on DOM change: https://github.com/rhyneandrew/Conversation.JS
I'm dynamically generating and changing the content of my site with javascript.
I'm adding video files and the videojs-javascript-files by javascript and initialize the video by calling _V_(videos[i].id);.
However, initializing the video only works at the first time!
When I then change the content of the site and then move to the video's page again, initializing the video again (the video-tag has still the same id) does not work.
The browser's HTML5 videoplayer is there but not the videojs-styled one.
Is there any other way I could "force" initialization of the player? What could cause this problem?
This is my script:
videoPlayer = {
check: function() {
videos = document.getElementsByTagName("video");
if (videos.length > 0) {
this.init();
}
},
init: function() {
if (isPlayer) {
//alert("init");
for (var i = 0; i < videos.length; i++) var player = _V_(videos[i].id, {}, function() {
alert("player init!")
});
}
else {
this.build();
}
},
build: function() {
//alert("build");
if (isPlayer == false) {
var head = document.getElementsByTagName("head")[0];
var videoScript = document.createElement('script');
videoScript.type = 'text/javascript';
videoScript.src = './min/g=videojs';
var videocss = document.createElement('link');
videocss.type = 'text/css';
videocss.rel = 'stylesheet';
videocss.href = './min/g=videocss';
isPlayer = true;
videoScript.onload = this.init;
head.appendChild(videocss);
head.appendChild(videoScript);
}
}
}
Thank you very much in advance!
Have you tried creating a new video element and (re)initializing it instead of re-using the previous video element?
You can also try to "reset" everything, src, tracks, captions, etc with the new values
I know it's pretty late, but you could try checking the children of the video element. For example, if it already contains a div of class vjs-poster do nothing, else initialize video-js.
I'm trying to get an user input image to refresh say every two seconds. The javascript gets user input for an URL and the javscript adds it to the page. Then the images loaded need to refresh every 2 seconds but i can't get it to refresh properly without refreshing the whole page or reloading from the cache:
function getImg(){
var url=document.getElementById('txt').value;
var div=document.createElement('div');
div.className="imageWrapper";
var img=document.createElement('img');
img.src=url;
div.appendChild(img);
document.getElementById('images').appendChild(div);
return false;
}
setInterval(function(){
$('img').each(function(){
var time = (new Date()).getTime();
$(this).attr("src", $(this).attr("src") + time );
});
}, 2000);
any ideas?
When you need to force reload the resource, you have to add a dymmy queryString at the end of your url:
<img id="img1" src="myimg.png?dummy=23423423423">
Javascript:
$('#img1').attr('src','myimg.png?dummy=23423423423');
and change the dummy value for each refresh
Your premise seems good, not sure why it isn't working. Why mixing and matching jQuery with non-jquery? This is a modification of your code, but it is a working example. You should be able to adapt it for your purpose.
http://jsfiddle.net/zr692/1/
You can create elements via jQuery easily. See the modified getImg function I created. Ia also switched from attr to prop which is the recommended means of accessing the src attribute in jQuery 1.7+.
function getImg() {
var url = 'http://placehold.it/300x300/123456';
var $div = $('<div />');
var $img = $('<img />', { src: url });
$div.append($img);
$('body').append($div);
}
getImg();
var interval = setInterval(function() {
$('img').each(function() {
var time = (new Date()).getTime();
var oldurl = $(this).prop('src');
var newurl = oldurl.substring(0, oldurl.lastIndexOf('/') + 1) + time.toString().substr(7, 6);
$('#output').html(newurl);
$(this).prop('src', newurl);
});
}, 2000);
Put the image in a container as:
<div id="container"><img src=""../> </div>
then simply update the content of the container as:
$('#container').html('<img src="newSource"../>');