Archive for the ‘CSS’ Category

* Surfin’ Safari

Posted on October 9th, 2008 by Dave Johnson. Filed under AJAX, CSS, JavaScript, XML, completeui, quirks, safari.


For the past little while I have been busy fixing up Complete UI to work in Safari. The big problem for us in getting Complete UI working in the WebKit powered browser was that there was no client side XSLT JavaScript API until Safari 3.

So there were a few things I had to update to get things all working properly - and this more or less applies to Chrome now as well but I need to check on a few things.

XMLDocument::selectNodes

The first problem I came across was using the XMLDocument::selectNodes method. To get selectNodes working I had to implement my own NamespaceResolver which is usually handled for you by the browser.

I had to change the call to the XMLDocument:evaluate method a bit to look like this:

var oResult = this.evaluate(
  sExpr,
  (oContextNode?oContextNode:this),
  new MyNSResolver(),
  XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
  null);

Where the MyNSResolver class essentially implements the lookupNamespaceURI method through a switch statement returning the appropriate URI for the specified namespace prefix. Pretty easy but kinda annoying to figure out!


function MyNSResolver() {};
MyNSResolver.prototype.lookupNamespaceURI = function(prefix) {
  switch (prefix) {
    case "xsl":
      return "http://www.w3.org/1999/XSL/Transform";
      break;
    case "ntb":
      return "http://www.nitobi.com";
      break;
    default:
      return null;
  }
}

XSLT Transformations

Then there was the actual act of performing an XSLT transformation. Doing the transformations was fine but getting the output node or string from the transformations - depending on if the <xsl:output /> was text, html or xml - was rather different than both Firefox and Internet Explorer. Go figure.

For transforming to an XMLDocument here is what I found to be the output of an XML transformation for the various output methods.

Text:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title></title>
  </head>
  <body>
    <pre>innerText</pre>
  </body>
</html>

XML:

<output>innerText</output>

HTML:

<html>
  <body>
    <output>innerText</output>
  </body>
</html>

XSLT Parameters

There is also one difference in how the Safari XSLT processor deals with parameters. Rather than casting true / false to 1 / 0 the Safari XSLT processor does not recognize true or false values and requires the inputs to be 1 / 0. I have started setting all my XSLT params like this:


oXsltProc.addParameter("paramName", val+0, "");

Events and Focus

There were some other small issues that I came across regarding implementing rich keyboard navigation and events in general.

For example, in our Grid component I had to change the HTML element that we used to “focus” the Grid so that we could capture key presses from a <DIV> to an <INPUT>. Apparently you can’t call Element:focus on a <DIV> element from JavaScript but you can on an <INPUT> (even with a tabIndex set but I try to avoid those for accessibility reasons anyhow).

However, that was not my only problem with keyboard navigation. The other problem was that the focusable element (the newly created <INPUT> in this case) was still not getting focus due to a small code snippet like this:


oMyInput.focus();
cancelEvent(evt);

That second line where I cancel the event (wrapped nicely in a cross browser library call) somehow prevents the <INPUT> from getting the focus. Never figured out a workaround aside from a browser check before calling cancelEvent.

CSS

