¿Existe una forma fácil de recargar CSS sin recargar la página?

90

Estoy tratando de crear un editor CSS en vivo en la página con una función de vista previa que recargaría la hoja de estilo y la aplicaría sin necesidad de recargar la página. ¿Cuál sería la mejor manera de hacerlo?

Stephen Belanger
fuente
1
2014 y esta pregunta está en la página de inicio ...
Kroltan
1
2019, casi 2020, y esta pregunta sigue apareciendo en la página de inicio…
ZER0

Respuestas:

51

En la página "editar", en lugar de incluir su CSS de la forma habitual (con una <link>etiqueta), escríbalo todo en una <style>etiqueta. Editar la innerHTMLpropiedad de eso actualizará automáticamente la página, incluso sin un viaje de ida y vuelta al servidor.

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

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

El Javascript, usando jQuery:

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

¡Y eso debería ser todo!

Si desea ser realmente elegante, adjunte la función al teclado en el área de texto, aunque podría obtener algunos efectos secundarios no deseados (la página cambiaría constantemente a medida que escribe)

Editar : probado y funciona (en Firefox 3.5, al menos, aunque debería funcionar con otros navegadores). Vea la demostración aquí: http://jsbin.com/owapi

nickf
fuente
3
IE barfs en innerHTMLbusca de <style>elementos (y <script>).
JPot
3
¿y si está href'ed?
allenhwkim
Por cierto, puede adjuntar una función a la tecla hacia abajo en el área de texto pero acelerarla con lo-dash (por ejemplo).
Camilo Martin
109

Posiblemente no sea aplicable para su situación, pero aquí está la función jQuery que uso para recargar hojas de estilo externas:

/**
 * 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
fuente
3
Puede convertirlo en un marcador usando ted.mielczarek.org/code/mozilla/bookmarklet.html
Luke Stanley
36
Esta frase única que no es de jquery funciona para mí en 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
No estoy seguro de si es porque solo estoy abriendo la página en Chrome desde el disco, pero esto no me funciona.
Joao Carlos
14

No hay absolutamente ninguna necesidad de usar jQuery para esto. La siguiente función de JavaScript recargará todos sus archivos 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
fuente
1
Estoy usando esto en la consola, así que no necesito agregar nada más en mi código
loco.loop
@Bram la llave es opcional. El código funciona bien.
Dan Bray
1
¡Gran respuesta ya que no depende de jQuery! :)
Gustavo Straube
9

Echa un vistazo al elegante proyecto Vogue de Andrew Davey: http://aboutcode.net/vogue/

mcintyre321
fuente
Esto es exactamente lo que he estado buscando. Vuelve a cargar el CSS tan pronto como se cambia la hoja de estilo, sin la necesidad de actualizar manualmente la página. Muchas gracias por compartir :)
Devner
¿Se puede ejecutar Vogue localmente en wamp?
chrisdillon
Intenté volver a cargar el script, como Vogue. Pero en Chrome es un problema, porque los archivos de hoja de estilo olest permanecen en el navegador y funcionan. Por ejemplo, en un elemento cambio el fondo de rojo a blanco, y debo desactivar el último color rojo.
Peter
7

Una versión más corta en Vanilla JS y en una línea:

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

O expandido:

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

Una solución más de jQuery

Para una sola hoja de estilo con id "css" intente esto:

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

Envuélvalo en una función que tenga un scrope global y puede usarlo desde la Consola de desarrollador en Chrome o Firebug en Firefox:

var reloadCSS = function() {
  $('#css').replaceWith('<link id="css" rel="stylesheet" href="css/main.css?t=' + Date.now() + '"></link>');
};
mattdlockyer
fuente
1
hola, tengo esto, que de alguna manera solo funciona :( aunque tengo el tiempo agregado para hacerlo único (esto es en firefox): <code> función 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

Basado en soluciones anteriores, he creado un marcador con código 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);

Imagen de Firefox:

ingrese la descripción de la imagen aquí

¿Qué hace?

Vuelve a cargar CSS agregando parámetros de cadena de consulta (como las soluciones anteriores):

LukLed
fuente
0

Sí, vuelva a cargar la etiqueta css. Y recuerde hacer que la nueva URL sea única (generalmente agregando un parámetro de consulta aleatorio). Tengo un código para hacer esto, pero no conmigo en este momento. Editaré más tarde ...

editar: demasiado tarde ... harto y nickf me ganaron ;-)

slebetman
fuente
0

ahora tengo esto:

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

cree cualquier elemento en su página con id changeCss con un atributo href con la nueva URL css en él. y un elemento de enlace con el CSS inicial:

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

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

Otra respuesta: hay un bookmarklet llamado ReCSS . No lo he usado mucho, pero parece funcionar.

Hay un marcador en esa página para arrastrar y soltar en la barra de direcciones (parece que no puedo hacer uno aquí). En caso de que esté roto, aquí está el código:

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

simple si está usando php Simplemente agregue la hora actual al final del css como

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

Así que ahora, cada vez que recargas lo que sea, el tiempo cambia y el navegador piensa que es un archivo diferente ya que el último bit sigue cambiando ... Puedes hacer esto para cualquier archivo u obligar al navegador a actualizar siempre usando cualquier lenguaje de scripting que quieras

asiimwedismas
fuente
0

De manera sencilla, puede utilizar rel = "preload" en lugar de rel = "stylesheet" .

<link rel="preload" href="path/to/mystylesheet.css" as="style" onload="this.rel='stylesheet'">
Gagan
fuente
Dijiste usar rel="reload"pero el ejemplo dice rel="preload".
haykam
Gracias @haykam por corregirme, lo he actualizado.
Gagan
0

Dado que esta pregunta se mostró en el stackoverflow en 2019, me gustaría agregar mi contribución usando un JavaScript más moderno.

Específicamente, para hojas de estilo CSS que no están en línea, ya que eso ya está cubierto de la pregunta original, de alguna manera.

En primer lugar, observe que todavía no tenemos Objetos de hoja de estilo construibles. Sin embargo, esperamos que lleguen pronto.

Mientras tanto, asumiendo el siguiente contenido 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>

Podríamos tener, en 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
fuente