有没有一种简单的方法,在不重新加载页面的情况下重新加载css?

105

我正在尝试制作一个实时的、在页面内的CSS编辑器,并具有预览功能,可以重新加载样式表并应用它而无需重新加载整个页面。那么,最好的方法是什么?


1
2014年,这个问题在主页上... - Kroltan
1
2019年,即将到来的2020年,这个问题仍然出现在主页上... - ZER0
2024年报道,∠(^ー^) - diopside
14个回答

115

也许不适用于您的情况,但这是我用于重新加载外部样式表的 jQuery 函数:

/**
 * Forces a reload of all stylesheets by appending a unique query string
 * to each stylesheet URL.
 */
function reloadStylesheets() {
    var queryString = '?reload=' + new Date().getTime();
    $('link[rel="stylesheet"]').each(function () {
        this.href = this.href.replace(/\?.*|$/, queryString);
    });
}

5
使用http://ted.mielczarek.org/code/mozilla/bookmarklet.html,您可以将其设置为书签。 - Luke Stanley
41
这个非jQuery的一行代码在我的Chrome浏览器中有效:var links = document.getElementsByTagName("link"); for (var i = 0; i < links.length;i++) { var link = links[i]; if (link.rel === "stylesheet") {link.href += "?"; }} - Claude
我不确定是因为我只是从磁盘上在Chrome中打开页面,但这对我来说不起作用。 - Joao Carlos

53

在“编辑”页面上,不要使用普通的<link>标签来包含你的CSS样式,而是将所有内容都写到<style>标签中。通过编辑该标签的innerHTML属性,即可自动更新页面,甚至无需返回服务器进行往返请求。

<style type="text/css" id="styles">
    p {
        color: #f0f;
    }
</style>

<textarea id="editor"></textarea>
<button id="preview">Preview</button>

使用jQuery编写的Javascript代码:

jQuery(function($) {
    var $ed = $('#editor')
      , $style = $('#styles')
      , $button = $('#preview')
    ;
    $ed.val($style.html());
    $button.click(function() {
        $style.html($ed.val());
        return false;
    });
});

就这些了!

如果你想要更高级一点,可以将函数附加到文本区域的keydown事件上,但是可能会出现一些意外的副作用(在您键入时页面会不断变化)。

编辑:已测试并可行(至少在Firefox 3.5中可以,其他浏览器也应该没问题)。在这里查看演示:http://jsbin.com/owapi


3
IEжөҸи§ҲеҷЁж— жі•еӨ„зҗҶ<style>пјҲе’Ң<script>пјүе…ғзҙ зҡ„innerHTMLгҖӮ - JPot
4
如果它被 href 链接了会怎样? - allenhwkim
顺便说一句,你可以将一个函数附加到textarea的keydown事件上,但(例如)要用lo-dash来进行节流。 - Camilo Martin

24

毫无必要使用jQuery来实现这个功能。以下JavaScript函数将重新加载您的所有CSS文件:

function reloadCss()
{
    var links = document.getElementsByTagName("link");
    for (var cl in links)
    {
        var link = links[cl];
        if (link.rel === "stylesheet")
            link.href += "";
    }
}

1
我在控制台中使用它,因此我不需要在代码中添加任何其他内容。 - loco.loop
@Bram,花括号是可选的。代码运行良好。 - Dan Bray
2
非常好的答案,因为它不依赖于jQuery! :) - Gustavo Straube
1
只是想知道 === 的目的 - 什么情况下 rel 属性值可以是 "stylesheet",但它的类型不是字符串? - Geat

11

用 Vanilla JS 缩短并压缩成一行:

document.querySelectorAll("link[rel=stylesheet]").forEach(link => link.href = link.href.replace(/\?.*|$/, "?" + Date.now()))

它循环遍历所有样式表链接,并向URL附加(或更新)时间戳。


9

这正是我一直在寻找的。它会在样式表更改后立即重新加载CSS,无需手动刷新页面。非常感谢您的分享 :) - Devner
Vogue可以在wamp上本地运行吗? - chrisdillon
我尝试重新加载脚本,就像时尚杂志一样。但在Chrome中存在问题,因为最旧的样式表文件仍然留在浏览器中并且正在工作。例如,在一个元素中,我将背景从红色更改为白色,我必须禁用上一个颜色红色。 - Peter

6

再来一个jQuery解决方案

针对具有id“css”的单一样式表,请尝试以下方法:

$('#css').replaceWith('<link id="css" rel="stylesheet" href="css/main.css?t=' + Date.now() + '"></link>');

将其包装在具有全局范围的函数中,您可以在Chrome的开发者控制台或Firefox的Firebug中使用它:

var reloadCSS = function() {
  $('#css').replaceWith('<link id="css" rel="stylesheet" href="css/main.css?t=' + Date.now() + '"></link>');
};

