Как загрузить файлы CSS с помощью Javascript?

317

Можно ли импортировать таблицы стилей CSS в HTML-страницу, используя Javascript? Если так, как это можно сделать?

PS javascript будет размещен на моем сайте, но я хочу, чтобы пользователи могли добавлять <head>теги своего сайта, и он должен иметь возможность импортировать файл css, размещенный на моем сервере, в текущую веб-страницу. (и файл css, и файл javascript будут размещены на моем сервере).

Нажмите Upvote
источник
Есть также вопрос о jQuery stackoverflow.com/questions/2685614/…
jcubic

Ответы:

416

Вот способ «старой школы», который, надеюсь, работает во всех браузерах. Теоретически, вы бы использовали, setAttributeк сожалению, IE6 не поддерживает его последовательно.

var cssId = 'myCss';  // you could encode the css path itself to generate id..
if (!document.getElementById(cssId))
{
    var head  = document.getElementsByTagName('head')[0];
    var link  = document.createElement('link');
    link.id   = cssId;
    link.rel  = 'stylesheet';
    link.type = 'text/css';
    link.href = 'http://website.com/css/stylesheet.css';
    link.media = 'all';
    head.appendChild(link);
}

В этом примере проверяется, был ли CSS уже добавлен, поэтому он добавляет его только один раз.

Поместите этот код в файл javascript, попросите конечного пользователя просто включить javascript и убедитесь, что путь CSS является абсолютным, чтобы он загружался с ваших серверов.

VanillaJS

Вот пример, который использует простой JavaScript для вставки CSS-ссылки в headэлемент на основе части имени файла в URL:

<script type="text/javascript">
var file = location.pathname.split( "/" ).pop();

var link = document.createElement( "link" );
link.href = file.substr( 0, file.lastIndexOf( "." ) ) + ".css";
link.type = "text/css";
link.rel = "stylesheet";
link.media = "screen,print";

document.getElementsByTagName( "head" )[0].appendChild( link );
</script>

Вставьте код непосредственно перед закрывающим headтегом, и CSS будет загружен до визуализации страницы. Использование внешнего .jsфайла JavaScript ( ) приведет к появлению флэш-памяти нестандартного содержимого ( FOUC ).

card100
источник
6
Как насчет запуска обратного вызова после загрузки файла CSS?
jchook
1
Это довольно сложно сделать надежно. Популярные библиотеки Javascript теперь обычно имеют некоторую форму загрузки javascript и таблиц стилей с обратным вызовом. В качестве примера см. YUI Get .
9
возможно, было бы лучше использовать другой символ, чем $, для ярлыка документа, поскольку он может легко мешать jQuery (как это было в моем случае);)
Zathrus Writer
2
@jonnybojangles Использование jQuery.noConflict будет означать переименование всех ваших ссылок на jQuery как $. Было бы гораздо проще просто использовать другое имя переменной для загрузчика CSS.
Tommypyatt
2
@jchook Мне удалось добавить link.onload = function(){ ... }
ответный
74

Если вы используете JQuery:

$('head').append('<link rel="stylesheet" type="text/css" href="style.css">');
BoumTAC
источник
1
это работает только в том случае, если таблица стилей вставлена ​​до правильной загрузки страницы? Когда я запускаю эту команду внутри консоли на загруженной странице с файлом CSS, который я разместил в dropbox, она не будет работать. Любая идея , как я могу сделать эту работу:$('head').append('<link rel="stylesheet" type="text/css" href="https://dl.dropboxusercontent.com/s/ep1nzckmvgjq7jr/remove_transitions_from_page.css">');
томас
50

Я думаю, что-то вроде этого скрипта будет делать:

<script type="text/javascript" src="/js/styles.js"></script>

Этот файл JS содержит следующее утверждение:

if (!document.getElementById) document.write('<link rel="stylesheet" type="text/css" href="https://stackoverflow.com/css/versions4.css">');

Адрес javascript и css должен быть абсолютным, если они ссылаются на ваш сайт.

Многие методы импорта CSS обсуждаются в этой статье «Скажи нет CSS-хаки с методами ветвления» .

