hacks.mozilla.org

Author Archive for Eric Shepherd

css transforms: styling the web in two dimensions

One feature that Firefox 3.5 adds to its CSS implementation is transform functions. These let you manipulate elements in two dimensional space by rotating, skewing, scaling, and translating them to alter their appearance.

I’ve put together a demo that shows how some of these functions work.

There are four animating objects in this demo. Let’s take a look at each of them.

Rotating the Firefox logo

On the left, we see the Firefox logo in a nice box, happily spinning in place. This is done by periodically setting the rotation value of the image object, whose ID is logoimg, like this:

  var logo = document.getElementById("logoimg");
 
  logoAngle = logoAngle + 2;
  if (logoAngle >= 360) {
    logoAngle = logoAngle - 360;
  }
 
  var style = "-moz-transform: rotate(" + logoAngle + "deg)";
  logo.setAttribute("style", style);

Every time the animation function is run, we rotate it by 2° around its origin by constructing a style string of the form -moz-transform: rotate(Ndeg).

By default, all elements’ origins are at their centers (that is, 50% along each axis). The origin can be changed using the -moz-transform-origin attribute.

Skewing text

We have two examples of skewing in this demo; the first skews horizontally, which causes the text to “lean” back and forth along the X axis. The second skews vertically, which causes the baseline to pivot along the Y axis.

In both cases, the code to accomplish this animation is essentially identical, so let’s just look at the code for skewing horizontally:

  text1SkewAngle = text1SkewAngle + text1SkewOffset;
  if (text1SkewAngle > 45) {
    text1SkewAngle = 45;
    text1SkewOffset = -2;
  } else if (text1SkewAngle < -45) {
    text1SkewAngle = -45;
    text1SkewOffset = 2;
  }
 
  text1.style.MozTransform = "skewx(" + text1SkewAngle + "deg)";

This code updates the current amount by which the text is skewed, starting at zero degrees and moving back and forth between -45° and 45° at a rate of 2° each time the animation function is called. Positive values skew the element to the right and negative values to the left.

Then the element’s transform style is updated, setting the transform function to be of the form skewx(Ndeg), then setting the element’s style.MozTransform property to that value.

Scaling elements

The last of the examples included in the demo shows how to scale an element using the scale transform function:

  text3Scale = text3Scale + text3ScaleOffset;
  if (text3Scale > 6) {
    text3Scale = 6;
    text3ScaleOffset = -0.1;
    text3.innerHTML = "It's going away so fast!"
    text3.style.color = "blue";
  } else if (text3Scale < 1) {
    text3Scale = 1;
    text3ScaleOffset = 0.1;
    text3.innerHTML = "It's coming right at us!";
    text3.style.color = "red";
  }
 
  text3.style.MozTransform = "scale(" + text3Scale + ")";

This code scales the element up and down between its original size (a scale factor of 1) and a scale factor of 6, moving by 0.1 units each frame. This is done by building a transform of the form scale(N), then setting the element’s style.MozTransform property to that value.

In addition, just for fun, we’re also changing the text and the color of the text in the block as we switch scaling directions, by setting the value of the block’s innerHTML property to the new contents.

Final notes

Three more tidbits to take away from this:

First, note that as the scaling text grows wider, the document’s width changes to fit it, getting wider as the text grows so that its right edge passes the edge of the document, then narrower as it shrinks again. You can see this by watching the scroll bar at the bottom of the Firefox browser window.

Second, note that you can actually select and copy the text not only while the elements are transformed, but the selection remains intact while the text continues to transform (although when we change the contents of the scaling example, the selection goes away).

Third, I didn’t cover all the possible transforms here. For example, I skipped over the translate transform function, which lets you translate an object horizontally or vertically (basically, shifting its position by an offset). You can get a full list of the supported transforms on the Mozilla Developer Center web site.

Obviously this demo is somewhat frivolous (as demos are prone to be). However, there are genuinely useful things you can do with these when designing interfaces; for example, you can draw text rotated by 90° along the Y axis of a table in order to fit row labels in a narrow but tall space.

using web workers: working smarter, not harder

This article is written by Malte Ubl, who has done a lot of great work with using Web Workers as part of the bespin project.

