Jak na CSS importy?

Chcete použít CSS import, ale nefunguje?

@import(//ajax.googleapis.com/ajax/libs/jqueryui/1.11.1/themes/smoothness/jquery-ui.css);

Kam s ním?

Nejdůležitějším a často opomíjeným problémem je, že @import musí být na začátku CSS souboru – veškeré importy je potřeba provést před tím, než začnete definovat ostatní CSS pravidla.

/* Tohle je v pořádku */
@import(/css/theme.css)
body { color: black; } /* ignore theme color */
/* Tohle fungovat nebude! */
body { color: black; } /* výchozí barva */
@import(/css/theme.css) /* načti vlastní barvu */

Pokud chcete použít importy, musíte soubory uspořádat tak, aby import byl vždy na začátku – a to i za cenu toho, že soubor rozdělíte na dva (či více). Např. výše uvedený nefunkční případ by se dal opravit tak, že výchozí barvu načtete v samostatném souboru, a následně v dalším souboru na začátek uvedete import:

/* default.css */
body {color: black; }

/* custom.css */
@import(/css/theme.css)
body { font-size: 1.1REM }

Importu totiž vadí pouze pravidla v daném souboru, pravidla nadefinovaná v jiném souboru je možno uvést před importem.

Minifikace

Na problém narazíte v okamžiku, kdy začnete používat nějaké minifikační nástroj. A postačí úplně primitivní, který jen spojí CSS soubory do jednoho, aby se zrychlilo jejich načítání – pak, i když byl import původně na začátku, může se stát, že při spojení se před něj dostanou pravidla z jiného souboru.

<link href="/minify/build.php
      ?files=default.css+custom.css">
//custom.css obsahuje @import pravidlo, které je nyní uprostřed výsledného souboru!

Nejjednodušší pravidlo pro tento případ je: „nepoužívat importy“. Jestliže chcete spojit soubory do jednoho, aby se rychleji načetli, nedává smysl načítat některý ze souborů přes import – protože ten vždy stahuje importovaný soubor v samostatném requestu.

Jednodušší je tedy importovaný soubor zahrnout přímo do minifikace:

<link href="/minify/build.php
      ?files=default.css+theme.css+custom.css">

Pokud ale import použít prostě potřebujete (např. pro každý theme načítáte jiný Google Font), bude potřeba buď pravidla napsat tak, aby nevadilo pořadí jejich načítání (pomocí selektorů nebo příznaku !important) nebo oželet trochu rychlosti a soubory rozdělit na dva nebo tři tak, aby importy byly vždy na začátku:

<link href="/minify/build.php
      ?files=default1.css+default2.css">
<link href="/minify/build.php
      ?files=custom1.css+custom2.css">
//custom1.css obsahuje import souboru theme.css

Přeci jen to, jestli načítáte jeden nebo dva soubory, není až takový rozdíl a pokud šlo původně o 10 či více CSS souborů, které jste spojili do 2 requestů, pořád jste ušetřili podstatnou dobu potřebnou na navazování spojení pro requesty.

Programové hlídání importů

Pokud musíte používat CSS import a chcete si být 100% jisti, že ho někdo (třeba vy sám) v budoucnu nerozbije (např. neopatrným přidáním pravidla na začátek souboru nebo změnou pořadí pro minifikaci), můžete správnost importu hlídat JavaScriptem.

Všechny CSS soubory a pravidla v nich jsou totiž dostupná v seznamu document.styleSheets a pravidla, kterým prohlížeč nerozuměl, v tomto seznamu prostě nenajdete.

var css, rules, href, imprt, i, j;
css = document.styleSheets;
for (i = 0; i < css.length; i++) {
    rules = css[i].cssRules;
    for (j = 0; j < rules.length; j++) {
        if (rules[j] instanceof CSSImportRule) {
            href = rules[j].href;
            if (isOk(href)) {
                return true; //imported OK
            }
        }
        else {
            break; //if import is not first,
                   //it will be ignored anyway
        }
    }
}
return false; //imported file not found

Pro ještě větší přesnost můžete přečíst rules[j].stylesheet.cssRules a zjistit, jaká pravidla se ze souboru skutečně načetla. Pokud ale načítáte soubor externě (z jiného serveru), nebude to možné kvůli cross-site omezení. Proto je bezpečnější zkontrolovat jen URL a ověřit, že prohlížeč správně našel a rozluštil @import definici (a předpokládat, že k chybě při stahování již nedošlo).

Pokud je import obsažen v externím souboru (z jiného serveru), pak není možno vůbec ověřit, zda k importu došlo (opět kvůli cross-site omezení v řádku rules = css[i].cssRules), ale pokud externímu serveru důvěřujete natolik, že z něj stahujete soubor, budete muset i věřit, že správně ošetří importy.

Napsat komentář

Vaše emailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *