Czy istnieje łatwy sposób na ponowne załadowanie css bez ponownego ładowania strony?

90

Próbuję stworzyć na żywo edytor css na stronie z funkcją podglądu, która przeładuje arkusz stylów i zastosuje go bez konieczności ponownego ładowania strony. Jaki byłby najlepszy sposób rozwiązania tego problemu?

Stephen Belanger
źródło
1
2014 i to pytanie jest na stronie głównej ...
Kroltan
1
2019, prawie 2020, a to pytanie wciąż pojawia się na stronie głównej…
ZER0

Odpowiedzi:

51

Na stronie „edytuj”, zamiast włączać CSS w normalny sposób (za pomocą <link>tagu), zapisz to wszystko w <style>tagu. Edycja tej innerHTMLwłaściwości spowoduje automatyczną aktualizację strony, nawet bez powrotu do serwera.

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

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

JavaScript, używając jQuery:

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

I to powinno być to!

Jeśli chcesz być naprawdę fantazyjny, dołącz funkcję do keydown w obszarze tekstowym, chociaż możesz uzyskać niepożądane efekty uboczne (strona będzie się ciągle zmieniać podczas pisania)

Edycja : przetestowana i działa (przynajmniej w Firefoksie 3.5, ale powinno działać dobrze z innymi przeglądarkami). Zobacz demo tutaj: http://jsbin.com/owapi

nickf
źródło
3
IE włącza się innerHTMLdla <style>elementów (i <script>).
JPot
3
co jeśli jest href'ed?
allenhwkim
Przy okazji, możesz dołączyć funkcję do keydown w obszarze tekstowym, ale dusić ją za pomocą lo-dash (na przykład).
Camilo Martin
109

Prawdopodobnie nie ma zastosowania w twojej sytuacji, ale oto funkcja jQuery, której używam do ponownego ładowania zewnętrznych arkuszy stylów:

/**
 * 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);
    });
}
Harto
źródło
3
Możesz zrobić z tego zakładkę za pomocą ted.mielczarek.org/code/mozilla/bookmarklet.html
Luke Stanley
36
Ten non-jquery one-liner działa dla mnie w 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
Nie jestem pewien, czy to dlatego, że właśnie otwieram stronę na chrome z dysku, ale to nie działa dla mnie.
Joao Carlos
14

Nie ma do tego absolutnie potrzeby używania jQuery. Następująca funkcja JavaScript przeładuje wszystkie twoje pliki CSS:

function reloadCss()
{
    var links = document.getElementsByTagName("link");
    for (var cl in links)
    {
        var link = links[cl];
        if (link.rel === "stylesheet")
            link.href += "";
    }
}
Dan Bray
źródło
1
Używam tego w konsoli, więc nie muszę dodawać nic więcej w moim kodzie
loco.loop
@Bram nawias klamrowy jest opcjonalny. Kod działa dobrze.
Dan Bray
1
Świetna odpowiedź, ponieważ nie opiera się na jQuery! :)
Gustavo Straube
9

Sprawdź odlotowy projekt Andrew Davey'a Vogue - http://aboutcode.net/vogue/

mcintyre321
źródło
To jest dokładnie to, czego szukałem. Ponownie ładuje CSS natychmiast po zmianie arkusza stylów, bez konieczności ręcznego odświeżania strony.
Wielkie
Czy Vogue można uruchomić lokalnie na wampie?
chrisdillon,
Próbowałem przeładować skrypt, jak Vogue. Ale w Chrome jest problem, ponieważ najstarsze pliki arkuszy stylów pozostają w przeglądarce i działają. Na przykład w jednym elemencie zmieniam tło z czerwonego na białe i musiałem wyłączyć ostatni kolor czerwony.
Peter,
7

Krótsza wersja w Vanilla JS i w jednej linii:

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

Lub rozszerzony:

for (var link of document.querySelectorAll("link[rel=stylesheet]")) {
  link.href = link.href.replace(/\?.*|$/, "?" + Date.now())
}
flori
źródło
6

Jeszcze jedno rozwiązanie jQuery

W przypadku pojedynczego arkusza stylów o identyfikatorze „css” spróbuj tego:

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

Owiń go w funkcję, która ma zasięg globalny i możesz jej używać z Konsoli programisty w przeglądarce Chrome lub Firebug w przeglądarce Firefox:

var reloadCSS = function() {
  $('#css').replaceWith('<link id="css" rel="stylesheet" href="css/main.css?t=' + Date.now() + '"></link>');
};
mattdlockyer
źródło
1
cześć, mam to, które trochę jak działa tylko te :( chociaż mam czas dodany, aby uczynić go wyjątkowym (to jest w Firefoksie): <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
3

W oparciu o poprzednie rozwiązania stworzyłem zakładkę z kodem 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);

Obraz z przeglądarki Firefox:

wprowadź opis obrazu tutaj

Co to robi?

Przeładowuje CSS, dodając parametry ciągu zapytania (jak rozwiązania powyżej):

LukLed
źródło
0

Tak, załaduj ponownie tag css. I pamiętaj, aby nowy adres URL był unikalny (zwykle przez dołączenie losowego parametru zapytania). Mam kod, aby to zrobić, ale teraz nie mam go ze sobą. Będzie edytować później ...

edycja: za późno ... harto i nickf mnie do tego pobili ;-)

slebetman
źródło
0

mam teraz to:

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

uczyń dowolny element na swojej stronie z id changeCss z atrybutem href z nowym url css w nim. oraz element link z początkowym css:

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

<img src="click.jpg" id="changeCss" href="css2.css?t=">
tibi
źródło
0

Inna odpowiedź: istnieje bookmarklet o nazwie ReCSS . Nie używałem go intensywnie, ale wydaje się, że działa.

Na tej stronie znajduje się bookmarklet, który można przeciągnąć i upuścić na pasek adresu (nie wydaje się, aby go tutaj utworzyć). Na wypadek, gdyby coś się zepsuło, oto kod:

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)();
Christopher Schneider
źródło
0

proste, jeśli używasz php. Po prostu dodaj aktualny czas na końcu css

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

Więc teraz za każdym razem, gdy przeładowujesz cokolwiek to jest, czas się zmienia i przeglądarka uważa, że ​​to inny plik, ponieważ ostatni bit ciągle się zmienia .... Możesz to zrobić dla dowolnego pliku, zmuszając przeglądarkę do zawsze odświeżania przy użyciu dowolnego języka skryptowego

asiimwedismas
źródło
0

W prosty sposób możesz użyć rel = "preload" zamiast rel = "stylesheet" .

<link rel="preload" href="path/to/mystylesheet.css" as="style" onload="this.rel='stylesheet'">
Gagan
źródło
Powiedziałeś użyć, rel="reload"ale przykład mówi rel="preload".
haykam
Dzięki @haykam za poprawienie mnie, zaktualizowałem go.
Gagan
0

Ponieważ to pytanie zostało pokazane w stackoverflow w 2019 roku, chciałbym dodać swój wkład za pomocą bardziej nowoczesnego JavaScript.

W szczególności dla arkuszy stylów CSS, które nie są wbudowane - ponieważ jest to już w jakiś sposób uwzględnione w pierwotnym pytaniu.

Przede wszystkim zauważ, że wciąż nie mamy obiektów konstruowalnych arkuszy stylów. Mamy jednak nadzieję, że wkrótce wylądują.

W międzyczasie zakładając następującą zawartość 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>

Mogliśmy w 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);
}
ZER0
źródło