In recent years, the user experience of web applications has grown richer and richer. In-browser applications like GMail, Meebo and Bespin give us an impression of how the web will look and feel in the future. One of the key aspects of creating a great user experience is to build applications that are highly responsive. Users hate to wait and they hate those moments where an application seems to work for a while, then stops responding to their input.

At the core of modern client-side web applications lies the JavaScript programming language. JavaScript and the DOM that it talks to is inherently single-threaded. This means that in JavaScript only one thing can happen at any given time. Even if your computer has 32 cores it will keep only one of those cores busy when it’s doing a long computation.  For example if you calculate the perfect trajectory to get to the moon it won’t be able to render an animation that shows the trajectory at the same time and it won’t be able to react to any user events like clicks or typing on the keyboard while it’s doing that calculation.

Concurrency

To maintain responsiveness while performing intense computations concurrency is a part of most modern programming languages. In the past concurrency was often achieved by the use of threads. Threads, however, make it increasingly hard for the programmer to understand the program flow which often leads to very hard to understand bugs and chaotic behavior when different threads manipulate the same data simultaneously.

Web Workers, which were recommended by the WHATWG, were introduced in Firefox 3.5 to add concurrency to JavaScript applications without also introducing the problems associated with multithreaded programs. Starting a worker is easy – just use the new Worker interface.

In this example the worker.js file will be loaded and the a new thread will be created to execute that code.

// Start worker from file "worker.js"
var worker = new Worker("worker.js");

Communication between the main UI thread and workers is done by passing messages using the postMessage method. postMessage was added for cross-window communication in Firefox 3. To send a message from the worker back to the page, you just post a message:

// Send a message back to the main UI thread
postMessage("Hello Page!");

To catch the message from the worker, you define an “onmessage” callback on the worker object. Here we just alert the event data that is passed to the callback function. In this case, “event.data” contains the “Hello Page!” string that was sent above.

worker.onmessage = function (event) {
  alert(event.data);
  // Send a message to the worker
  worker.postMessage("Hello Worker");
}

To send a message to the worker we call the postMessage method on the worker object. To receive these messages inside the worker, simply define an onmessage function that will be called every time a message is posted to the worker.

Error Handling

There are two levels at which you can recover from runtime errors that occur in a worker. First, you can define an onerror function within the worker. Second, you can handle errors from the outside the worker by attaching an onerror handler on to the worker object:

worker.onerror = function (event) {
  alert(event.message);
  event.preventDefault();
}

The event.preventDefault() method prevents the default action, which would be to display the error to the user or at least show it in the error console. Here we alert the error message instead.

Shared Nothing

Workers share absolutely no state with the page they are associated with or with any other workers; the only way they can interact at all is through postMessage. Workers also have no access to the DOM, so they can not directly manipulate the web page. There is thus no risk of problems with data integrity when multiple workers want to manipulate the same data at once.

A standard setup that is using workers would consist of a page JavaScript component that is listening for user events. When an event occurs that triggers an intensive calculation a message is sent to the worker which then starts the computation. The script on the page, however, can terminate immediately and listen for more user events. As soon as the worker is done, it sends a return message to the page which can then, for example, display the result.


The unresponsive script warning that is being displayed by browsers when a script is taking a long time to execute is a thing of the past when using web workers.

The Fibonacci Example

Next is an example of a worker that calculates the Fibonacci numbers from 0 to 99 in the background. Actually, because calculating Fibonacci numbers using this very inefficient method can take a lot of time for larger numbers (as in greater than something like 30) the script might never finish on your computer (or crash because it blows out the stack), but when doing it in a worker this has no effect on the responsiveness of the main web page. So you can still draw a complex animation to make the waiting time for the next number a little more fun.

This HTML page contains a script that starts a worker from the file “fib-worker.js”. Messages from the worker are displayed on the browser’s console using console.log.

<!DOCTYPE html>
<html>
    <head>
      <title>Web Worker API Demo</title>
      <script type="text/javascript">
        var worker = new Worker("fib-worker.js");
        worker.onmessage = function (event) {
          console.log(event.data.index +" -> " + event.data.value)
        }
      </script>  
    </head>
    <body>
    </body>
</html>

The JavaScript file that implements the worker contains a loop that calculates Fibonacci numbers and sends the result to the page.

