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

Posted

技术标签:

【中文标题】即时替换 css 文件(并将新样式应用于页面)【英文标题】:Replacing css file on the fly (and apply the new style to the page) 【发布时间】:2013-11-19 14:33:07 【问题描述】:

我有一个页面在标题中有<link>,它加载了名为light.css 的CSS。我还有一个名为dark.css 的文件。我想要一个按钮来一起交换页面的样式(css文件中使用了40个选择器,有些在两个文件中不匹配)。

如何使用 JS 删除对 light.css 的引用并删除所有已应用的样式,然后加载 dark.css 并从中应用所有样式?我不能简单地重置所有元素,因为有些样式是通过不同的 css 文件应用的,有些是由 JS 动态生成的。有没有一种简单而有效的方法可以在不重新加载页面的情况下做到这一点? Vanilla JS 更可取,不过我还是会使用 jQuery 进行后期处理,所以 jQ 也可以。

【问题讨论】:

我选择了 Mattew 的答案,因为使用该方法,我可以轻松扩展 for() 循环以处理多个文件并在其他脚本/样式表中交换 lightdark 【参考方案1】:

您可以在文档中包含所有样式表,然后根据需要激活/停用它们。

在我阅读规范时,您应该可以activate an alternate stylesheet by changing its disabled property from true to false,但似乎只有 Firefox 可以正确执行此操作。

所以我认为你有几个选择:

切换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>

设置和切换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>

切换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>

您可以使用getElementById、querySelector 等选择样式表节点。

(避免使用非标准的&lt;link disabled&gt;。设置htmlLinkElement#disabled 也可以。)

【讨论】:

@sam 现在很抱歉,我不能接受别人的问题的答案 :)... 只是,对页面的性能有影响吗?在该属性设置为 false 之前,浏览器是否会忽略禁用的链接? 不幸的是,将disabled 设置为属性是不鼓励的:“使用 disabled 作为 HTML 属性是非标准的,仅由某些浏览器使用 (W3 #27677)。不要使用它。” -> developer.mozilla.org/en-US/docs/Web/HTML/Element/… @dzenesiz 浏览器可以跳过下载备用样式表,直到需要它,但我不知道它们的实际行为。 只是为了澄清@Daniel所说的,HTML属性是非标准的,但根据Mozilla,DOM属性是。因此,以上述方式使用 javascript 切换它实际上是符合标准的。除非我遗漏了什么,否则这应该是公认的答案。 CSS Object Model 说明了 disabled 标志:“注意:即使未设置,也不一定意味着 CSS 样式表实际上用于渲染”。这可能是答案适用于 Firefox,但不适用于 Webkit 和 Blink (Epyphany & Chromium) 的原因。【参考方案2】:

您可以创建一个新链接,并将旧链接替换为新链接。如果你把它放在一个函数中,你可以在任何需要的地方重复使用它。

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

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>

为简单起见,我使用了内联 javascript。在生产环境中,您可能希望使用不显眼的事件侦听器。

【讨论】:

我认为简单地更新 href 属性也可以正常工作:oldlink.href = cssFile; // done 是的。这将替换 DOM 中的整个链接节点。 如果你想拉一个实时重载类型的东西,这可能是要走的路,因为 href 可能是相同的,如果 href 没有,浏览器实际上可能不会做任何事情t 实际上改变了。 在切换css文件时,下载文件和渲染样式的差距导致html没有样式。我想,应该有一个默认样式表,它总是在那里添加基本样式。移动浏览器只需花费大量时间来替换 css 样式表。此外,鉴于 jekyll 生成的静态网站,不同页面的链接索引可能会有所不同 您可以使用绝对 URL 来绕过位于不同文件夹或诸如此类的页面。我喜欢使用默认样式表来防止 FOUC 显示的想法。不错的提示!【参考方案3】:

如果您在链接元素上设置了 ID

<link rel="stylesheet" id="stylesheet" href="stylesheet1.css"/>

您可以使用 Javascript 定位它

document.getElementsByTagName('head')[0].getElementById('stylesheet').href='stylesheet2.css';

或者只是..

document.getElementById('stylesheet').href='stylesheet2.css';

这里有一个更详尽的例子:

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

【讨论】:

【参考方案4】:

这个问题已经很老了,但我会建议一种这里没有提到的方法,在这种方法中,您将在 HTML 中包含两个 CSS 文件,但 CSS 会像

light.css

/*** light.css ***/

p.main
   color: #222;


/*** other light CSS ***/

dark.css 会像

/*** dark.css ***/

.dark_layout p.main
   color: #fff;
   background-color: #222;


/*** other dark CSS ***/

dark.css 中的每个选择器基本上都是.dark_layout 的子代

如果有人选择改变网站的主题,那么你需要做的就是改变body元素的类。

$("#changetheme").click(function()
   $("body").toggleClass("dark_layout");
);

现在,一旦用户单击#changetheme,您的所有元素都将具有深色 css。如果您使用任何类型的 CSS 预处理器,这很容易做到。

您还可以为背景和颜色添加 CSS 动画,使过渡非常平滑。

【讨论】:

【参考方案5】:

使用 jquery 你绝对可以交换 css 文件。在单击按钮时执行此操作。

var cssLink = $('link[href*="light.css"]');
cssLink.replaceWith('<link href="dark.css" type="text/css" rel="stylesheet">');

或者sam's answer,也可以。这是jquery语法。

$('link[href*="light.css"]').prop('disabled', true);
$('link[href*="dark.css"]').prop('disabled', false);

【讨论】:

它可能会更好,但我喜欢你如何清晰地定义 sam 的 jQ 部分并帮助我清楚地理解一切。【参考方案6】:

使用 jquery .attr() 你可以设置 href 你的 link 标签 .i.e

示例代码

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

【讨论】:

【参考方案7】:

也许我想得太复杂了,但由于接受的答案对我不起作用,我想我也会分享我的解决方案。

故事: 我想做的是在头部包含我页面的不同“皮肤”作为附加样式表,这些样式表添加到“主”样式中,并通过按下页面上的按钮来切换它们(没有浏览器设置或其他东西)。

问题: 我认为@sam 的解决方案非常优雅,但对我来说根本不起作用。至少部分问题是我正在使用一个主 CSS 文件,而只是将其他 CSS 文件添加到顶部作为“皮肤”,因此我必须使用 missing 'title' 属性对文件进行分组。

这是我想出的。 首先使用“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=''>

请注意,我为主 CSS 文件指定了 title='main',而所有其他文件都有 class='style-skin' 且没有标题。 要切换皮肤,我正在使用 jQuery。我让纯粹主义者去寻找优雅的 VanillaJS 版本:

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

它的作用是遍历所有可用的皮肤,获取(即将)激活的皮肤,将标题设置为“主”并激活它。所有其他皮肤都被禁用并且标题被删除。

【讨论】:

【参考方案8】:

只需将Link href 属性更新到新的 css 文件即可。

function setStyleSheet(fileName)
       document.getElementById("WhatEverYouAssignIdToStyleSheet").setAttribute('href', fileName);
    

【讨论】:

以上是关于即时替换 css 文件(并将新样式应用于页面)的主要内容,如果未能解决你的问题,请参考以下文章

仅将 CSS 样式表应用于单个 UserControl

在页面加载时选择默认 css

为啥在html中调用外部css样式表没有效果

next.js 我不知道如何将全局 .container css 样式应用到其他页面

如何修复html和css文件之间的运行顺序?

将样式应用于 Angular 2 中动态创建的元素