Finally, in some of our components we also generate CSS using XSTL and dynamically insert it into the page. For example, the developer defined column widths in a Grid produce dynamically generated CSS. However, WebKit does not seem to support the bulk creation of stylesheets neither using the document.createStylesheet method of Internet Explorer nor the hacky way of doing in Firefox by creating a <STYLE&gt element and setting the innerText. Instead Safari requires that you use the uber slow DOM API for adding rules to stylesheets :(

Miscellany

You will often see the “xml namespace prefix mapped to wrong URI” error when working with XSLT in Safari.

Be careful that you are using double quotes in your XSLT for attributes etc and only use single quotes in attribute values.

Of course you also have to be very careful about the nodes that you are transforming / selecting as you are also likely to get the “WRONG_DOCUMENT_ERR” fairly frequently.

Oh yah and depending on the application expect a lot of random “Stack overflow” errors!

Tags: , , , , , , , .



* Internet Explorer StyleSheet Quirks

Posted on February 19th, 2008 by Dave Johnson. Filed under AJAX, CSS, InternetExplorer, JavaScript, quirks.


I have spent the better part of the past week fighting with the Internet Explorer 31 stylesheets limit.


http://flickr.com/photos/cassidy/2461135/

It came up when, thanks to the great performance of our Grid component, a customer wanted to have about 35 grids on a single page for a very complex ordering system. Now as is usually the case, by the time that people come to us to help them they usually have a pretty firm business case for their application and don’t want to change the overall information architecture and the like - so we had to figure out how to get 35 grids running in Internet Explorer.

The problem arises from the fact that for a live scrolling grid where blocks of data are dynamically inserted into the page as the user scrolls, each grid needs its own stylesheet since the column widths and a few other parameters are defined on a grid/column basis and need to be changed globally in a lot of cases; for example, when a column is resized we need to be able to just change one CSS rule and have the widths of all the relevant HTML nodes get updated.

The worst part is that there is even a difference between IE 6 and IE 7 - w00t. In IE 7 it has no problem with just creating one stylesheet and continually appending or overwriting that stylesheet. So that was a pretty easy fix to have a global stylesheet instead of one for each grid. Then comes IE 6… in IE 6 it seems that you can’t even write to the same stylesheet object more than 31 times (or some number around 31 I am not really sure).

So what was the solution for IE 6? We essentially had to make a registry of all the components on the page that keeps track of which components were done initializing and then when all the components are ready create one huge stylesheet and write the contents only that one time. Failing to use this approach meant that IE 6 would just crash.

The other approach that we of course considered was using addRule on the stylesheet object to inject each of the CSS rules into an existing stylesheet rather than writing the stylesheet. I quickly learned that addRule is ridiculously slow in IE. Something like on the order of 30ms to add a rule. So ~35 grids * 50 columns per grid * 30ms per addRule = way too long. Retarded.

We now almost have everything working with > 31 grids. Joy.

.



* How Does CSS Work?

Posted on January 14th, 2008 by Dave Johnson. Filed under AJAX, CSS.


I was just making some content for an Ajax video training series that Andre, Alexei and I are preparing for Prentice Hall as an extension of our book (Enterprise Ajax) and thought that I would just share this tidbit about CSS for those that have never really fully understood how it works but know enough to be dangerous.

CSS rules are applied using two approaches: inheritance and the cascade. So styles can be applied to certain elements through inheritance from styles of parent elements or by the battling of different styles based on cascade rules.

Cascade

The cascade is a bit more involved. There are three important aspects when the browser determines what styles get applied to what elements.

Origin

The first is the style origin. Styles can defined either by the web page author (Author), the person viewing the web page (User) or the application being used by the user to view the web page (UserAgent). The precedence rules for the origin are just that - Author, User, UserAgent - in order from highest precedence to lowest. Of course User specified styles can use the !important modifier on their styles to override Author styles.

Specificity

The second aspect of the cascade is specificity. The specificity is determined by how specific (go figure) the CSS selector rule is that matches a particular element. ID selectors are the most specific followed by selectors based on attribute values such as class names followed by selectors with element names in them - i.e. in order of precedence from highest to lowest we have #header {}, *.header {}, div {}. To get the specificity of a rule we count the number of ID selectors (call it “A”), the number of class or attribute selectors (call it “B”) and finally the number of tag names (call it “C”). Then we concatenate ABC and we come up with a final number like 321 and then compare all the rules for a style and highest number wins.

Order

Finally we have the style order. If we have multiple rules in the Author stylesheet for a page that all have the same specificity then the last defined style will win.

Inheritance

If the cascade does not result in a style being set, then inheritance may become important for the defining of an elements style.

Most CSS styles are not inherited. Background color, borders and the like are not inherited by default whereas line-height and fonts are. You can force a style to inherit by setting the value of the style to inherit as in background-color: inherit;. That’s really all there is to inheriting - just don’t get it mixed up with object oriented inheritance. If you feel like you want to do something along the lines of object oriented inheritance then remember that you can define multiple rules separated by commas such that those rules all use the same styles such as .header, .footer {font-face: arial;}.

For the entire story check out the official W3C site but hopefully this will help some people out there write more succinct and understandable stylesheets!

.



* Declarative Ajax with CSS

Posted on September 20th, 2007 by Dave Johnson. Filed under AJAX, CSS, JavaScript.


Those that have developed or used Ajax components to build an application will be familiar with the idea of using some sort of declarative structure to define or configure a component. This is commonly achieved through either HTML or JSON.

For example, a simple dynamic table or grid JavaScript object may take a parameter that sets the height of each row in the table. Through JavaScript it might look like this:

var myTable = new Table({”id”:”myTable”, “rowHeight”:”20px”,”data”:["dog","cat","bird"]});

This could in theory instantiate a dynamic table with rows of height 20px and contents as defined by the data array.

Everything is right in the world.

Class it up

However, there are some out there - I won’t name any names - that might prefer to set something a table row height through CSS instead. So rather than setting the rowHeight in the configuration directly they may instead just specify a rowClass that is the class that will be applied to each TR element in the table. Defining the table would then look something like this:

var myTable = new Table({”id”:”myTable”, “rowClass”:”tableRow”,”data”:["dog","cat","bird"]});

and the corresponding CSS would look like this:

.tableRow {height:20px;}

Now the only problem here is that there are situations where we may want to know what the height of the rows in the table are through the objects API. For example:

alert(myGrid.getRowHeight());

So the question is, how can we support using CSS as the declaration for a component (too bad you can’t just put any name/value pairs in CSS in Firefox :(
Bridging the API Divide

Luckily for us we have the DOM. In the Nitobi Toolkit it is pretty easy to find a class in a stylesheet and read properties from it. In our Grid control we do something like this for rowHeight such that it can be defined through an HMTL declaration or CSS and still be accessible through the API. We end up with some code like this:

var ntbRow = nitobi.html.getClass(”ntbrow”);
if (ntbRow != null && ntbRow.height != null)
  this.rowHeight = parseInt(ntbRow.height);

The getClass function essentially scours all the included stylesheets for rules that contain the class in question.

This solution makes the components more skinnable and easier to work with in general while at the same time preserving the JavaScript API.

.



* CSS Pseudo Class Madness

Posted on June 4th, 2007 by Dave Johnson. Filed under AJAX, CSS, InternetExplorer, quirks.


Through the course of building an Ajax Grid component we have come across many a quirk in both Firefox and Internet Explorer.

The latest thing we found was something that cropped up when we finally converted our Grid to support standards mode in Internet Explorer 6 and 7. To do this we had to fall back on a good blog post from a while back about the use of the table-layout: fixed; and white-space: nowrap; styles in creating an HTML table where the contents of the cells do not wrap if the contents are wider than the cell width.

Essentially what he came up with was that you needed the following:

      width: 0px; and table-layout: fixed; on the table
      white-space: nowrap; and overflow: hidden; on the cells
      and use <col> tags to specify the column widths but place them at the bottom of the table

How he came up with that last one I don’t know!

At any rate, that seemed all well and good; things were great in our small prototype in both quirks and standards mode. Then when we actually brought it into the product, it was not working at all in standards mode. Several hours and coffees / beers later I finally determined that there was some other completely unrelated CSS that was causing it not to work. The culprit was one of the great new CSS features of IE 7 - the pseudo class. We were using pseudo classes like :hover since it makes life much easier in a lot of cases so you don’t have to attach mouseover / mouseout handlers to some elements just to change a color.

So just having any :hover pseudo classes in the page would cause the nowrap behaviour of the table to fail! Even if they were on some random class that is not used with no contents inside the CSS rule, as soon as you move your mouse onto the web page the table layout reverts to not respect overflow: hidden; on the table cells. Check it out here in IE.

At that point I thought I was home free… clearly I had been sniffing too much of the Internet Explorer glue.

Once again I moved my code into the actual product and once again it did not work. At that point the only difference between the product and the prototype was one thing: in the product we use generated CSS. What we do is use XSLT to build a stylesheet with all the column widths etc and then insert it into the page using document.createStyleSheet(); and then set the CSS contents using stylesheet.cssText = myCSS;. Once again we were astounded (really???) at the crapness of IE 7.

In the end it came down to adopting the age old approach of placing div’s inside of each table cell and setting the overflow and white-space CSS properties on it. This really sucks since it dramaticall increases the number of elements in the web page and therefore can really slow down application performance.

In the past I have posted a few other interesting tidbits about using a:hover being bad as well as inline event definitions. We have recently found a really great problem in Firefox with calling focus() on an element that I will cover soon.

Tags: .



* Internet Explorer Standards Mode

Posted on January 12th, 2007 by Dave Johnson. Filed under CSS, DHTML, InternetExplorer, Web.


I love Internet Explorer. Today we discovered that in IE7 CSS pseudo classes like li:hover work fine in standards mode but not in quirks mode. What on earth were they smoking when they decided to add functionality to standards mode and not quirks mode? w00t!

.