Setting href for .less stylesheet through JS - javascript

I'm using cookies to find out if the user is in light or dark mode onload of body. I always use the light.less as the fallback/default if a cookie can't be found. So in my <head> I have
<link rel="stylesheet" type="text/css" href="../assets/main.css">
<link rel="stylesheet/less" type="text/css" id="colorMode" href="../assets/light.less">
<script src="../assets/less.js/dist/less.min.js" type="text/javascript"></script>
and my body tag is as follows:
<body onload="checkNav(); checkCookies();" onresize="checkNav()">
The checkCookies() is the function to review the cookie and act accordingly, it is shown below.
function checkCookies() {
var style = getCookie("style");
if (style == 'dark') {
document.getElementById("colorMode").href = "../assets/dark.less";
document.getElementById("switchIcon").innerHTML = "toggle_on";
document.cookie = "style=dark; path=/~sam.walker";
}
else {
//Already set by default
}
}
The getCookie() function simply returns the relevant style cookie
The colorMode stylesheet with href = ../assets/light.less does change as expected to ../assets/dark.less as I've checked with inspector but the style itself does not physically change. I've checked cache and its nothing to do with that. Any help would be greatly appriciated.

Including the stylesheet as a .less format won't work unless you have <script src="less.js" type="text/javascript"></script> added within the <head> section of your page.
Check out the usage information from Less.js here

less.min.js will find references to LESS files and generates CSS from them when it loads.
You are creating a new reference to a LESS file after that, by which time it is too late for less.js to notice.
You need to call checkCookies(); after you have linked to the LESS stylesheet but before you load the less.js script.

Thanks for your help,
Through your info I have found the following (botch) fix:
var elem = document.getElementById('NameOfOriginalLessGeneratedStyle'); //REQUIRES CHANGE ON SERVER CHANGE
elem.parentNode.removeChild(elem);
//Deleted previous styles
less.refresh();
//Loads new style
Should run after stylesheet href change.

Related

CSS file is not being loaded dynamically via ng-href

I am trying to dynamically load different css styles into my page using ng-href, but the page is not being updated with the activated style. Code is as follows:
<html ng-app="myapp" ng-controller="myController as myctrl">
<head>
<link rel="stylesheet" ng-href="../assets/css/{{ myctrl.style }}.css">
</head>
</html>
In my controller, I do the following:
vm.style = "redStyle";
pub.subscribe('style', function(theStyle) {
vm.style = theStyle;
});
The variable in the subscribe is updated with the new style once a publish has taken place. But the respective css file is not being loaded such that the style is updated on the page. Any ideas what I am missing out on?
Here is a working demo
It's very much the same as what you have so it's something else in your code. Hard to tell unless you put up all your code.
Assuming the stylesheet actually does exist, and the style variable is getting updated then my guess is that the culprit is
pub.subscribe()
If this callback is being triggered by something outside of angular then angular wont see the updated variable. You can bring it back into angular space like so:
pub.subscribe('style', function (theStyle) {
$scope.$apply(function(){
vm.style= theStyle;
});
});
Try this:
<link rel="stylesheet" data-ng-if="myctrl.style" data-ng-href="../assets/css/{{ myctrl.style }}.css" />
I solved it differently.
In my html, I gave the link element an id:
<link id="theme" rel="stylesheet" ng-href="../assets/css/{{theme}}.css">
And in the controller I say:
var myTheme = document.getElementById("theme");
var path = "../assets/css/{{theme}}.css";
myTheme.href = path.replace("{theme}", theme.class);

Appending Stylesheet via javascript without flickering

I have a default CSS code for my page. I am injecting a CSS stylesheet file into the bottom of the head that overrides the default one using JavaScript. For some reason when I load the page, I see the default one and then it overrides it with the loaded stylesheet,
What can I do so that flickering will not occur? I thought that if I add a CSS at the end of the head after the default one I won't see the flickering because the content is not loaded yet, but apparently, it is. Any solution for that?
I don't know if flickering is the right word, I just see the default CSS and immediately after I see the page with the overridden CSS. Furthermore, maybe it's relevant, the overridden CSS only overrides some of the elements not all of them.
Here is the code:
<head>
<link href="/Content/app.min.css?ver=17" rel="stylesheet" />
<script>
// dark theme
if (localStorage.getItem("current_theme") === "dark") {
var head = document.head,
link = document.createElement('link');
link.type = 'text/css',
link.rel = 'stylesheet',
link.href = '/Content/dark_theme.min.css?r=' +
(Math.floor(Math.random() * 20000) + 1);
head.appendChild(link);
}
</script>
// the JavaScript appended stylsheet will render here before the </head> element
</head>
What happens is that the change of the new CSS happens only after the page has been loaded. I put a breakpoint in the footer, and only after the page is loaded I see the new CSS update.
I've found out that this happens because the stylesheet file is loaded asynchronously and therefore the delay. I need to inject the CSS code inline to make it work. The problem is with that approach is that it adds 9KB to each page call instead of dynamically based on the localStorage variable value.
The following code works faster:
<head>
<link href="/Content/app.min.css?ver=17" rel="stylesheet">
<script>
// dark theme
if (localStorage.getItem("current_theme") === "dark")
document.head.innerHTML += '<link rel="stylesheet" href="/Content/dark_theme.min.css">';
</script>
</head>
But your approach is wrong.
You'd better use a cookie for this stuff. Save the theme name to the cookie. Read cookie from request headers and include the required css right on the server side. So the client receives:
<head>
<link href="/Content/app.min.css?ver=17" rel="stylesheet">
<link rel="stylesheet" href="/Content/dark_theme.min.css">
</head>
Also I'd recommend setting correct Expires headers on the server and getting rid of ugly ?ver=17 or ?r=(Math.floor(Math.random() * 20000) + 1)

