I'm using the following JavaScript to dynamically load stylesheets:
function set_stylesheet(name) {
var link = document.getElementById('userstylelink');
link.href = link.href.replace(/[^\/]+\.css$/, name + '.css');
}
Is there any way to determine whether the new CSS file is loaded successfully? If it fails, I'd like to be able to apply a default stylesheet.
You might want to see my answer to another similar question here:
Detect and log when external JavaScript or CSS resources fail to load
Basically, you can add an onload callback to see if the file was loaded. (If you load via JS of course)
The simplest way is to check styleSheet.cssText property of the link element after a new href was assigned.
function set_stylesheet(name) {
var link = document.getElementById('userstylelink');
link.href = link.href.replace(/[^\/]+\.css$/, name + '.css');
if ( link.styleSheet.cssText ) {
//if not empty string, it was loaded
}
else {
link.href = "default.css";
}
Alternatively there is "onerror" event which fires when the resource fails to load after href assigned.
Ideally, you would load them all at the beginning and then switch between then.
http://www.alistapart.com/articles/alternate/
http://www.thesitewizard.com/javascripts/change-style-sheets.shtml
That doesn't really answer the question, but I think this way is preferred.
I'd recommend loading via ajax, checking the response as the user pimvbd mentions, but also place a dummy rule at the end of your stylesheet that styles a hidden element with a declaration you can check. For example, give a hidden div border: 987px and check to see if the hidden div's border is in fact 987px. Yes, it introduces a dependency on that style and that element. I've had endless discussions on this with many people, and there's not really a better way (yet). Hopefully s get some attention in browser releases in the near future...
There is a solution that requires no javascript or detection of whether the stylesheet loaded.
It seems you could also apply your default style with a built-in style sheet and then have the dynamically loaded stylesheet override the defaults. If the new stylesheet doesn't load, the default is already loaded and in place, nothing further to do. If the new stylesheet does load, it just overrides the default values and shows the new style.
Related
I load some style.css dynamically in javascript. when the style is loaded, I'll do some calculation that depends on the styles. The code is like this:
link = document.createElement('link');
link.href = 'sheety.css';
link.rel = 'stylesheet';
document.head.appendChild(link);
link.onload = function(){
//some code
//here, I can't the the correct style sometime.
//but most of the time, I can get the correct style
setTimeout(function(){
//here, I can also get the correct style
}, 1000);
};
So, my question is: when does the style is applied successfully?
If I modify the element's position(width, height), can I get the correct value instant, or I must wait some time to let the browser do something by using like setTimeout() function?
I read some resources that says: call dom.getComputedStyle will cause a browser reflow.
I indeed call this method, but I still get the wrong width/height of the DOM.
When I debug the JS code in chrome, I can see that the style is not applied at the break point (from the style tab in chrome developer tools).
Once the style sheet is loaded, a CSSOM or CSSObjectModel is generated. Along with the DOM, the CSSOM is rasterized by a rasterizer and applied (in Chrome, done by Skia).
A style can be said to be applied successfully when a browser completes a reflow or a repaint. We can force the browser for a redraw using many techniques:
element.hide().show(); #using jQuery
Inserting a node into the DOM
and removing it.
These techniques are better explained in a similar question.
I'm writing a Javascript file which will be a component in a webpage. I'd like it to be simple to use - just reference the script file in your page, and it is there. To that end however there is a complication - where should the HTML go that the Javascript generates? One approach would be to require a placeholder element in the page with a fixed ID or class or something. But that's an extra requirement. It would be better if the HTML was generated at the location that the script is placed (or, at the start of body, if the script is placed in head). Also, for extra customizability, if the fixed ID was found, the HTML would be placed inside that placeholder.
So I'm wondering - how do I detect my script's location in the page? And how do I place HTML there? document.write() comes to mind, but that is documented as being pretty unreliable. Also it doesn't help if the script is in the head. Not to mention what happens if my script is loaded dynamically via some AJAX call, but I suppose that can be left as an unsupported scenario.
I am doing that with this code...
// This is for Firefox only at the moment.
var thisScriptElement = document.currentScript,
// Generic `a` element for exploiting its ability to return `pathname`.
a = document.createElement('a');
if ( ! thisScriptElement) {
// Iterate backwards, to look for our script.
var scriptElements = document.body.getElementsByTagName('script'),
i = scriptElements.length;
while (i--) {
if ( ! scriptElements[i].src) {
continue;
}
a.href = scriptElements[i].src;
if (a.pathname.replace(/^.*\//, '') == 'name-of-your-js-code.js') {
thisScriptElement = scriptElements[i];
break;
}
}
}
Then, to add your element, it's simple as...
currentScript.parentNode.insertBefore(newElement, currentScript);
I simply add a script element anywhere (and multiple times if necessary) in the body element to include it...
<script type="text/javascript" src="somewhere/name-of-your-js-code.js?"></script>
Ensure the code runs as is, not in DOM ready or window's load event.
Basically, we first check for document.currentScript, which is Firefox only but still useful (if it becomes standardised and/or other browsers implement it, it should be most reliable and fastest).
Then I create a generic a element to exploit some of its functionality, such as extracting the path portion of the href.
I then iterate backwards over the script elements (because in parse order the last script element should be the currently executing script), comparing the filename to what we know ours is called. You may be able to skip this, but I am doing this to be safe.
document.write is very reliable if used as you indicate (a default SharePoint 2010 page uses it 6 times). If placed in the head, it will write content to immediately after the body element. The trick is to build a single string of HTML and write it in one go, don't write snippets of half-formed HTML.
An alternative is to use document.getElementsByTagName('script') while the document is loading and assume the the last one is the current script element. Then you can look at the parent and if it's the head, use the load or DOM ready event to add your elements after the body. Otherwise, just add it before or after the script element as appropriate.
I want to implement different CSS style sheet using javascript or code behind on aspx page so that for different web browser my page look better. Can anyone have some solution about this problem? I try a lot to implement that but failed.
Generally you don't want to go down the route of dynamically generating CSS with Javascript. The best approach to CSS is to:
Use a reset CSS;
Declare a DOCTYPE on every page; and
If necessary, include IE-specific additions (because, let's face it, it's always IE that causes the problems).
To add to Ravia:
You can use Request.Browser to get browser versions:
HttpBrowserCapabilities bc = Request.Browser;
if (bc.Browser == "IE" && bc.Version == "6.0")
{
HtmlLink link = new HtmlLink();
link.Href = ResolveClientUrl("~/CSSFile.css");
link.Attributes.Add("rel", "stylesheet");
link.Attributes.Add("type", "text/css");
Page.Header.Controls.Add(link);
}
I'd go with the server side option (aspx in your case).
check the 'user_agent' request header to determine the user's browser type
logically include a different css file based on this variable
HtmlLink styleSheet = new HtmlLink();
styleSheet.Attributes.Add("rel","stylesheet");
styleSheet.Attributes.Add("type","text/css");
styleSheet.Attributes.Add("href",ResolveClientUrl("MyStyleSheet.css"));
this.Page.Header.Controls.Add(styleSheet);
Check this out.
You can even set the style by adding a literal to your head tag and add the css style as text to this literal.
Happy coding.
Am wondering how it would be possible to unload a CSS from a page. e.g. In my page I have included a file called a.css. Now I want the user to be able to change the theme, which is CSS driven, thus he/she should be able to unload a.css and then I can load b.css (else they will conflict)
Any idea how to go about this?
Take the link element and disable it
document.getElementsByTagName('link')[0].disabled = true;
With jquery, this works:
$("link[href='fileToRemove.css']").remove();
Obviously, replace fileToRemove.css with the relative path and filename of the file to be unloaded.
var firstLink = document.getElementsByTagName('link')[0];
firstLink.parentNode.removeChild(firstLink)
This would remove the first link element on the page - not sure how your html is structured but I'm sure you can use it as an example. You might want to check the type attribute if it's 'text/css' and you're targeting the right media (screen), or possibly check if the href contains 'css' anywhere if you have other link elements that aren't css references.
Note you can also re-set the href attribute to point to a non-existing page instead of removing the element entirely.
Oddly enough, IE and firefox support the disabled attribute, but neither Chrome, Safari, nor Opera support it. So, this should be the most cross-browser solution.
// Disables a particular stylesheet given its DOM Element
function unload_stylesheet(DOMelement){
DOMelement.disabled = true;
DOMelement.parentNode.removeChild( DOMelement );
DOMelement.href = "data:text/css,"; // empty stylesheet to be sure
}
// Usage:
unload_stylesheet( document.getElementsByTagName('link')[0] );
In firefox, I have the following fragment in my .css file
tree (negative){ font-size: 120%; color: green;}
Using javascript, how do I change the rule, to set the color to red?
NOTE:
I do not want to change the element.
I want to change the rule.
Please do not answer with something like
...
element.style.color = 'red';
What you're looking for is the document.styleSheets property, through which you can access your css rules and manipulate them. Most browsers have this property, however the interface is slightly different for IE.
For example, try pasting the following in FF for this page and pressing enter:
javascript:alert(document.styleSheets[0].cssRules[1].cssText)
For me that yields the string "body { line-height: 1; }". There are methods/properties that allow you to manipulate the rules.
Here's a library that abstracts this interface for you (cross-browser): http://code.google.com/p/sheetup/
function changeCSSRule (stylesheetID, selectorName, replacementRules) {
var i, theStylesheet = document.getElementById(stylesheetID).sheet,
thecss = (theStylesheet.cssRules) ? theStylesheet.cssRules : theStylesheet.rules;
for(i=0; i < thecss.length; i++){
if(thecss[i].selectorText == selectorName) {
thecss[i].style.cssText = replacementRules;
}
}
};
You can change CSS rules in style sheets through the CSS Object Model (currently known as DOM Level 2 Style). However, if you literally have "tree (negative)" in your style sheet that rule will be dropped and not appear in the Object Model at all.
As there is no HTML element tree I am going to assume that tree is the id or class of another element.
You would first retrieve the DOM element by id:
var tree = document.getElementById("tree");
Now tree represents your DOM element and you can manipulate it any way you like:
tree.style.color = "red";
Here is a great reference for mapping css properties to their javascript equivalent.
I'm not sure you can do actual class/selector overrides. You would need to target each element that used the .tree class and set the CSS. The quickest and easiest way would be through jQuery (or another similar framework):
$('.tree').each(function() { this.style.color = "red"; });
You could even use the built-in CSS functions:
$('.tree').css('color', 'red');
(I did it the first way to show you how standard JS would do it. The $(...) part is jQuery for selecting all elements with the .tree class. If you're not using jQuery, you'd need alternative code.)
If tree is an ID, not a class (there should only be one on the page) so using getElementById should be fine. Your code should look like the other answer.
for( var i in document.getElementsByTagName("tree") ){
document.getElementsByTagName("tree")[i].style.color = "red";
}
As I said in another answer's comment, I've never seen this done how you want. I've only ever targeted elements the same way as the CSS renderer would and changed each element style.
I did see this though: jQuery.Rule
It sounds like it does what you want but the demo causes my browser to flip out a bit. I'd invite you to look at the source to see it really does do what you want, and if you want to use it without jQ, use it as a starting point.
Edit: yes this should work. It works by appending another <style> tag to the page and writing out your overrides within. It's fairly simple to follow if you wanted to port it to plain JS.
For debugging, you can use Firebug to change the CSS rules on-the-fly.
If you want to change the rendered css rules from one page request to the next then some sort of server-side scripting will be required. Otherwise the original style sheet would simply reload at the next page request.
If you want to use an event on the first page to force the server-side action then you can use AJAX to actually change the CSS rule for the user.
"I want to change the rule so that
when I navigate to the next page, I
don't have to make all the changes
again."
It sounds like what you might want then is a remote request ("ajax") back to the server with the request you want to make, and generate a dynamic stylesheet which is sent back to the client?
How/why is this Firefox specific?
I want to change the rule so that when I navigate to the next page, I don't have to make all the changes again.
There are two approaches I can think of here. Namely client side and/or server side.
Client side:
Store the theme setting into cookies and load them up next time by javascript.
Server side:
If your site have an login system, you may also store the user preference into the database and generate the webpages with this inforamtion in mind next time on.
Utimately, you are still writing things like element.style.color =. But, they should get what you want.