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?
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?
Respuestas:
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 innerHTML
propiedad 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
innerHTML
busca de <style>
elementos (y <script>
).
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);
});
}
var links = document.getElementsByTagName("link"); for (var i = 0; i < links.length;i++) { var link = links[i]; if (link.rel === "stylesheet") {link.href += "?"; }}
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 += "";
}
}
Echa un vistazo al elegante proyecto Vogue de Andrew Davey: http://aboutcode.net/vogue/
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())
}
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>');
};
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:
¿Qué hace?
Vuelve a cargar CSS agregando parámetros de cadena de consulta (como las soluciones anteriores):
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 ;-)
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=">
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)();
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
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'">
rel="reload"
pero el ejemplo dice rel="preload"
.
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);
}