Но в статье «Использование JavaScript для динамического добавления таблиц стилей CSS для портлета» упоминается также возможность CreateStyleSheet (собственный метод для IE):

<script type="text/javascript">
//<![CDATA[
if(document.createStyleSheet) {
  document.createStyleSheet('http://server/stylesheet.css');
}
else {
  var styles = "@import url(' http://server/stylesheet.css ');";
  var newSS=document.createElement('link');
  newSS.rel='stylesheet';
  newSS.href='data:text/css,'+escape(styles);
  document.getElementsByTagName("head")[0].appendChild(newSS);
}
//]]>
VonC
источник
вот что я придумал, чтобы добавить document.createStyleSheet()в браузеры, у которых его нет: stackoverflow.com/questions/524696/…
Christoph
1
Не знаю точно, в каком случае, но в некоторых случаях document.writeэто не рекомендуется, поскольку оно перезаписывает весь текст вашего сайта.
Эдуард Лука
@VonC, есть ли функция для прямого получения <style>элемента вместо того, чтобы предполагать, что это первый дочерний элемент <head>via ("head")[0]?
Pacerier
@Pacerier Я полагаю, вы найдете то, что обсуждалось в groups.google.com/forum/#!topic/prototype-scriptaculous/… . Это было бы, например:var style = document.getElementsByTagName("style")[0];
VonC
21

Element.insertAdjacentHTML имеет очень хорошую поддержку браузера и может добавить таблицу стилей в одну строку.

document.getElementsByTagName("head")[0].insertAdjacentHTML(
    "beforeend",
    "<link rel=\"stylesheet\" href=\"path/to/style.css\" />");
dangowans
источник
12

Если вы хотите знать (или подождать), пока сам стиль не загрузится, это работает:

// this will work in IE 10, 11 and Safari/Chrome/Firefox/Edge
// add ES6 poly-fill for the Promise, if needed (or rewrite to use a callback)

let fetchStyle = function(url) {
  return new Promise((resolve, reject) => {
    let link = document.createElement('link');
    link.type = 'text/css';
    link.rel = 'stylesheet';
    link.onload = function() { resolve(); console.log('style has loaded'); };
    link.href = url;

    let headScript = document.querySelector('script');
    headScript.parentNode.insertBefore(link, headScript);
  });
};
Сандстр
источник
Как я могу использовать это
Радж Шарма
Вы бы сделали fetchStyle (url) .then (function () {вещи идут сюда}), чтобы прочитать об обещаниях
Бен Талиадорос
8

Я знаю, что это довольно старая тема, но вот мои 5 центов.

Есть другой способ сделать это в зависимости от ваших потребностей.

У меня есть случай, когда я хочу, чтобы файл CSS был активен только некоторое время. Как переключение CSS. Активируйте CSS, а затем после другого события деактивируйте его.

Вместо того, чтобы динамически загружать css и затем удалять его, вы можете добавить идентификатор Class / id перед всеми элементами в новом css, а затем просто переключить этот класс / id базового узла вашего css (например, тега body).

В этом решении вы бы изначально загружали больше CSS-файлов, но у вас есть более динамичный способ переключения макетов CSS.

JohanSellberg
источник
7

В современном браузере вы можете использовать promiseвот так. Создайте функцию загрузчика с обещанием:

function LoadCSS( cssURL ) {

    // 'cssURL' is the stylesheet's URL, i.e. /css/styles.css

    return new Promise( function( resolve, reject ) {

        var link = document.createElement( 'link' );

        link.rel  = 'stylesheet';

        link.href = cssURL;

        document.head.appendChild( link );

        link.onload = function() { 

            resolve(); 

            console.log( 'CSS has loaded!' ); 
        };
    } );
}

Тогда, очевидно, вы хотите что-то сделать после загрузки CSS. Вы можете вызвать функцию, которая должна запускаться после загрузки CSS следующим образом:

LoadCSS( 'css/styles.css' ).then( function() {

    console.log( 'Another function is triggered after CSS had been loaded.' );

    return DoAfterCSSHasLoaded();
} );

