Up to Speed with Opera 7

by Kenneth Tibbetts

Content and Control Opera has always had a lot going for it- great css support, fast rendering speed, and a small footprint on the client machine. The biggest gap between Opera and the major browsers (Mozilla Sea Monkey and Netscape 6+, and Microsoft's Internet Explorer) has been in accessing and scripting document objects. For the most part, a page in Opera could be fast and beautiful, but not especially dynamic. The gap is closing in Opera 7.

Writing for Opera

One thing Opera doesn't have is a very open development environment. It's hard to tell where the vendor is taking it. Is this 'feature' a bug, or is it intended? Is this method working the way it is always gonna work, or is it on somebody's to-do list? Most of Opera support is by way of user forums and listservs, which are mainly concerned with the interface, not what makes pages fail.

After a couple of weeks of road testing I've come up with a short list of gotchas- places where you can get into trouble if you aren't aware of certain Operatic peculiarities. This is not a big list- especially for the first beta of a new piece of software. Believe me, I have similar gotcha lists for the current IE and  Gecko Browsers. But since writing scripts that will run on Opera 7 is a new deal, it may be helpful to see some of the places where we can go wrong. It still, by the way, has more fake ids than a president's daughter, and testing Opera in all it's incarnations is beyond me. I work with Opera as Opera.  

ecmascript and the dom 

The first thing that will get you will probably have something to do with the way Opera handles null, undefined and empty string comparisons. At least for now it seems to be safest to treat those three values as not equal, and test for all three to avoid any problems. 

Opera 7 implements try-catch-finally error handling. This makes it easier to backtrace a problem in your code. Unfortunately, all of the browsers implement the error object in their own way, and Opera is even more so. We are on our own (again) when it comes to decyphering the error messages, and every browser counts lines differently.  But it can save you a lot of time when something isn't working.  

Opera 7 failed on some pages I hadn't expected, and a try-catch cornered a problem- the new browser doesn't support regular expression syntax as well as the majors do. Specifically it gagged on a look ahead assertion- a syntax like:
/\bw*\s*(?=\()/g;
which, when used in an exec or looping match should return word strings that are followed by an open parenthesis, without including the parenthesis in the match. 

I assumed if I got that far, past all kinds of detect and deter code, the client would be able to handle it. Opera found the strings OK, but returned the crap along with the values I was looking for. Well, I live and learn and learn and learn...

I once assumed that I could keep prevent a browser from running some document object code by guarding the call with an if (document.createElement) expression. For some reason, Opera 5 and 6 returned true and got past the guard, so it could immediately throw a runtime error when the method was actually called.  I cobbled the switch into document.createTextNode, which stumped the old Operas, but I never felt really comfortable with it. Opera is famous for knowing about an object but not the methods that knowlege implies. 

nodeLists and Objects

When you are manipulating a document, adding or removing elements, or changing the order of a document's elements, you often use the nodeSort returned from element.getElementsByTagName(tagname). But a nodeSort is live- it changes as the document changes. Sometimes you want a snapshot of a page to refer to. I got in the habit of copying the elements, one by one, from the nodeSort into an object that would serve as a reference. In the major browsers this was no problem, because the nodeSort was an object itself. Opera 7 surprised me by failing on such a page. After a bit of querying I realized that the nodeSort in Opera was being returned as a Function, and not as the more general Object I was writing for. It may be a small thing, but so is the nut that holds the propeller. It was enough to make me rewrite some code.

While I'm on the subject, Opera has its own way of handling Objects. The worst of it, from my prospective, is that some of the Objects that have always been enumerable are not so in Opera. You get errors if you try to run a for in loop that would return the navigator properties in another browser:

for(var o in navigator)str+=o+'('+typeof(o)+')='+navigator[o].

You can query any of the properties if you call them by name, but you can't enumerate them this way.

And you run into the same trouble if you try a for in loop on an element's style object. You can access each property by name, but you can't loop through them. Another page buster to work around.

Speaking of Style

Opera has always done a wonderful job at rendering pages with css styles, either inline or from stylesheets. It still has a couple of weaknesses- it does not support the cssText property, and it does not allow any reading or writing of the stylesheets, or access to the computed style of an element. None of these shortcomings will necessarily break a page, and you can read or write to any element directly through its inline style object. But be careful of the methods you have been calling. Opera is a game little critter, and will try anything that doesn't have a darn good fence around it. 

Here is another time that Opera 7 went around my code and busted a perfectly good page. I was using  another if gate. This time I needed to block browsers that couldn't handle the CSS2 getComputedStyle method for reading the actual displayed style of an element. I used it mainly to keep out IE, which has its own proprietory method for this (did I mention my other gotcha lists?). I tested for  (document.defaultView), figuring that a client wouldn't have this object in its beady brain if it couldn't use its methods.  

You guessed it- Opera somehow knows that document.defaultView is an object, got past my gate, and had brain failure. So I cobbled in another conditional, tripled the length of the gate code, and managed to keep Opera from hurting itself. I had a puppy once... 

All in all, Opera is very good at rendering CSS and CSS2 the way you want it to. Opera 7 finally allows you as much freedom with iframes as the big guys, including the src attribute. On the down side, a couple minor points-It does a poor job of changing the appearance of form elements once they are on the page. And Opera  has its own idea for the 'auto' size property value.

The other browsers will 'cinch up' a positioned element that has its width set to 'auto', so that it takes only as much room as it needs on the page. If you are not sure of the fonts or resolution of your visitors, it is handy to skip specifying the actual width of an element. Opera will use up all the horizontal space there is unless you give it a definite size. Not a page breaker, but annoying.

And this isn't a style problem, but Opera has always had this one- It is still ignoring scripting 'disabled' attributes on buttons and other elements. You can write the script, and read it back changed true or false, but the button doesn't give you any feedback, and it continues to pass events you associated with it, disabled or no. And just when Mozilla/Netscape almost has it right. Oh well.

Crashing Comments

Another page crash occurred on a page that I format on the user's screen. I take a large document and break it up into separate screen views, and build a toc and navigation bar along the way. I could not get that page to work in Opera 7. I couldn't even catch the error, it would crash before the error got handled. 

To make a long long story short, what was happening was that the browser was going through the document tree, node by node, and moving groups of elements to newly created 'divs' . Whenever the engine got to an html comment it crashed the browser. It couldn't handle moving the comments. I didn't have the problem in the other browsers, and I wasted about a day trying to 'fix' it in Opera, till it dawned on me that it didn't matter where the stupid comments were. They weren't going anywhere in the source! I added a quick test of the nodes as they get processed, and if they are nodeType ==8, or comments, I leave them in place.

Another surprise might come up on pages that use a keypress event. Opera has dozens of built in keyboard shortcuts, and allows the user to define his own. This makes capturing a keypress on the window or document a very elaborate proposition. The W3 hasn't yet come up with a recommendation for keyboard event handling, so don't hold it against Opera. Except for keyboard events, the code that works in Mozilla/Netscape/Sea Monkey for event handling will also work in Opera.

A weirder problem on the same page had to do with scrolling the window. Sometimes Opera was behaving nicely, and other times it would crash and burn, when it got to a window.scrollTo(0,0) instruction. I am still not a hundred percent sure about this one, but it seemed to crash when I changed a display property and then called scrollTo(0,0). In the page, you  get to the bottom of one view and click a 'next' button to hide that one and display the next. You then need to go to the top of the next 'page'.

The other browsers don't have a problem here, and in fact need the command or you find yourself  at the bottom of the new page after you click 'next'. With tears in my eye, I iffed out Opera for the scrollTo's following display changes. And paint me green and call me kermit- Opera scrolled to the top of the next page view without the scrollTo statement, exactly as the others do with the statement. This behavior may be intended, but it may change in the next release. If I put the scrollTo's in a separate function, after the display change, Opera seems to behave.

Several other types of script commands have the same pattern- Opera 7 crashed when I remove a node in the same function that made use of it, or if I insertBefore an element and then change the display of the reference element. So I have some work to do on pages I want to make Opera friendly, by moving calls that affect the display into their own little routines. 

I really would like to know how long that to-do list is. 

The thing is, all the problems I've found are fixable or work-aroundable, and without doing anything that breaks Mozilla or IE. There are a few if (Yankee.iz(Opera)) switches, but it's not bad at all, not for a new kid. 

I expect to find a few more gotchas, but I really do like the new Opera Browser. It is small, it is smart, it makes beautiful pages, and it is really, really fast. And when it is good, it is very, very good...

happy returns...

Kenneth Tibbetts

yankee@yankeeweb.net

www.yankeeweb.net/

December 9, 2002


Comparing CSS Support in Current Browsers

Browser Style Support