Dinamično vključevanje CSS z JavaScript?

Se je kdo že igral s tem? Načeloma je zadeva besno enostavna, zelo podobno se dinamično vključuje JS in CSS, takole:

CSS: (predvidevamo, da imamo v spremenljivkah file in media o datoteki in media typu)

var head = document.getElementsByTagName('head').item(0);
var css = document.createElement('link');
css.setAttribute('type', 'text/css');
css.setAttribute('rel', 'stylesheet');
css.setAttribute('href', file);
css.setAttribute('media', media);
head.appendChild(css);

JS: (predvidevamo, da imamo v spremenljivki file podatek o datoteki)

var head = document.getElementsByTagName('head').item(0);
script = document.createElement('script');
script.setAttribute('type', 'text/javascript');
script.setAttribute('src', file);
head.appendChild(script);

Do težave pridem, ko želim loviti dogodek, ko se datoteka uspešno naloži, za JS je to enostavno:

var func = function() {
   // some code
};
script.onload = func;
script.onreadystatechange = function() {
   if (/complete|loaded/.test(script.readyState)) func();
};

script.onload se izvrši v IE, script.onreadystatechange pa v FF (imamo problem, ker se lahko izvrši dvakrat, ampak pustimo to, ne bi dodajal kode, zaradi preglednosti).

Če želim to isto storiti s CSS, se v FF ne zgodi nič, ni nobenega dogodka, niti load, niti readystatechange, v IE se baje izvrši kar oboje :)

Vprašanje je enostavno, se je kdo že ubadal s tem problemom in uspešno rešil detekcijo uspešno dinamično naloženega CSSja? Na webu sem sicer našel "rešitev", ki pa ne deluje, preverjanje document.styleSheets.length, ki se, po mojih opažanjih, poveča takoj, ne pa šele takrat, ko je CSS že naložen, neuporabno skratka.

5 odgovorov

script.onload lahko izvedeš tudi tako, da executaš neko funkcijo na koncu .js fajla.

Za css pa ne vem, kako bi pripoal onload event. Edina ideja, ki mi pade na pamet, je ta, da na nek obstoječi element na strani določiš neobstoječi stil XYZ. Ta stil definiraš v dinamičnem CSS-u, potem pa s timerjem preverjaš, kdaj se mu je neka lastnost določila (npr. background-color). Ko dobiš tisti background color, ki je definiran v CSS-u, veš, da se je CSS ne samo naložil, ampak tudi apliciral (kar je lahko pomembno, odvisno od problema). Ne vem pa, če to deluje.

lp

Ja, res je, uloviti želim dogodek, ko je CSS že apliciran. Ta tvoja rešitev mi lahko zadeve reši le za določeno situacijo, jaz bi si pa le želel, da zadevo uredim bolj generično.

Očitno bom le moral poiskati nek workaround, problem je sicer sila preprost. Z nekim klicem, lahko bi mu rekli tudi AJAX, v dokument dodam nek CSS in v DOM v BODY appendam kar želim. Ker se CSS še ni naložil, se mi tisti del DOMa, ki sem ga dodal, za trenutek pojavi na dnu strani, seveda nepostajlan, potem pa se pravilno zloži tja, kamor se mora po pravilih iz CSSja. Zadevo sem sicer že rešil blazno elegantno tako, da sem ves dodani DOM wrappal v DIV z izbranim IDjem, recimo "viniwrap", mu določil style="display:none;", na koncu CSSja pa dodal #viniwrap{display:block !important;}. Zadeva seveda deluje lušno, vendar si verjetno že sam ugotovil, kje pa ne, seveda v IE6 :)

Poskusil sem tudi tako, da v DOM pred prej omenjenim DIVom dodam <style type="text/css">#viniwrap{display:none;}</style> in ga na koncu CSSja poskušam overridat z #viniwrap{display:block;}, vendar se zadeva vseeno ne overrida, predvidevam da zato, ker se CSS doda v HEAD, ki pa ga overrida tisti style, ki se je v dokumentu sicer pojavil časovno kasneje, po strukturi pa prej. Ga bom poskusil dodati pred tisti zunanji fajl v HEAD, pa da vidimo :)

Še vedno pa iščem kakšno bolj elegantno rešitev, ta se mi mnogo butasta, tudi če deluje :P

Aha, sem imel prav, zadnja verzija deluje pravilno :) Sem pa še vedno mnenja, da je močno butasta :P

butasta rešitev za butast brskalnik :)

glede #vini_wrap; mogoče bi najprej naložil css, potem pa šele dodal elemente DOM. Na ta način bi se CSS zdownloadal prej in sveže dodani elementi ne bi pojavili na dni strani, ker bi CSS zanje že obstajal.

Ja, saj ravno to sem delal do sedaj, dodal CSS (external file) v HEAD in potem dodal elemente v DOM (znotraj BODY), pa se je dogajalo opisano. Zato sem želel loviti dogodek, ko se CSS naloži in aplicira, da pač toliko časa počakam, preden začnem manipulirati z DOMom.