admin管理员组

文章数量:1133769

I'm trying to make a live, in-page css editor with a preview function that would reload the stylesheet and apply it without needing to reload the page. What would be the best way to go about this?

I'm trying to make a live, in-page css editor with a preview function that would reload the stylesheet and apply it without needing to reload the page. What would be the best way to go about this?

Share Improve this question asked Jan 7, 2010 at 23:31 Stephen BelangerStephen Belanger 6,35112 gold badges47 silver badges49 bronze badges 3
  • 1 2014 and this question is on the home page... – Kroltan Commented Nov 4, 2014 at 11:32
  • 1 2019, almost 2020, and this question still popping on the home page… – ZER0 Commented Dec 4, 2019 at 12:41
  • 2024 reporting in ∠(^ー^) – diopside Commented Jul 23, 2023 at 23:27
Add a comment  | 

14 Answers 14

Reset to default 115

Possibly not applicable for your situation, but here's the jQuery function I use for reloading external stylesheets:

/**
 * 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);
    });
}

On the "edit" page, instead of including your CSS in the normal way (with a <link> tag), write it all to a <style> tag. Editing the innerHTML property of that will automatically update the page, even without a round-trip to the server.

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

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

The Javascript, using jQuery:

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

And that should be it!

If you wanted to be really fancy, attach the function to the keydown on the textarea, though you could get some unwanted side-effects (the page would be changing constantly as you type)

Edit: tested and works (in Firefox 3.5, at least, though should be fine with other browsers). See demo here: http://jsbin.com/owapi

There is absolutely no need to use jQuery for this. The following JavaScript function will reload all your CSS files:

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

A shorter version in Vanilla JS and in one line:

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

It loops trough all stylesheet links and appends (or updates) a timestamp to the URL.

Check out Andrew Davey's snazzy Vogue project - http://aboutcode.net/vogue/

One more jQuery solution

For a single stylesheet with id "css" try this:

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

Wrap it in a function that has global scrope and you can use it from the Developer Console in Chrome or Firebug in Firefox:

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

Based on previous solutions, I have created bookmark with JavaScript code:

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

Image from Firefox:

What does it do?

It reloads CSS by adding query string params (as solutions above):

  • Content/Site.css becomes Content/Site.css?trvhpqi=1409572193189 (adds date)
  • Content/Site.css?trvhpqi=1409572193189 becomes Content/Site.css?trvhpqi=1409572193200 (date changes)
  • http://fonts.googleapis.com/css?family=Open+Sans:400,300,300italic,400italic,800italic,800,700italic,700,600italic,600&subset=latin,latin-ext becomes http://fonts.googleapis.com/css?family=Open+Sans:400,300,300italic,400italic,800italic,800,700italic,700,600italic,600&subset=latin,latin-ext&trvhpqi=1409572193189 (adds new query string param with date)

Since this question was shown in the stackoverflow in 2019, I'd like to add my contribution using a more modern JavaScript.

Specifically, for CSS Stylesheet that are not inline – since that is already covered from the original question, somehow.

First of all, notice that we still don't have Constructable Stylesheet Objects. However, we hope to have them landed soon.

In the meantime, assuming the following HTML content:

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

We could have, in 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);
}

i now have this:

    function swapStyleSheet() {
        var old = $('#pagestyle').attr('href');
        var newCss = $('#changeCss').attr('href');
        var sheet = newCss +Math.random(0,10);
        $('#pagestyle').attr('href',sheet);
        $('#profile').attr('href',old);
        }
    $("#changeCss").on("click", function(event) { 
        swapStyleSheet();
    } );

make any element in your page with id changeCss with a href attribute with the new css url in it. and a link element with the starting css:

<link id="pagestyle" rel="stylesheet" type="text/css" href="css1.css?t=" />

<img src="click.jpg" id="changeCss" href="css2.css?t=">

Another answer: There's a bookmarklet called ReCSS. I haven't used it extensively, but seems to work.

There's a bookmarklet on that page to drag and drop onto your address bar (Can't seem to make one here). In case that's broke, here's the code:

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

In a simple manner you can use rel="preload" instead of rel="stylesheet" .

<link rel="preload" href="path/to/mystylesheet.css" as="style" onload="this.rel='stylesheet'">

Based on https://stackoverflow.com/a/59176853/3917091 on this page

function refreshStylesheets() {
  // In my case, I'm getting all urls on my site (mysite.dev).
  (document.querySelectorAll('link[rel="stylesheet"][href*="mysite.dev\/"],link[rel="stylesheet"][data-href*="mysite.dev\/"]') || []).forEach(async link => {
    // Reload the file, by data-href first if it's available, otherwise use href
    const reload = await fetch(link.dataset.href || link.href, { cache: "reload" }),
      // Generate url
      url = URL.createObjectURL(await reload.blob());

    // preserve real url
    if (!link.dataset.href) link.dataset.href = link.href;
    link.href = url.toString();
  });
}

The advantage this has, over appending to the url, is that this actually removes it from the browser cache. Using other scripts works great, but when you refresh the page, it reverts to what it had cached. Minor annoyance. However, this does not revert upon refresh.

It's a nice way to quickly change css for testing without ctrl F5 refresh all of the time, and then you roll out the change by server-side updating the filename or the query string on the style sheet as normal.

The data-href 'preserving' is important, or the permanency of refreshing on your cache only works once per page-view.


The same sort of script can be written for script[src] but I would not advise that, because you may end up with all kinds of bugs with certain things being done twice, like event listeners.

Yes, reload the css tag. And remember to make the new url unique (usually by appending a random query parameter). I have code to do this but not with me right now. Will edit later...

edit: too late... harto and nickf beat me to it ;-)

simple if u are using php Just append the current time at the end of the css like

<link href="css/name.css?<?php echo 
time(); ?>" rel="stylesheet">

So now everytime u reload whatever it is , the time changes and browser thinks its a different file since the last bit keeps changing.... U can do this for any file u force the browser to always refresh using whatever scripting language u want

本文标签: javascriptIs there an easy way to reload css without reloading the pageStack Overflow