// File fib-worker.js
function fib(n) {
   return n < 2 ? n : fib(n-1) + fib(n-2);
}
 
for(var i = 0; i < 100; ++i) {
   postMessage({
      index: i,
      value: fib(i)
   })
}

In the example above we see that we can also pass complex objects to the postMessage. These objects can contain everything that can be transmitted via JSON. This means that functions cannot be passed across worker boundaries and that the objects are passed by value rather than by reference.

Worker APIs

Workers support a function called importScripts. You can use this to load more source files into the worker.

importScripts("file.js");
importScripts("foo.js", "bar.js");

When you pass multiple parameters to the function the scripts will be downloaded in parallel but executed in the order of definition. The function does not return until all scripts have been downloaded and executed.

Here we load an external JavaScript file that calculates SHA-1 hash sums from strings and then we use it to hash responses from AJAX requests. We also use the standard XMLHttpRequest object to retrieve the content of the URL which is passed in via the onmessage event. The interesting part is that we don’t have to worry about making the AJAX request asynchronous because the worker itself is asynchronous with respect to page rendering, so a little waiting for the HTTP request does not hurt as much.

importScripts("sha1.js")
 
function onmessage(event) {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', event.data, false);
    xhr.send();
    postMessage(sha1(xhr.responseText));
}

Other APIs Available to Workers

Workers may use XMLHttpRequest for AJAX requests as seen above and access the client sided database using web storage API. Here the APIs are identical to their usage in regular JavaScript.

The setTimeout and setInterval (and the clearTimeout and clearInterval friends) functions, which enable executing code after a given period of time or at certain intervals, are also available within the worker as is the well known navigator object, which can be inspected to get information about the current browser.

More APIs may be added in the future.

Browser Compatibility

As of this writing (and to the knowledge of the author), Firefox 3.5 is the only browser that supports the ability to pass complex objects via postMessage and that implements the extended APIs defined above. Safari 4 implements a very basic version of the Worker API. For other browsers it is possible to use Workers via Google Gears, which originally introduced the concept to browsers.

Real World Usage

In the Bespin project, which is a browser based source code editor, we successfully used workers to implement CPU intensive features like real-time source code error checking and code completion. We also created a shim that implements the Worker API in terms of Google Gears and which adds the missing features to the worker implementation of Safari 4 and also moved to using transparent custom events on top of the postMessage interface. These components will be released as a stand-alone library to be usable in other projects in the future.

Web Workers will play an important role in making the Open Web an even more powerful platform for sophisticated applications. Because in the end all they do is execute JavaScript, it’s easy to make scripts work on clients which do yet have the luxury of web workers. So go ahead and add them to your applications today to make them feel just a little more responsive and more pleasant to use.

slick tables with css 3 selectors

This article and demo come to us courtesy of Ivan Enderlin, author of the HOA Framework and longtime web developer.

This is the article that accompanies the demo below, showing the use of CSS3 selectors implemented in Firefox 3.5 for easy and stylish tables.

CSS3 Selectors for Quick and Pretty Tables

View the Demo | CSS3 Selectors for Quick and Pretty Tables


See this demo step by step.

Basic HTML Table

First, we start by writing a simple HTML table. Note: we do not have any classes or ids, which is what makes this all so fantastic:

<table>
  <thead>
    <th>...</th>
    ...
    <th>...</th>
  </thead>
  <tbody>
    <tr>
      <td>...</td>
      ...
      <td>...</td>
    <tr>
    ...
    <tr>
      <td>...</td>
      ...
      <td>...</td>
    <tr>
  </tbody>
</table>

And now, let us write some CSS to make the plain old table look a bit more stylish:

table {
    font: 90%/1.5em "Lucida Grande", Geneva,
                    "DejaVu Sans", "Bitstream Vera Sans", AnjaliOldLipi,
                    "Lucida sans", "Trebuchet MS", Arial, Verdana;
    text-align: center;
    border: 4px black double;
    border-spacing: 0;
    -moz-border-radius: 12px;
    -moz-box-shadow: #6a3d37 5px 5px 6px;
    -webkit-border-radius: 12px;
    -webkit-box-shadow: #6a3d37 5px 5px 6px;
    border-radius: 12px;
    box-shadow: #6a3d37 5px 5px 6px;
    background: #b59d5c
}

