Archive for the 'browsers' Category
Smart browsers don't download unneeded images
Saturday, June 23rd, 2007We ofter complain about browsers, browser inconsistencies, quirks, hickups, the list goes on. Let's say something nice to them, and hope for good karma
It happens as your web app grows in size and team members that some parts of the stylesheets become obsolete, no one remembers why they were there in the first place, but no one has cojones to remove them, because of fear that removing them might break something you forgot to take into consideration. Same case when you have the same stylesheet for 50 different pages and on some pages only some of the styles are actually used. I was wondering, do you pay performance penalty when you have style rules that refer to images, but the rules are never needed to render the page? Will the browser download all those unneeded images? The answer is No. The browser will try to avoid downloading the image assets as much as possible. And this behavior is pleasantly consistent across IE, FF, Safari (for Windows), Opera.
Test #1
I tried this stylesheet:
body { background: url(bg.png); } #some-id { background: url(ie.png); } .some-class-name { background: url(o.png); } p { background: url(image.php); }
And applied it to a blank page that doesn't have any paragraphs, or elements with class name some-class-name, or ID some-id. The result was that only bg.png was downloaded, which is great.
> test #1
Test #2
I added a button which, when clicked, creates a new P element and sets a 3 seconds timeout before appending the new element to the body. (The background for the P element is the script image.php which only sleeps for 3 seconds for demonstration purposes, before redirecting to ff.png.) The result is that the image is requested only after the element is added to the document flow, not when it was created. Which is smart. It ain't added ’till it's added.
> test #2 (same file as test #1, btw)
Test #3
OK, modified test #2. A P element is created, its visibility is set to hidden and it's added to the document. It's officially in the document flow, although not currently displayed. My guess was that the browsers will download the image at this point. True for FF, IE7, Safari, Opera.
> test #3
Test #4
Here's the only inconsistence in the behavior of the browsers. A P element is created, but with display: none, then added to the document. So it's part of the DOM tree, but not really part of the document flow. Then another button changes display to block.
FF will wait for the display: block before downloading the image background
Opera will also wait until display: block
IE7 begins to crack under the pressure and downloads the image even with display: none
So is Safari
> test #4
So what?
Well, it's nice to know that the browsers won't download the images referred to from our stylesheets unless they are needed for rendering. There is a side effect though. If you happen to create dynamic elements that have some styles with background and no other similar elements already exists on the page, the user experience might suffer slightly as the image will generally be requested after the new element is added. In cases when this is important to you, you might need to take some extra care to make sure the image is downloaded before you add the new element. You might need to do for example a new Image() after initial page load. (reminds me of the good old days of image rollover buttons, those were the days, eh? Seems like no one does image rollover buttons and menus anymore. It's all css this, css that…
)
Dynamic SCRIPT and STYLE elements in IE
Friday, January 26th, 2007So you know how to add external scripts and styles, using the DOM, after the page is loaded. And what if you don't have external files, but have some style definitions and some JS code as text and you want it inserted and executed into a page.
The DOM way
"Ha! An easy one", you'd say and then go like:
var ss = document.createElement('script'); var scr = 'alert("bah");'; var tt = document.createTextNode(scr); ss.appendChild(tt); var hh = document.getElementsByTagName('head')[0]; hh.appendChild(ss);
"Ha!" in turn says IE, "No way!"
The IE way for SCRIPT
The above won't work in IE, but you can use the text property instead of creating a text node. Interestingly enough, this also works in Firefox.
var ss = document.createElement('script'); var scr = 'alert("bah");'; ss.text = scr; var hh = document.getElementsByTagName('head')[0]; hh.appendChild(ss);
The IE way for STYLE
STYLE, SCRIPT, what's the difference, they are merely elements of the DOM tree. For the normal browsers, yes, so creating a text node with the stylesheet body will work in Firefox. For IE, you need a workaround.
var ss1 = document.createElement('style'); var def = 'body {color: red;}'; ss1.setAttribute("type", "text/css"); ss1.styleSheet.cssText = def; var hh1 = document.getElementsByTagName('head')[0]; hh1.appendChild(ss1);
Note that while in the SCRIPT case I took the liberty of skipping the type attribute, it's absolutely required here.
So with a bit of object sniffing, we can get a cross-browser solution:
var ss1 = document.createElement('style'); var def = 'body {color: red;}'; ss1.setAttribute("type", "text/css"); if (ss1.styleSheet) { // IE ss1.styleSheet.cssText = def; } else { // the world var tt1 = document.createTextNode(def); ss1.appendChild(tt1); } var hh1 = document.getElementsByTagName('head')[0]; hh1.appendChild(ss1);
Firebug console for IE
Wednesday, December 6th, 2006Update: A better version of what I was trying to do is here. It works around the cross-domain permission problems in IE by not loading a page in the frame, but putting there the actual content.
Firebug - no words to describe how cool it is, really. After the recent new release (1.0. beta) the number of features is overwhelming. I for one can't live anymore without it, seriously.
One of the things I noticed on the website is the ability to use the Firebug console in other browsers than Firefox. I don't know if this existed before version 1.0 but if it did, it was the best kept secret. I am so addicted to the console in Firefox, I use it all the time to tweak a few things here and there when I'm working on a page. Recently I was looking for something similar for IE, but couldn't find it. Lo and behold, it was right under my nose.
So, here's the page that describes how to use Firebug in IE (and others). Basically you unzip the Firebug Lite files somewhere on your server and then you include firebug.js in your pages. But why stop there? And isn't it possible to avoid including this script on every page (and forgetting to remove once you're done, or removing it prematurelly since a page, just like a painting, is never really finished). Bookmarklets to the rescue!
I wanted to host the Firebug files on my hard-drive and then use a javascript dynamic include to load firebug.js via a bookmarklet. This way I would be able to load the firebug console every time I want it, on any page. Unfortunatelly IE's security policy won't allow it. Then?
Solution
The solution I came up with is:
- you copy the Firebug Lite files somewhere on your server
- you call a bookmarklet that will load firebug.js
- you hit F12 and you have a console!
This procedure has to be repeated for every domain you're working on, because of the security policy that won't allow cross-domain frame scripting. You can have one copy for your http://localhost and one for every domain. To ease the creation of bookmarklets that load firebug.js, I came up with a Firebug bookmarklet generator.
In action
- I copied Firebug Lite files (get the .zip) on this server (phpied.com), they are here.
- I (and you can try the same) generate a bookmarklet, using the bookmarklet tool
- Add the generated bookmarklet to the favorites
- Go to any page on phpied.com
- Click the new favorite
- Hit F12 to show/hide the console
Here's how (a readable version of) the generated code looks like:
javascript:(function(){ var firebug_js = document.createElement('script'); firebug_js.setAttribute('type', 'text/javascript'); firebug_js.src = 'http%3A//www.phpied.com/files/firebug/firebug.js'; document.getElementsByTagName('head')[0].appendChild(firebug_js); firebug_js.onreadystatechange = function () { if (firebug_js.readyState == 'complete') { console.open() } } })()
Minor improvement to the console
The Firebug Lite console executes the code you type, but doesn't show it again when you use the up/down arrows, the way it does in Firefox. So I added this feature (copying from myself), you can replace the firebug.js you download with my version.
Not sold yet?
Here's a screenshot of the console in action, I used it to change my photo on the homepage.
Go ahead, please
I strongly encourage everyone to try this out. Firebug is a beautiful thing and using even a bit of it in IE is great.
Rendering styles
Wednesday, October 4th, 2006The question is - what will a browser do, given a page with several stylesheets, each of them probably overwriting definitions from the previous ones? Will the browser render the page using the first received css file, while downloading the other ones and after that partially re-rendering where required? The answer is: no, the browser will wait until all CSS files are downloaded, (then probably merge all definitions, just a wild guess) and will render once.
Test
I did this test - one page with two stylesheets that contain pretty much the same selectors for different table styles (thanks to this gallery). Each of the CSS files is actually a PHP script and has a call to sleep(), one sleeps for 5 seconds, the other one for 10.
Result
The browser sits there and waits for the both styles, rendering nothing (except for the page title, but that's not really rendering, is it?). So nothing happens for 10 seconds, then the second style is used for the final rendering. This happens in both FF and IE.
Misc
I also tried sleeping in the actual page, and flushing the output after each row. In my home environment FF renders each row as it's received, but in my hosted environment, it waits for the whole table. IE alsways waits for the complete table.
If I put the page to too much sleep so that the php script dies before the second stylesheet is dowloaded, the browser uses whatever is at hand (css1) to render the page.
Demo/download
- the actual test - two CSS files, first one sleeping 5 seconds, the other one 10
- table with no styles, sleeping 1 second after each row
- table with css1 only, css sleeps 5 seconds
- zipped test for your testing pleasure
quirks or no quirks bookmarklet
Wednesday, September 20th, 2006Here's a bookmarklet that will tell you whether or not the browser renders your page in Standards Complaiance Mode or Quirks Mode. The bookmarklet will figure this out for the page as well as for all the frames (and their frames) recursively. Enjoy!
Install
Drag this to your bookmarklets/favorites or right click and add to favorites:
Sample output
Here's a sample output, produced when used in my Wordpress backend when writing this post:
![]()
As you can see the page has two frames (probably iframes, doesn't matter), one of them is rendered in Standards Compliant Mode (CSS1Compat) the other one is in Quirks Mode (BackCompat). The overall document is CSS1Compat as well. For the frames, if they were named, you would see the name of the frame before the URL brackets.
And this is GMail, wow, lotsa frames, none compliant ![]()
![]()
The code
The code is pretty simple, just accessing the compatMode of the the document object. Here it is in more human readable form (not one long line like bookmarket code).
var response = 'Document mode: ' + document.compatMode; function checkFrames(w) { if(w.frames && w.frames.length>0){ response+='\n\n'; for(var i=0;i<w.frames.length;i++){ var fr=w.frames[i]; try { response+=fr.name + ' ('+fr.document.location+') - '+ fr.document.compatMode+'\n'; } catch (e) { response+='Could not access this frame\n'; } checkFrames(fr); } } } checkFrames(window); alert(response);