动态替换 css 文件(并将新样式应用于页面)

我有一个页面,其中有 <link>在头,加载名为 light.css的 CSS。我还有一个名为 dark.css的文件。我希望一个按钮交换页面的样式所有在一起(有40个选择器使用的 css 文件和一些不匹配的两个文件)。

我怎样才能删除引用 light.css与 JS 和删除所有的样式,应用,然后加载 dark.css和应用所有的样式从那?我不能简单地重置所有元素,因为有些样式是通过不同的 css 文件应用的,有些是由 JS 动态生成的。有没有一种简单而有效的方法可以在不重新加载页面的情况下做到这一点?香草 JS 更可取,但是我将使用 jQuery 进行后续处理,所以 jQ 也不错。

118635 次浏览

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>
<a href="#" onclick="changeCSS('positive.css', 0);">STYLE 1</a>
<a href="#" onclick="changeCSS('negative.css', 0);">STYLE 2</a>
</body>
</html>

For simplicity, I used inline javascript. In production you would want to use unobtrusive event listeners.

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);

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.)

Using jquery .attr() you can set href of your link tag .i.e

Sample code

$("#yourButtonId").on('click',function(){
$("link").attr(href,yourCssUrl);
});

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>

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.

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.

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.