The best way to change favicon in browser [duplicate] - javascript
I have a web application that's branded according to the user that's currently logged in. I'd like to change the favicon of the page to be the logo of the private label, but I'm unable to find any code or any examples of how to do this. Has anybody successfully done this before?
I'm picturing having a dozen icons in a folder, and the reference to which favicon.ico file to use is just generated dynamically along with the HTML page. Thoughts?
Why not?
var link = document.querySelector("link[rel~='icon']");
if (!link) {
link = document.createElement('link');
link.rel = 'icon';
document.head.appendChild(link);
}
link.href = 'https://stackoverflow.com/favicon.ico';
Here’s some code that works in Firefox, Opera, and Chrome (unlike every other answer posted here). Here is a different demo of code that works in IE11 too. The following example might not work in Safari or Internet Explorer.
/*!
* Dynamically changing favicons with JavaScript
* Works in all A-grade browsers except Safari and Internet Explorer
* Demo: http://mathiasbynens.be/demo/dynamic-favicons
*/
// HTML5™, baby! http://mathiasbynens.be/notes/document-head
document.head = document.head || document.getElementsByTagName('head')[0];
function changeFavicon(src) {
var link = document.createElement('link'),
oldLink = document.getElementById('dynamic-favicon');
link.id = 'dynamic-favicon';
link.rel = 'shortcut icon';
link.href = src;
if (oldLink) {
document.head.removeChild(oldLink);
}
document.head.appendChild(link);
}
You would then use it as follows:
var btn = document.getElementsByTagName('button')[0];
btn.onclick = function() {
changeFavicon('http://www.google.com/favicon.ico');
};
Fork away or view a demo.
If you have the following HTML snippet:
<link id="favicon" rel="shortcut icon" type="image/png" href="favicon.png" />
You can change the favicon using Javascript by changing the HREF element on this link, for instance (assuming you're using JQuery):
$("#favicon").attr("href","favicon2.png");
You can also create a Canvas element and set the HREF as a ToDataURL() of the canvas, much like the Favicon Defender does.
jQuery Version:
$("link[rel='shortcut icon']").attr("href", "favicon.ico");
or even better:
$("link[rel*='icon']").attr("href", "favicon.ico");
Vanilla JS version:
document.querySelector("link[rel='shortcut icon']").href = "favicon.ico";
document.querySelector("link[rel*='icon']").href = "favicon.ico";
A more modern approach:
const changeFavicon = link => {
let $favicon = document.querySelector('link[rel="icon"]')
// If a <link rel="icon"> element already exists,
// change its href to the given link.
if ($favicon !== null) {
$favicon.href = link
// Otherwise, create a new element and append it to <head>.
} else {
$favicon = document.createElement("link")
$favicon.rel = "icon"
$favicon.href = link
document.head.appendChild($favicon)
}
}
You can then use it like this:
changeFavicon("http://www.stackoverflow.com/favicon.ico")
Here's a snippet to make the favicon be an emoji, or text. It works in the console when I'm at stackoverflow.
function changeFavicon(text) {
const canvas = document.createElement('canvas');
canvas.height = 64;
canvas.width = 64;
const ctx = canvas.getContext('2d');
ctx.font = '64px serif';
ctx.fillText(text, 0, 64);
const link = document.createElement('link');
const oldLinks = document.querySelectorAll('link[rel="shortcut icon"]');
oldLinks.forEach(e => e.parentNode.removeChild(e));
link.id = 'dynamic-favicon';
link.rel = 'shortcut icon';
link.href = canvas.toDataURL();
document.head.appendChild(link);
}
changeFavicon('❤️');
The favicon is declared in the head tag with something like:
<link rel="shortcut icon" type="image/ico" href="favicon.ico">
You should be able to just pass the name of the icon you want along in the view data and throw it into the head tag.
Here's some code I use to add dynamic favicon support to Opera, Firefox and Chrome. I couldn't get IE or Safari working though. Basically Chrome allows dynamic favicons, but it only updates them when the page's location (or an iframe etc in it) changes as far as I can tell:
var IE = navigator.userAgent.indexOf("MSIE")!=-1
var favicon = {
change: function(iconURL) {
if (arguments.length == 2) {
document.title = optionalDocTitle}
this.addLink(iconURL, "icon")
this.addLink(iconURL, "shortcut icon")
// Google Chrome HACK - whenever an IFrame changes location
// (even to about:blank), it updates the favicon for some reason
// It doesn't work on Safari at all though :-(
if (!IE) { // Disable the IE "click" sound
if (!window.__IFrame) {
__IFrame = document.createElement('iframe')
var s = __IFrame.style
s.height = s.width = s.left = s.top = s.border = 0
s.position = 'absolute'
s.visibility = 'hidden'
document.body.appendChild(__IFrame)}
__IFrame.src = 'about:blank'}},
addLink: function(iconURL, relValue) {
var link = document.createElement("link")
link.type = "image/x-icon"
link.rel = relValue
link.href = iconURL
this.removeLinkIfExists(relValue)
this.docHead.appendChild(link)},
removeLinkIfExists: function(relValue) {
var links = this.docHead.getElementsByTagName("link");
for (var i=0; i<links.length; i++) {
var link = links[i]
if (link.type == "image/x-icon" && link.rel == relValue) {
this.docHead.removeChild(link)
return}}}, // Assuming only one match at most.
docHead: document.getElementsByTagName("head")[0]}
To change favicons, just go favicon.change("ICON URL") using the above.
(credits to http://softwareas.com/dynamic-favicons for the code I based this on.)
Or if you want an emoticon :)
var canvas = document.createElement("canvas");
canvas.height = 64;
canvas.width = 64;
var ctx = canvas.getContext("2d");
ctx.font = "64px serif";
ctx.fillText("☠️", 0, 64);
$("link[rel*='icon']").prop("href", canvas.toDataURL());
Props to https://koddsson.com/posts/emoji-favicon/
in most cases, favicon is declared like this.
<link rel="icon" href"...." />
This way you can attain reference to it with this.
const linkElement = document.querySelector('link[rel=icon]');
and you can change the picture with this
linkElement.href = 'url/to/any/picture/remote/or/relative';
The only way to make this work for IE is to set you web server to treat requests for *.ico to call your server side scripting language (PHP, .NET, etc). Also setup *.ico to redirect to a single script and have this script deliver the correct favicon file. I'm sure there is still going to be some interesting issues with cache if you want to be able to bounce back and forth in the same browser between different favicons.
I would use Greg's approach and make a custom handler for favicon.ico
Here is a (simplified) handler that works:
using System;
using System.IO;
using System.Web;
namespace FaviconOverrider
{
public class IcoHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "image/x-icon";
byte[] imageData = imageToByteArray(context.Server.MapPath("/ear.ico"));
context.Response.BinaryWrite(imageData);
}
public bool IsReusable
{
get { return true; }
}
public byte[] imageToByteArray(string imagePath)
{
byte[] imageByteArray;
using (FileStream fs = new FileStream(imagePath, FileMode.Open, FileAccess.Read))
{
imageByteArray = new byte[fs.Length];
fs.Read(imageByteArray, 0, imageByteArray.Length);
}
return imageByteArray;
}
}
}
Then you can use that handler in the httpHandlers section of the web config in IIS6 or use the 'Handler Mappings' feature in IIS7.
There is a single line solution for those who use jQuery:
$("link[rel*='icon']").prop("href",'https://www.stackoverflow.com/favicon.ico');
I use this feature all the time when developing sites ... so I can see at-a-glance which tab has local, dev or prod running in it.
Now that Chrome supports SVG favicons it makes it a whole lot easier.
Tampermonkey Script
Have a gander at https://gist.github.com/elliz/bb7661d8ed1535c93d03afcd0609360f for a tampermonkey script that points to a demo site I chucked up at https://elliz.github.io/svg-favicon/
Basic code
Adapted this from another answer ... could be improved but good enough for my needs.
(function() {
'use strict';
// play with https://codepen.io/elliz/full/ygvgay for getting it right
// viewBox is required but does not need to be 16x16
const svg = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<circle cx="8" cy="8" r="7.2" fill="gold" stroke="#000" stroke-width="1" />
<circle cx="8" cy="8" r="3.1" fill="#fff" stroke="#000" stroke-width="1" />
</svg>
`;
var favicon_link_html = document.createElement('link');
favicon_link_html.rel = 'icon';
favicon_link_html.href = svgToDataUri(svg);
favicon_link_html.type = 'image/svg+xml';
try {
let favicons = document.querySelectorAll('link[rel~="icon"]');
favicons.forEach(function(favicon) {
favicon.parentNode.removeChild(favicon);
});
const head = document.getElementsByTagName('head')[0];
head.insertBefore( favicon_link_html, head.firstChild );
}
catch(e) { }
// functions -------------------------------
function escapeRegExp(str) {
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
}
function replaceAll(str, find, replace) {
return str.replace(new RegExp(escapeRegExp(find), 'g'), replace);
}
function svgToDataUri(svg) {
// these may not all be needed - used to be for uri-encoded svg in old browsers
var encoded = svg.replace(/\s+/g, " ")
encoded = replaceAll(encoded, "%", "%25");
encoded = replaceAll(encoded, "> <", "><"); // normalise spaces elements
encoded = replaceAll(encoded, "; }", ";}"); // normalise spaces css
encoded = replaceAll(encoded, "<", "%3c");
encoded = replaceAll(encoded, ">", "%3e");
encoded = replaceAll(encoded, "\"", "'"); // normalise quotes ... possible issues with quotes in <text>
encoded = replaceAll(encoded, "#", "%23"); // needed for ie and firefox
encoded = replaceAll(encoded, "{", "%7b");
encoded = replaceAll(encoded, "}", "%7d");
encoded = replaceAll(encoded, "|", "%7c");
encoded = replaceAll(encoded, "^", "%5e");
encoded = replaceAll(encoded, "`", "%60");
encoded = replaceAll(encoded, "#", "%40");
var dataUri = 'data:image/svg+xml;charset=UTF-8,' + encoded.trim();
return dataUri;
}
})();
Just pop your own SVG (maybe cleaned with Jake Archibald's SVGOMG if you're using a tool) into the const at the top. Make sure it is square (using the viewBox attribute) and you're good to go.
I use favico.js in my projects.
It allows to change the favicon to a range of predefined shapes and also custom ones.
Internally it uses canvas for rendering and base64 data URL for icon encoding.
The library also has nice features: icon badges and animations; purportedly, you can even stream the webcam video into the icon :)
According to WikiPedia, you can specify which favicon file to load using the link tag in the head section, with a parameter of rel="icon".
For example:
<link rel="icon" type="image/png" href="/path/image.png">
I imagine if you wanted to write some dynamic content for that call, you would have access to cookies so you could retrieve your session information that way and present appropriate content.
You may fall foul of file formats (IE reportedly only supports it's .ICO format, whilst most everyone else supports PNG and GIF images) and possibly caching issues, both on the browser and through proxies. This would be because of the original itention of favicon, specifically, for marking a bookmark with a site's mini-logo.
Yes totally possible
Use a querystring after the favicon.ico (and other files links -
see answer link below)
Simply make sure the server responds to the "someUserId" with
the correct image file (that could be static routing rules, or
dynamic server side code).
e.g.
<link rel="shortcut icon" href="/favicon.ico?userId=someUserId">
Then whatever server side language / framework you use should easily be able to find the file based on the userId and serve it up in response to that request.
But to do favicons properly (its actually a really complex subject) please see the answer here https://stackoverflow.com/a/45301651/661584
A lot lot easier than working out all the details yourself.
Enjoy.
Testing the proposed solutions on 2021 on Chrome, I found that some times the browser cache the favicon and do not show the change, even if the link was changed
This code worked (similar to previous proposal but adds a random parameter to avoid caching)
let oldFavicon = document.getElementById('favicon')
var link = document.createElement('link')
link.id = 'favicon';
link.type = 'image/x-icon'
link.rel = 'icon';
link.href = new_favicon_url +'?=' + Math.random();
if (oldFavicon) {
document.head.removeChild(oldFavicon);
}
document.head.appendChild(link);
Copied from https://gist.github.com/mathiasbynens/428626#gistcomment-1809869
in case that someone else have the same problem
Related
Using CSS media queries inside a JavaScript file
I am working on an already existing webpage and want to resize some elements using CSS media queries like width but i only have access to the script file, is there a way to do this without injecting CSS in my js file? As of now i've tried injecting my css file line by line in my js file
Although less than ideal, it seems that this is possible by creating a MediaQueryList object from window.matchMedia(), and set inline styles by listening to events for changes on it. Detailed guide on: MDN Here is a quick example targeting #media (max-width: 640px): (Open full page and try change window size to see effects) const body = document.querySelector("body"); const title = document.querySelector("h1"); const media = window.matchMedia("(max-width: 640px)"); body.style.background = media.matches ? "pink" : "lightgreen"; title.innerText = "Open full page and try change window size"; media.addEventListener("change", (event) => { if (event.matches) { body.style.background = "pink"; title.innerText = `Matching: ${media.media}`; } if (!event.matches) { body.style.background = "lightgreen"; title.innerText = `Not matching: ${media.media}`; } }); <h1></h1>
The best way would be to load a stylesheet that is hosted someplace you control, and then ask JavaScript to load it in the page that you want. Code would look like: function loadStylesheet( absPath ) { const linkElement = document.createElement('link'); linkElement.rel = 'stylesheet'; linkElement.href = absPath; linkElement.type = "text/css"; const head = document.head || document.querySelector('head'); head.insertAdjacentElement('beforeend', linkElement); } Then you would call loadStylesheet() with your stylesheet's URL as the parameter.
Print html page with internet explorer
I have to print a table with its style So I'm using jQuery.copyCSS to clone its CSS,style into another element (Because I'm testing it on IE 8 and seems like it doesn't preserve CSS after clicking/calling window.print()) https://github.com/moagrius/copycss I thought to "send" the table to another page and call from there the print. Thus I need to clone the css into another element (to pass on the second page) $("#table_report").clone().attr({"id":"table_report_clone", "name":"clone"}).appendTo("body"); // doesn't matter if it appears on the page, I will just pass these one $('#table_report_clone').copyCSS('#table_report'); // copy CSS from original to clone var clone = $("#table_report_clone").html(); var w = window.open(); $(w.document.body).html(clone ); //table_report should be the table with its style w.document.close(); So, passing .html it will parse only the HTML not including the style How can I do that? EDIT 1: Now some icons are being displayed..however the table is really 'raw' w.document.write(clone); // instead of $(w.document.body).html(clone); EDIT 2: Changed adding some tips by #Roljhon En fact this does work on FF, Chrome, but in IE 8 nope.. (Anyway I'm using JQuery 1.5.1) dumpCSSText is a function from https://stackoverflow.com/a/15011387/7370271 since I have to get/join the styles attributes $("#table_report").inlineStyler(); var table_report = document.getElementById("table_report"); var w = window.open(); var css = "" + dumpCSSText(table_report) //css of your table_content var style = document.createElement('style'); style.type = "text/css"; style.appendChild(document.createTextNode(css)); w.document.head.appendChild(style); w.document.body.innerHTML = document.getElementById("table_report").innerHTML EDIT 3: Now it works var table_report = $("#table_report").html(); var w = window.open(); w.document.write('<html><head><link rel="stylesheet" href="/i/css/apex.min.css?v=4.2.6.00.03" type="text/css" /><!--[if IE]><link rel="stylesheet" href="/i/css/apex_ie.min.css?v=4.2.6.00.03" type="text/css"/><![endif]--><link rel="stylesheet" href="/i/libraries/jquery-ui/1.8.22/themes/base/jquery-ui.min.css" type="text/css" /></head><body>'); $(w.document.body).html(table_report); w.document.write('</body></html>'); w.document.close(); w.focus(); w.print(); w.close(); Finally I'm now at 90%..the only problem is CSS in IE8.. Thank you
I tried to create a solution to your problem and this could possibly solve it or give you an idea of what to do to pass your table css. Option 1 You could create a link to the stylesheet.Create it directly from your javascript. But make sure that the stylesheet content is the exact CSS of the table_content and append this to the head section of the new window and at the same time write your table in the body part of the new window. var link = document.createElement('link'); link.rel = "stylesheet"; link.href ="table_content_style.css"; // this will have your table_content_clone CSS w.document.head.appendChild(link); w.document.body.innerHTML = "<h1>test</h1>"; // your html table markup Option 2 You could create the stylesheet as well directly from javascript and doing the same thing as above. var css = "body{background-color: red;}"; //css of your table_content var style = document.createElement('style'); style.type="text/css"; style.appendChild(document.createTextNode(css)); w.document.head.appendChild(style); w.document.body.innerHTML = "<h1>test</h1>"; // your html table markup I hope that helps. See fiddle: https://jsfiddle.net/0vzwzrpq/
The best approach to style elements you'd like to print is to use CSS media queries. #media print { body { background-color: pink; } } There is a very good article here about the subject: https://www.smashingmagazine.com/2011/11/how-to-set-up-a-print-style-sheet/
Link an external CSS file to a JavaScript File [duplicate]
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">';
Load a javascript file and css file depending on user agent
Just like in the title. I got two files: one is javascript file and one is css file. And if user-agent is an iPad I want to load those files - but only when user-agent is iPad. So below two lines are only loaded when user-agent is an iPad. how can i achieve that <link rel="stylesheet" href="/c/dropkick.css" type="text/css"/> <script src="/s/jquery.dropkick-1.0.0.js" type="text/javascript"></script>
if (navigator.userAgent.match(/iPad/i) != null){ // may need changing? var js = document.createElement('script'); js.type = "text/javascript"; js.src = "/s/jquery.dropkick-1.0.0.js"; var css = document.createElement('link'); css.type = "text/css"; css.rel = "stylesheet"; css.href = "/c/dropkick.css"; var h = document.getElementsByTagName('head')[0]; h.appendChild(js); h.appendChild(css); } Or whatever would be in the User-Agent header for an iPad. References: window.navigator.userAgent document.createElement node.appendChild
You can use document.createElement to create link and script elements, and then append them to the document (for instance, append them to document.getElementsByTagName('head')[0] or similar). This answer here on SO suggests that you can dtect an iPad by just looking for the string "ipad" in the navigator.userAgent field. Of course, the user agent field can be spoofed. So for example: <script> (function() { var elm, head; if (navigator.userAgent.indexOf("ipad") !== -1) { head = document.getElementsByTagName('head')[0] || document.body || document.documentElement; elm = document.createElement('link'); elm.rel = "stylesheet"; elm.href = "/c/dropkick.css"; head.appendChild(elm); elm = document.createElement('script'); elm.src = "/s/jquery.dropkick-1.0.0.js"; head.appendChild(elm); } })(); </script> ...but that's off-the-cuff, untested. (Note that there's no reason to put the type on either link or script; in the case of link, the type comes from the content-type of the response. In the case of script, the default is JavaScript.)
Debugging the base URL element with Firebug
I'm adding the base URL tag to the document head using JS, so the relative links on the page work. But it does not take effect, and Firebug (debugging addon for Firefox) shows the <BASE /> element greyed out.. why? Does this mean Firefox cannot understand it or the syntax is incorrect? Image http://www.freeimagehosting.net/uploads/a3122c1ddd.png
http://www.w3schools.com/TAGS/tag_base.asp the base tag has two components href and target. Yours seems to be fine. coold you give some example of the links on which it is failing? see http://ashita.org/StackOverflow/base_test.html for a demonstration. (my test) Edit: see comments function addBase(url) { var regex = /^(https?|ftp):\/\//; var a = Array.prototype.slice.call(document.getElementsByTagName('a'),0); var link = Array.prototype.slice.call(document.getElementsByTagName('link'),0); var script = Array.prototype.slice.call(document.getElementsByTagName('script'),0); var img = Array.prototype.slice.call(document.getElementsByTagName('img'),0); var hrefs = a.concat(link); var srcs = img.concat(script); var element,href,src; for (var i=0,len=hrefs.length;i<len;++i) { element = hrefs[i]; href = element.getAttribute("href"); if (href) { if (!regex.test(href)) { href = (url + "/" + href).replace("//","/"); //to handle double slash collision element.setAttribute("href",href); } } } for (var i=0,len=srcs.length;i<len;++i) { element = srcs[i]; src = element.getAttribute("src"); if (src) { if (!regex.test(src)) { src = (url + "/" + src).replace("//","/"); //to handle double slash collision element.setAttribute("src",src); } } } } Tested and working in firefox