Load css file before js

I had a internal style followed by a external style. I noticed the page was blank till the external css didn't load. So i changed it to the below code. Now the external css request is made after the js.
Why for both above and how do i make css request before js. Are there any advantages to it(css before js in below code).
<body>
<style>
body {
background: #333;
}
</style>
<script>
var headHTML = document.getElementsByTagName('head')[0].innerHTML;
headHTML += '<link type="text/css" rel="stylesheet" href="build/main.css">';
document.getElementsByTagName('head')[0].innerHTML = headHTML;
</script>
<!-- The polyfills js is generated during the build process -->
<script src="build/polyfills.js"></script>
Use setTimeout in a function which is called when the body loads.
<body onload="loadPage()">
JS
function loadPage() {
//code to load css
setTimeout(function() {
//code to load js
}, 1);
}
I think that would work. Hope it helps.
This happends because a page is rendered from top to bottom. So I suppose that browser renders you inline styles and goes executing inlines script which uppends link to a style. Then it goes further and executes external script. And after that it loads your newly appended stylesheet.
So, I'd be too naive to ask but why don't you just put your stylesheet link into the head?
Of course you should just put your css files like normal people do :). but if you really want to make it happen, it's gonna get as ugly as this code gets:
<script>
var head = document.getElementsByTagName('head')[0],
link = document.createElement('link');
link.setAttribute('rel', 'stylesheet');
link.setAttribute('href', 'style.css');
var sheet = "sheet", cssRules = "cssRules";
if (!('sheet' in link)) {
sheet = "styleSheet";
cssRules = "rules";
}
var waitForCSS = setInterval(function() {
if (link[sheet]) {
// now you can load your javascript files here like I did with CSS
// or just use any js code you want.
clearInterval(waitForCSS);
}
}, 10);
head.appendChild(link);
</script>
The way to do this is
<head>
<link type="text/css" rel="stylesheet" href="build/main.css">
<style>
body {
background: #333;
}
</style>
</head>
<body>
<!--
Rest of your code in body
//-->
<!--Body is going to end after the below //-->
<script>
window.addEventListener("DOMContentLoaded",function(){
var sc=document.createElement('script');
sc.src="build/polyfills.js";
document.head.appendChild(sc);
});
</script>
</body>
A webpage is parsed from top to bottom.
So, try put the style in your head tag and place the scripts in just before end of body tag
In the script,
add an eventlistener to window when the Dom content Loaded, make a script tag, append src and append it to Head.
It's important to load the style before anything because it's the visual of your page. It's the first thing the user see.
You change css too along with DOM using javascript. So it is preferred to load css first.
Adding a preload mostly did the trick
<link rel="preload" href="build/main.css" as="style">
The browser now made the request for css. Then it makes a call for js. Then it adds CSS tag to the head. Finally, tries to remakes the call to get CSS but since the call is in progress or done it just loads it. There is an issue of FOUC though if CSS takes times.

Change entire CSS file on refresh

All other questions I've found relating to this are about changing specific elements, or changing the CSS file with a button, but what I'm looking to find out is:
Is there a script that will swap an entire CSS file whenever the page is refreshed?
I.e. I've got my core style.css and supplementary {color}.css files which replace certain elements in style.css, and I'd like those supplementary CSS files to be loaded randomly on refresh.
Sorry, I don't even know where, to begin with this. Hopefully, someone can offer some pointers?
Thank you.
Fundamentally this is just a matter of picking something at random, e.g.:
<head>
<!-- ... -->
<script>
var sheets = ["sheet1.css", "sheet2.css", "sheet3.css"];
var sheet = sheets[Math.floor(Math.random() * sheets.length)];
document.write('<link rel="stylesheet" href="' + sheet + '">');
</script>
<noscript>
<link rel="stylesheet" href="sheet1.css">
</noscript>
<!-- ... -->
(One of the rare cases where document.write isn't actually a bad solution.) Note the noscript fallback will always use the same stylesheet on browsers with JavaScript disabled.
All you need to do to load a CSS-file with Javascript is to add a <link> element to the DOM/body and it will be loaded automatically.
So in your <head> section you could include a <script> tag that just randomly selects a color.css from an array and generate the link tag, preferably as early as possible in the file to prevent flickering.
<script>
var colors = ['red.css', 'blue.css', 'green.css'];
var colors_idx = Math.floor(Math.random()*colors.length);
document.write('<link href="'+colors[ colors_idx ]+'" rel="stylesheet" type="text/css" />');
</script>
(PS. There are cleaner ways to inject HTML, keeping it concise to focus on the solution. Use your favorite approach, document.write can be a bit fickle.)

Find a script in head with jquery based on it's data-attribute

In my content editor you can change custom webfonts on the fly. If you change a font, it deletes all scripts and styles using the data-attribute as an identifier and the new ones then get appended after an ajax call. Now after some testing i realised it work's very well with css files but it ignores the < script >'s. Any ideas? Here is my Script:
$('head').find('[data-fontset-id=ce-fontset]').each(function() {
$(this).remove();
});
For example this is how the head section looks like:
<link data-fonset-id="ce-fontset" rel="stylesheet" href="..........">
<script data-fonset-id="ce-fontset" type="text/javascript" src="//use.typekit.net/xxxxx.js"></script>
<script data-fonset-id="ce-fontset" type="text/javascript">try{Typekit.load();}catch(e){}</script>
In this example, the css file gets removed but the javascript files didnt, any ideas why they are being ignored?
Thanks a lot in advance,
Michael

Categories