Pull to refresh

Еще один способ подгрузки CSS через RequireJS

Reading time 3 min
Views 10K
В процессе разработки JS модулей, претендующих на переиспользуемость, часто возникает необходимость кроме js-кода и разметки подгрузить еще и файл со стилями. Как известно, сами по себе стили могут быть добавлены к документу тремя способами: через тэг link, через тэг style, и через атрибут style. В зависимости от выбранного способа можно получить различные плюсы и минусы. Я предлагаю посмотреть на способ, состоящий из использования тэга link, но избавленный от проблемы отсутствия события окончания загрузки таблицы стилей со стороны браузера.

для тех кому только код
define(["text!myCSS.css"], function(cssText) {
	'use strict';
	var link = document.createElement("link");
	link.rel = "stylesheet";
	link.type = "text/css"
	link.href = "data:text/css,"+encodeURI(cssText);
	var cssLinks = document.querySelectorAll("link[rel=stylesheet]");
	
	if (cssLinks.length > 0) {
		cssLinks[0].parentElement.insertBefore(link, cssLinks[0]);
	} else {
		document.querySelector("head").appendChild(link);
	}
});


Начнем с ответа на вопрос «Зачем именно через тэг link?»

Дело в том, что от модуля обычно хочется получить возможность удобно кастомизировать его визуальное представление.
Если мы захотим использовать атрибут style прямо в нашей разметке, то в дальнейшем при переиспользовании нам придется как-то эти атрибуты менять — супер неудобно и не гибко.

Если мы захотим использовать тэг style, то возникает проблема с тем, что для кастомизации таких стилей придется также вставлять в документ тэг style с нужным содержимым, что также не очень удобно.

Если мы захотим использовать тэг link, то мы сможем просто подключить нашу собственную таблицу стилей после загруженной и подправить представление по-умолчанию под сиюминутные нужды.

Из вышеперечисленного выходит, что вариант с тэгом link наиболее гибкий, т.к. позволяет переопределить стили при использовании компонента наибольшим числом способов.

Как написано в документации RequireJS, для подгрузки css можно использовать такой код:

function loadCss(url) {
    var link = document.createElement("link");
    link.type = "text/css";
    link.rel = "stylesheet";
    link.href = url;
    document.getElementsByTagName("head")[0].appendChild(link);
}

Он всем неплох, кроме того что вы не узнаете, когда именно будет подгружен ваш css (и будет ли вообще, могли же, например, в путях опечататься). Эта проблема чревата еще и тем, что может вызвать некрасивое поведение картинки, в случае если рендер страницы будет проводится до окончания загрузки файла.

А хочется написать компонент примерно так:

define(["text!myCSS.css", "text!myHTML.html"], function(cssText, htmlText) {
	'use strict';
...
});

Но как же потом запихнуть полученный текст css в нашу страницу? Тэг style мог бы нам помочь, но ранее было решено, что наш вариант — это именно link.

Предлагаемое решение — это Data URL (если кто не знает, что это такое, здесь можно посмотреть).

Добавлять будем примерно так:

	var link = document.createElement("link");
	link.rel = "stylesheet";
	link.type = "text/css"
	link.href = "data:text/css,"+encodeURI(cssText);
	var cssLinks = document.querySelectorAll("link[rel=stylesheet]");
	
	if (cssLinks.length > 0) {
		cssLinks[0].parentElement.insertBefore(link, cssLinks[0]);
	} else {
		document.querySelector("head").appendChild(link);
	}

Метод несомненно имеет некоторые минусы, из очевидных — base64 кодирование увеличивает объем данных, теоретически можно столкнуться с ограничениями на длину URL для некоторых браузеров. Но если объем стилей небольшой, то метод выглядит вполне рабочим.

UPD:
Cпасибо oledje за подсказку, base64 кодирование для текста не нужно, лучше подойдет URL encoding, подправил код.
Tags:
Hubs:
+9
Comments 28
Comments Comments 28

Articles