I have a page which has <link> in the header that loads the CSS named light.css. I also have a file named dark.css. I want a button to swap the style of the page all together (there are 40 selectors used in css file and some do not match in two files).
How can I remove reference to light.css with JS and remove all the styles that were applied and then load dark.css and apply all the styles from that? I can't simply reset all of the elements, since some of the styles are applied through different css files and some are dynamically generated by JS. Is there a simple, yet effective way to do that without reloading the page? Vanilla JS is preferable, however I will use jQuery for later processing anyways, so jQ is also fine.
You can include all the stylesheets in the document and then activate/deactivate them as needed.
In my reading of the spec, you should be able to activate an alternate stylesheet by changing its disabled property from true to false, but only Firefox seems to do this correctly.
So I think you have a few options:
Toggle rel=alternate
<link rel="stylesheet" href="main.css">
<link rel="stylesheet alternate" href="light.css" id="light" title="Light">
<link rel="stylesheet alternate" href="dark.css" id="dark" title="Dark">
<script>
function enableStylesheet (node) {
node.rel = 'stylesheet';
}
function disableStylesheet (node) {
node.rel = 'alternate stylesheet';
}
</script>
Set and toggle disabled
<link rel="stylesheet" href="main.css">
<link rel="stylesheet" href="light.css" id="light" class="alternate">
<link rel="stylesheet" href="dark.css" id="dark" class="alternate">
<script>
function enableStylesheet (node) {
node.disabled = false;
}
function disableStylesheet (node) {
node.disabled = true;
}
document
.querySelectorAll('link[rel=stylesheet].alternate')
.forEach(disableStylesheet);
</script>
Toggle media=none
<link rel="stylesheet" href="main.css">
<link rel="stylesheet" href="light.css" media="none" id="light">
<link rel="stylesheet" href="dark.css" media="none" id="dark">
<script>
function enableStylesheet (node) {
node.media = '';
}
function disableStylesheet (node) {
node.media = 'none';
}
</script>
You can select a stylesheet node with getElementById, querySelector, etc.
(Avoid the nonstandard <link disabled>. Setting HTMLLinkElement#disabled is fine though.)
You can create a new link, and replace the old one with the new one. If you put it in a function, you can reuse it wherever it's needed.
The Javascript:
function changeCSS(cssFile, cssLinkIndex) {
var oldlink = document.getElementsByTagName("link").item(cssLinkIndex);
var newlink = document.createElement("link");
newlink.setAttribute("rel", "stylesheet");
newlink.setAttribute("type", "text/css");
newlink.setAttribute("href", cssFile);
document.getElementsByTagName("head").item(cssLinkIndex).replaceChild(newlink, oldlink);
}
The HTML:
<html>
<head>
<title>Changing CSS</title>
<link rel="stylesheet" type="text/css" href="positive.css"/>
</head>
<body>
STYLE 1
STYLE 2
</body>
</html>
For simplicity, I used inline javascript. In production you would want to use unobtrusive event listeners.
If you set an ID on the link element
<link rel="stylesheet" id="stylesheet" href="stylesheet1.css"/>
you can target it with Javascript
document.getElementsByTagName('head')[0].getElementById('stylesheet').href='stylesheet2.css';
or just..
document.getElementById('stylesheet').href='stylesheet2.css';
Here's a more thorough example:
<head>
<script>
function setStyleSheet(url){
var stylesheet = document.getElementById("stylesheet");
stylesheet.setAttribute('href', url);
}
</script>
<link id="stylesheet" rel="stylesheet" type="text/css" href="stylesheet1.css"/>
</head>
<body>
<a onclick="setStyleSheet('stylesheet1.css')" href="#">Style 1</a>
<a onclick="setStyleSheet('stylesheet2.css')" href="#">Style 2</a>
</body>
This question is pretty old but I would suggest an approach which is not mentioned here, in which you will include both the CSS files in the HTML, but the CSS will be like
light.css
/*** light.css ***/
p.main{
color: #222;
}
/*** other light CSS ***/
and dark.css will be like
/*** dark.css ***/
.dark_theme p.main{
color: #fff;
background-color: #222;
}
/*** other dark CSS ***/
basicall every selector in dark.css will be a child of .dark_theme
Then all you need to do is to change the class of body element if someone selects to change the theme of the website.
$("#changetheme").click(function(){
$("body").toggleClass("dark_theme");
});
And now all your elements will have the dark css once the user clicks on #changetheme. This is very easy to do if you are using any kind of CSS preprocessors.
You can also add CSS animations for backgrounds and colors which makes the transition highly smooth.
Using jquery you can definitely swap the css file. Do this on button click.
var cssLink = $('link[href*="light.css"]');
cssLink.replaceWith('<link href="dark.css" type="text/css" rel="stylesheet">');
Or as sam's answer, that works too. Here is the jquery syntax.
$('link[href*="light.css"]').prop('disabled', true);
$('link[href*="dark.css"]').prop('disabled', false);
Using jquery .attr() you can set href of your link tag .i.e
Sample code
$("#yourButtonId").on('click',function(){
$("link").attr(href,yourCssUrl);
});
Maybe I'm thinking too complicated, but since the accepted answer was not working for me I thought I'd share my solution as well.
Story:
What I wanted to do was to include different 'skins' of my page in the head as additional stylesheets that where added to the 'main' style and switch them by pressing a button on the page (no browser settings or stuff).
Problem:
I thought #sam's solution was very elegant but it did not work at all for me. At least part of the problem is that I'm using one main CSS file and just add others on top as 'skins' and thus I had to group the files with the missing 'title' property.
Here is what I came up with.
First add all 'skins' to the head using 'alternate':
<link rel="stylesheet" href="css/main.css" title='main'>
<link rel="stylesheet alternate" href="css/skin1.css" class='style-skin' title=''>
<link rel="stylesheet alternate" href="css/skin2.css" class='style-skin' title=''>
<link rel="stylesheet alternate" href="css/skin3.css" class='style-skin' title=''>
Note that I gave the main CSS file the title='main' and all others have a class='style-skin' and no title.
To switch the skins I'm using jQuery. I leave it up to the purists to find an elegant VanillaJS version:
var activeSkin = 0;
$('#myButton').on('click', function(){
var skins = $('.style-skin');
if (activeSkin > skins.length) activeSkin=0;
skins.each(function(index){
if (index === activeSkin){
$(this).prop('title', 'main');
$(this).prop('disabled', false);
}else{
$(this).prop('title', '');
$(this).prop('disabled', true);
}
});
activeSkin++
});
What it does is it iterates over all available skins, takes the (soon) active one, sets the title to 'main' and activates it. All other skins are disabled and title is removed.
Simply update you Link href attribute to your new css file.
function setStyleSheet(fileName){
document.getElementById("WhatEverYouAssignIdToStyleSheet").setAttribute('href', fileName);
}
I reworked lampe's example, and you can add a class using a selector in this way:
first apply the class to specific selectors in a javascript (repeat as many times you need for specific element selectors (in my HTML):
$("p:nth-of-type(even)").toggleClass("main mainswitch");
Then the html looks like this
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js">
</script>
<script>
$(document).ready(function(){
$("button").click(function(){
$(".mainswitch").toggleClass("main");
});
});
</script>
<style>
.main {
font-size: 120%;
color: red;
}
</style>
</head>
<body>
<div>
<p>This is a paragraph.</p>
<p class="main mainswitch">This is another paragraph.</p>
<p>This is a paragraph.</p>
<p>This is a paragraph.</p>
<p>This is a paragraph.</p>
</div>
<button>Toggle class "main" for p elements</button>
</body>
</html>
If you're using Angular (cause it's not 2013 anymore), you can try the answer/solution/suggestion from here:
How can I change the targeted CSS file on a click event
It did the trick for me.
Related
I am using Javascript to change the css of my web page and I am trying to figure out how to make which ever css is picked, the css for all other pages on my site.
Here is my code:
<link id="pagestyle" rel="stylesheet" type="text/css" href="dash4.css">
<script>
function swapStyleSheet(sheet){
document.getElementById('pagestyle').setAttribute('href', sheet);
}
</script>
<button class="settings" onclick="swapStyleSheet('dash4.css')"> COMFORTABLE</button>
<button class="settings" onclick="swapStyleSheet('dash4_minimal.css')">MINIMAL</button>
just put your script before the closing tag of your body
and with jquery write
$(document).ready(function(){
$("#button-id").click(function(){
$("#pagestyle").attr("href",sheet);
});
});
I am building a simple web app for mobile platforms using jQuery Mobile and in that, I intend to read some data from an API sending it as JSON (which I have exposed from a server side Django based project), and then parses it using jQuery's mechanism and then I create list elements based off that data.
Now, I have the following index.html:
<html>
<head>
<title>Playism App</title>
<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="js/jm/jquery.mobile-1.3.2.min.js"></script>
<script type="text/javascript" src="js/jsonParser.js"></script>
<link rel="stylesheet" type="text/css" href="css/major.css">
<link rel="stylesheet" type="text/css" href="js/jm/jquery.mobile-1.3.2.min.css">
<link rel="stylesheet" type="text/css" href="js/jm/jquery.mobile.theme-1.3.2.min.css">
</head>
<body>
<p>List of games: </p><br/>
<div id="gameContainer" data-role="page">
<ul data-role="listview" data-inset="true" data-filter="true" id="gamesList">
<!-- Content here will be dynamically generated based on the JSON output parsed from the API feed -->
<li>Dummy</li>
</ul>
</div>
<script type="text/javascript" src="js/gamesRenderer.js"></script>
<script type="text/javascript">
$(document).ready(function(){
renderGames();
});
</script>
</body>
</html>
Now, just to test I created that Dummy list element and it's rendering perfect but there is no styling applied to any of the new elements which I inject using .append() calls from jQuery. The code is as follows:
function renderGames(){
for (var i = objCreated.length - 1; i >= 0; i--) {
$("ul#gamesList").append("<li><a href='#''>" + objCreated[i].name + "</a></li></ul>");
};
}
and as can be seen in index.html, I am calling it at DOM ready but no jQuery mobile styling gets applied to these manually injected list elements whereas the Dummy element gets proper styling. I believe something is wrong with the order in which the elements are called.
Thanks in advance !
Don't get me wrong but this question was asked so many times, but here's a solution for you:
function renderGames(){
for (var i = objCreated.length - 1; i >= 0; i--) {
$("ul#gamesList").append("<li><a href='#''>" + objCreated[i].name + "</a></li></ul>");
};
$("ul#gamesList").listview('refresh');
}
You need to use:
$("ul#gamesList").listview('refresh');
When working with a dynamically added jQuery Mobile you must manually start markup enhancement process. Read more about it in this article.
One other thing, never use document ready with jQuery Mobile, they should not be combined. Read more about it here. Sometimes it works sometimes not. Basically when working with jQuery Mobile always use page events.
Your final javascript should look like this:
$(document).on('pagebeforeshow', '#gameContainer', function(){
renderGames();
});
function renderGames(){
for (var i = 10 - 1; i >= 0; i--) {
$("ul#gamesList").append("<li><a href='#''>Some object" + i + "</a></li></ul>");
};
$("ul#gamesList").listview('refresh');
}
Working example: http://jsfiddle.net/Gajotres/5uPfM/
Seems the for loop make the css cannot load properly. Don't know what is the 'objCreated'.
Try to migrate the code here in JSFiddle.
Here is the code:
<body>
<p>List of games: </p><br/>
<div id="gameContainer" data-role="page">
<ul data-role="listview" data-inset="true" data-filter="true" id="gamesList">
<li>Dummy</li>
</ul>
</div>
</body>
$(document).ready(function(){
renderGames();
});
function renderGames(){
$("ul#gamesList").append("<li><a href='#''>Hello world!</a></li></ul>")
}
The css seems works on the injected elements. The list-style is "none" because of the jQuery Mobile UI css works.
first apply css and see your css file are linked properly
<link rel="stylesheet" type="text/css" href="css/major.css">
<link rel="stylesheet" type="text/css" href="js/jm/jquery.mobile-1.3.2.min.css">
<link rel="stylesheet" type="text/css" href="js/jm/jquery.mobile.theme-1.3.2.min.css">
then JS and see your js file are linked properly
<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="js/jm/jquery.mobile-1.3.2.min.js"></script>
<script type="text/javascript" src="js/jsonParser.js"></script>
<script type="text/javascript">
$(document).ready(function(){
renderGames();
});
</script>
I have a html + css + javascript application.
I want to be able to enable theming.
All my css are replicated in two folders: /theme1/... and /theme2/...
So my html looks like:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="theme1/file1.css"/>
<link rel="stylesheet" href="theme1/file2.css"/>
....
....
</head>
<body>
.....
</body>
</html>
I want to be able to change using javascript the home folder of the css (theme1 to theme2).
Any ideas?
Here is what you will need to solve the problem:
Get the relevant tags. In this case, any link tag with rel="stylesheet" will probably do, but you can even go so far as to specify "starting with theme1" if you want. This can all be done with document.querySelectorAll("link[rel=stylesheet][href^=theme1]")
Loop through them. A simple for loop will do nicely.
getAttribute("href") gets the string you need.
replace() will allow you to replace the part of the string you want.
setAttribute("href",newattr) will put the attribute back into the tag.
<link id="foo" rel="stylesheet" href="theme1/file1.css"/>
When you want to change the theme:
document.getElementById('foo').href = 'theme1/file2.css';
I wondering how I can select the two stylesheet links I have below in the resize function below. I need to modify the two links href value based on the orientation value, but I'm unsure how to select and populate those inside the conditional statement below, any ideas?
<head>
<link rel="stylesheet" href="css/style.css" type='text/css' media='all' />
<link rel="stylesheet" href="css/iphone.css" type='text/css' media='all' />
<script type="text/javascript">
$ = jQuery
$(document).ready(function() {
$(window).resize(function() {
var orientation = window.orientation;
if(orientation == 90 || orientation == -90) {
//populate href of stylesheet link here
} else {
//populate href of stylesheet link here
}
});
});
</script>
</head>
Just give your stylesheet and id and change it like so:
$("#id").attr("href", "/somecss.css");
If you use CSS3 you can use css3 Media Queries to change your styles based on the Orientation of the users browser.
<link rel="stylesheet" media="all and (orientation:landscape)"href="landscape.css">
This will only include this stylesheet if the orientation of the users browser is landscape.
Remember this will only work on CSS3 compatible browsers.
Look at this link :
http://www.1stwebdesigner.com/tutorials/how-to-use-css3-orientation-media-queries/
another SO question:
CSS3: Detecting device orientation for iPhone
Its better to put both the css in one file and not to change the css later on.
Css Gets loaded first . and only then your javascript gets executed. So first your default css will be loadeed. then you would change the href tag (using other answer) then next file would be loaded. making an extra call to server. The better idea it to have both(landscape & potrait) css defined in one file.
IMHO 80% of the css for both landscape & potrait would be the same the rest 20% can be configured using the naive css fomr the first link.
Imagine a webpage which enables users to show an hidden element, using javascript to modify css a CSS style at runtime.
After his decision (which includes the modification of the stlyesheet) the user uses the printing functionality of his browser.
It seems that Internet Explorer does not respect the changes made in the stylesheet before during printing if the original css definition is located in an external file.
In other Browsers everything works as expected.
Please have a look at the example below, which changes a style class from its initial definition display:none to display:inline at runtime hence the element will be displayed.
But when printing this page, the element remains hidden in internet explorer (tested with IE 6,7,8).
Do you have a solution or workaround?
Minimalistic example (html file):
<html><head>
<LINK rel="stylesheet" type="text/css" href="minimal.css">
</head><body onload="displayCol();">
<script>
function displayCol()
{
var myrules;
if( document.styleSheets[0].cssRules ) {
myrules = document.styleSheets[0].cssRules;
} else {
if ( document.styleSheets[0].rules ) {
myrules = document.styleSheets[0].rules;
}
}
myrules[0].style.display = "inline";
}
</script>
<div class="col0" id="test">This is hidden by default.</div></body></html>
minimal.css
.col0 {
display:none;
}
UPDATE:
Please note that the decision if the object should be displayed or not is made by the user - it's not known at runtime!
Have you considered using the media=print way of getting the browser to use a stylesheet specifically for printing?
<link rel="stylesheet" href="print.css" media="print" />
If the css changes you are making are always the same, i.e. you can technically store them on a separate css file, then you can use this.
For non-static CSS, in IE (not sure about other browsers/later versions of IE), you could consider using the onbeforeprint event.
See here: http://www.javascriptkit.com/javatutors/ie5print.shtml
Instead of using javascript to change the stylesheet rules, use scripting to apply and remove classes to the elements that need to be displayed. Remember that an element can have more than one class applied to it.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Demo</title>
<style type="text/css">
.col0 {display:none;}
div.showCol {display: inline;}
</style>
<script type="text/javascript">
function displayCol() {
document.getElementById("test").className += " showCol";
}
</script>
</head>
<body onload="displayCol();">
<div class="col0" id="test">This is hidden by default.</div>
</body>
</html>
This answer to another question does a great job laying out different ways to do this with scripting: Change an element's class with JavaScript
You could try using a specific style sheet for printing, for example:
<link rel="stylesheet" type="text/css" href="print.css" media="print" />
EDIT - too slow :)
Javascript is not being evaluated when printing. It will look just like when Javascript is turned off. You need an extra media=print stylesheet and make any necessary changes there.
If that is not an option, you could create a link that will generate a static page that will look like it's supposed to for that particular user.
Based off your example scenario - in your style sheet add:
.col0 {
display: none;
}
body.showColumn .col0 {
display: inline;
}
Then simply toggle the .showColumn class on your body, and the column's visibility will be toggled accordingly.