The use of border-spacing, border-radius and box-shadow properties make for a quick and easy way to inject a little beauty into the table.

First Selection

Now, we would like to style all the th tags. This is easy with CSS Selectors:

th {
    color: #fff;
    font-size: 110%;
    text-shadow: #6a3d37 2px 2px 2px
}

Reminder: if we write table th we intend to select all the th elements which are child elements of the the table element, and if we write thead > th, we intend to select all the th elements which are direct children of the thead element. Well, it was just a reminder :-)

More Nuanced Selection

The th tag represents a table header. We would like to select the first table header. Hmm… maybe we should use the first-of-type pseudo-class. It represents an element that is the first sibling of its type in the list of children of its parent element. So now we have:

 
th:first-of-type {
font-weight: bold;
font-style: italic
}

Even and odd rows

A recurrent problem with tables is: how to select even and odd rows? The solution is the nth-child() pseudo-class. All these pseudo-classes understand the an+b syntax — to select all the even elements, we use 2n; to select all the odd elements, we use the 2n+1 elements; to select all third elements, we use 3n. In other words, this matches the bth child of an element after all the children have been split into groups of a elements each.

So, let’s style the even and odd rows:

 
tr:nth-child(odd) {
    color: #e0d8cb;
    background: #474644
}
 
tr:nth-child(even) {
    color: #6a3d37
}

Padding on first and last columns

Now, we want to add a padding to the first and the last column. I remind you again that we do not have any classes or IDs, and that the number of columns is unknown.

The solution is the first-of-type and the last-of-type pseudo-classes. We select all the first and last th and td like this:

 
th:first-of-type,
td:first-of-type {
    padding: 0 0 0 4em
}
 
th:last-of-type,
td:last-of-type {
    padding: 0 4em 0 0
}

The two last rows

Now, we would like to combine many pseudo-classes (and introduce a new one).

Let’s say we would like to select row number 1, number 4 and number 7. The mathematical expression is not so simple as we hoped. The tips is to split our rows in groups of 3, like this: 3n. But, that will select rows number 3, 6 and 9. Almost there! In these groups, we will select the first element, so 3n+1 (or 3n-2 if you like to complicate things).

That’s good, but that will select a row in our two last non-opaque rows. Ideally, we should say: “select the first row of each groups of three rows, but not the last row (which will be selected, because the last is the 7th row).” Simple. We are going to use the not pseudo-class, combined with the last-child pseudo-class (or last-of-type, which also works here).

Thus:

 
tr:nth-last-child(-n+2) {
    opacity: .75
}
 
tr:nth-child(3n+1):not(:last-child) td {
    text-shadow: red 0 0 8px
}

The final source is:

table {
    display: table;
    font: 90%/1.5em "Lucida Grande", Geneva,
                    "DejaVu Sans", "Bitstream Vera Sans", AnjaliOldLipi,
                    "Lucida sans", "Trebuchet MS", Arial, Verdana;
    text-align: center;
    border: 4px black double;
    border-spacing: 0;
    -moz-border-radius: 12px;
    -moz-box-shadow: #6a3d37 5px 5px 6px;
    -webkit-border-radius: 12px;
    -webkit-box-shadow: #6a3d37 5px 5px 6px;
    border-radius: 12px;
    box-shadow: #6a3d37 5px 5px 6px;
    background: #b59d5c
}
 
th {
    color: #fff;
    font-size: 110%;
    text-shadow: #6a3d37 2px 2px 2px
}
 
    th:first-of-type {
        font-weight: bold;
        font-style: italic
    }
 
tr:nth-child(odd) {
    color: #e0d8cb;
    background: #474644
}
 
tr:nth-child(even) {
    color: #6a3d37
}
 
th:first-of-type,
td:first-of-type {
    padding: 0 0 0 4em
}
 
th:last-of-type,
td:last-of-type {
    padding: 0 4em 0 0
}
 
tr:nth-last-child(-n+2) {
    opacity: .75
}
 
tr:nth-child(3n+1):not(:last-child) td {
    text-shadow: red 0 0 8px
}


View this demo step by step
.