Полезные ссылки, если вы хотите глубже понять, как это работает:

Официальные документы по обещаниям

Полезное руководство к обещаниям

Отличное вступительное видео об обещаниях

Артур Тарасов
источник
6

Используйте этот код:

var element = document.createElement("link");
element.setAttribute("rel", "stylesheet");
element.setAttribute("type", "text/css");
element.setAttribute("href", "external.css");
document.getElementsByTagName("head")[0].appendChild(element);
Гаурав Трипати
источник
4

Существует общий плагин jquery, который загружает css и JS файлы, синхронизируя и asych по требованию. Он также отслеживает то, что уже загружено :) см. Http://code.google.com/p/rloader/

EZ2
источник
4

Вот способ с методом создания элемента jQuery (мои предпочтения) и с обратным вызовом onLoad:

var css = $("<link>", {
  "rel" : "stylesheet",
  "type" :  "text/css",
  "href" : "style.css"
})[0];

css.onload = function(){
  console.log("CSS IN IFRAME LOADED");
};

document
  .getElementsByTagName("head")[0]
  .appendChild(css);
Lounge9
источник
3

Библиотека YUI может быть тем, что вы ищете. Он также поддерживает междоменную загрузку.

Если вы используете jquery, этот плагин делает то же самое.

anand.trex
источник
2

Ниже полный код, используемый для загрузки JS и / или CSS

function loadScript(directory, files){
  var head = document.getElementsByTagName("head")[0]
  var done = false
  var extension = '.js'
  for (var file of files){ 
    var path = directory + file + extension 
    var script = document.createElement("script")
    script.src = path        
    script.type = "text/javascript"
    script.onload = script.onreadystatechange = function() {
        if ( !done && (!this.readyState ||
            this.readyState == "loaded" || this.readyState == "complete") ) {
            done = true
            script.onload = script.onreadystatechange = null   // cleans up a little memory:
            head.removeChild(script)  // to avoid douple loading
        }
  };
  head.appendChild(script) 
  done = false
 }
}

function loadStyle(directory, files){
  var head = document.getElementsByTagName("head")[0]
  var extension = '.css'
  for (var file of files){ 
   var path = directory + file + extension 
   var link = document.createElement("link")
   link.href = path        
   link.type = "text/css"
   link.rel = "stylesheet" 
   head.appendChild(link) 
 }
}

(() => loadScript('libraries/', ['listen','functions', 'speak', 'commands', 'wsBrowser', 'main'])) ();
(() => loadScript('scripts/', ['index'])) ();

(() => loadStyle('styles/', ['index'])) ();
Хасан Юсеф
источник
1

Я хотел бы поделиться еще одним способом загрузить не только css, но и все ресурсы (js, css, images) и обработать событие onload для группы файлов. Это async-assets-loader. Смотрите пример ниже:

<script src="https://unpkg.com/async-assets-loader"></script>
<script>
var jsfile = "https://code.jquery.com/jquery-3.4.1.min.js";
var cssfile = "https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css";
var imgfile = "https://logos.keycdn.com/keycdn-logo-black.png";
var assetsLoader = new asyncAssetsLoader();
assetsLoader.load([
      {uri: jsfile, type: "script"},
      {uri: cssfile, type: "style"},
      {uri: imgfile, type: "img"}
    ], function () {
      console.log("Assets are loaded");
      console.log("Img width: " + assetsLoader.getLoadedTags()[imgfile].width);
    });
</script> 

По асинхронным активам-погрузчиком документы

v.babak
источник
0
var fileref = document.createElement("link")
fileref.setAttribute("rel", "stylesheet")
fileref.setAttribute("type", "text/css")
fileref.setAttribute("th:href", "@{/filepath}")
fileref.setAttribute("href", "/filepath")

Я использую тимелист, и это отлично работает. Спасибо

ekoindra0912
источник
Какой смысл добавлять th:hrefатрибут на стороне клиента? Он не будет обрабатываться Thymeleaf, поэтому здесь он кажется излишним.
Слава