1
嗨,我有这个问题,它只能工作一次 :( 即使我添加了时间来使它唯一(这是在Firefox上):<code> function swapStyleSheet(sheet) { var sheet = sheet+'?t=' + Date.now(); $('#pagestyle').replaceWith('<link id="css" rel="stylesheet" href="'+sheet+'"></link>'); } $("#stylesheet1").on("click", function(event) { swapStyleSheet("<c:url value='site.css'/>"); } ); $("#stylesheet2").on("click", function(event) { swapStyleSheet("<c:url value='site2.css'/>"); } ); </code> - tibi

4

基于之前的解决方案,我已经用JavaScript代码创建了书签:

javascript: { var toAppend = "trvhpqi=" + (new Date()).getTime(); var links = document.getElementsByTagName("link"); for (var i = 0; i < links.length;i++) { var link = links[i]; if (link.rel === "stylesheet") { if (link.href.indexOf("?") === -1) { link.href += "?" + toAppend; } else { if (link.href.indexOf("trvhpqi") === -1) { link.href += "&" + toAppend; } else { link.href = link.href.replace(/trvhpqi=\d{13}/, toAppend)} }; } } }; void(0);

来自Firefox的图片:

在此输入图片描述

它的作用是什么?

通过添加查询字符串参数(如上述解决方案),重新加载CSS:


2

自2019年这个问题在stackoverflow上出现以来,我想使用更现代的JavaScript来做出贡献。

具体来说,针对不是内联的CSS样式表——因为原始问题已经涵盖了这一点,某种程度上。

首先,请注意我们仍然没有可构建的StyleSheet对象。 但是,我们希望很快就能拥有它们。

与此同时,假设以下HTML内容:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link id="theme" rel="stylesheet" type="text/css" href="./index.css" />
    <script src="./index.js"></script>
  </head>
  <body>
    <p>Hello World</p>
    <button onclick="reload('theme')">Reload</button>
  </body>
</html>


我们可以在 index.js 文件中实现以下功能:
// Utility function to generate a promise that is 
// resolved when the `target` resource is loaded,
// and rejected if it fails to load.
//
const load = target =>
  new Promise((rs, rj) => {
    target.addEventListener("load", rs, { once: true });
    target.addEventListener(
      "error",
      rj.bind(null, `Can't load ${target.href}`),
      { once: true }
    );
  });


// Here the reload function called by the button.
// It takes an `id` of the stylesheet that needs to be reloaded
async function reload(id) {
  const link = document.getElementById(id);

  if (!link || !link.href) {
    throw new Error(`Can't reload '${id}', element or href attribute missing.`);
  }

  // Here the relevant part.
  // We're fetching the stylesheet from the server, specifying `reload`
  // as cache setting, since that is our intention.
  // With `reload`, the browser fetches the resource *without* first looking
  // in the cache, but then will update the cache with the downloaded resource.
  // So any other pages that request the same file and hit the cache first,
  // will use the updated version instead of the old ones.
  let response = await fetch(link.href, { cache: "reload" });

  // Once we fetched the stylesheet and replaced in the cache,
  // We want also to replace it in the document, so we're
  // creating a URL from the response's blob:
  let url = await URL.createObjectURL(await response.blob());

  // Then, we create another `<link>` element to display the updated style,
  // linked to the original one; but only if we didn't create previously:
  let updated = document.querySelector(`[data-link-id=${id}]`);

  if (!updated) {
    updated = document.createElement("link");
    updated.rel = "stylesheet";
    updated.type = "text/css";
    updated.dataset.linkId = id;
    link.parentElement.insertBefore(updated, link);

    // At this point we disable the original stylesheet,
    // so it won't be applied to the document anymore.
    link.disabled = true;
  }

  // We set the new <link> href...
  updated.href = url;

  // ...Waiting that is loaded...
  await load(updated);

  // ...and finally tell to the browser that we don't need
  // the blob's URL anymore, so it can be released.
  URL.revokeObjectURL(url);
}

这种方法的优点是它可以将URL从浏览器缓存中清除,而不是像追加URL那样只添加。使用其他脚本也很好用,但当您刷新页面时,它会恢复到之前缓存的状态,这可能会带来一些小烦恼。但是,使用这种方法后,即使您刷新页面,也不会回到之前的状态。我做了一些小修改:https://dev59.com/RnI-5IYBdhLWcg3wEELu#75495808 - Regular Jo
这种方法的优势在于,与将其附加到URL相比,它实际上会从浏览器缓存中删除。使用其他脚本效果很好,但当您刷新页面时,它会恢复到之前缓存的内容。这可能会带来一些小的困扰。然而,使用这种方法刷新页面后不会恢复。我做了一些小的修改:https://stackoverflow.com/a/75495808/3917091 - undefined

0
以简单的方式,您可以使用rel="preload"代替rel="stylesheet"
<link rel="preload" href="path/to/mystylesheet.css" as="style" onload="this.rel='stylesheet'">

你说要使用 rel="reload",但示例中却是 rel="preload" - bb216b3acfd8f72cbc8f899d4d6963
感谢 @haykam 的纠正,我已经更新了它。 - Gagan

0
另一个答案: 有一个名为ReCSS的书签小工具。我没有广泛使用它,但似乎可以工作。
该页面上有一个书签小工具,可拖放到您的地址栏上(似乎无法在此处制作)。如果出现问题,请使用以下代码:
javascript:void(function()%7Bvar%20i,a,s;a=document.getElementsByTagName('link');for(i=0;i%3Ca.length;i++)%7Bs=a[i];if(s.rel.toLowerCase().indexOf('stylesheet')%3E=0&&s.href)%20%7Bvar%20h=s.href.replace(/(&%7C%5C?)forceReload=%5Cd%20/,'');s.href=h%20(h.indexOf('?')%3E=0?'&':'?')%20'forceReload='%20(new%20Date().valueOf())%7D%7D%7D)();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接