Fluid Grids, Vertical Rhythm, and CSS Blocking

by Zack Grossbart on January 4, 2010

Here at Novell we’re working on a new reporting tool. It’s a web-based application with GWT and a little JQuery on the client side. On the server side, the tool uses Java servlets. It also uses REST for all communication between the browser and the server.

We’re investing in a new code base and we want it to grow into the future. Our framework must be maintainable and extensible. It also needs to welcome new programmers. In this article I’ll show you some of the styling guidelines we developed to make that happen. I’ll also show you the general CSS layout of the reporting tool and how we let customers customize that layout.

Our first step was creating a set of rules that made sure our lofty goals became reality.

Rule 1. Simple HTML

GWT is well-known for generating complex HTML. Seemingly simple widgets often generate many layers of extra tags. Generated code is always more complex than what you could write by hand. This complex HTML causes slow pages, complex CSS, and makes it difficult to style the UI. It also makes it very difficult for customers and partners to understand the DOM structure and customize the CSS.

Creating simple HTML from GWT requires some upfront planning, a willingness to create custom GWT widgets, and a tags first approach to GWT. It also requires a decent knowledge of CSS.

Rule 2. All layout in CSS

Making your HTML tags simple keeps your CSS simple. It also encourages you to push all layout logic into the CSS. This is important because CSS layout is much more powerful than HTML layout and separating layout and implementation keeps the code cleaner. Putting all the layout into CSS also makes it easy to customize the layout without recompiling.

Rule 3. No FlexTable

FlexTable is a common GWT class for simple form layout. It makes prototypes easy and gets your UI up and running fast. It’s also a major GWT anti-pattern.

FlexTable generates table tags for form layout. Tables work well for tabular data, but I’d rather use the right tool for the job. Tables are very limited in their layout functionality, difficult to customize, and notoriously hard to maintain.

We are committed to simple, accessible forms in the reporting tool and that means no FlexTable.

Rule 4. All images in CSS

The GWT compiler automatically creates CSS sprites. It stitches different images together at compile time and uses JavaScript to generate inline CSS that references those images. CSS sprites make the application load faster by eliminating extraneous HTTP requests. Abandoning CSS sprite generation was tricky, but we decided that customizing the reporting tool without recompiling is important.

That lead us to rule number four, all images should be referenced from CSS. That doesn’t preclude us from creating CSS sprites with external tools, but it means we can’t have the GWT compiler do it for us. This way, customers can completely change the colors, branding, and layout with just the CSS.

We also added an easy way to customize our CSS without editing our WAR file. I’ll get to that later in this article.

Rule 5. Love the grid

Graphic designers and typographers have use grids to make their designs clean and consistent for hundreds of years. They’ve become very popular on the web in the last few years. Grids are everywhere.

The reporting tool is based on a fluid grid. That means the grid changes size depending on the size of the browser window. Every browser is the perfect size for the reporting tool.

155 with 20 forever

Our fluid grid uses 155-pixel-wide columns with 20 pixels of space in between. These columns start on the left side of the page and continue forever toward the right side. Since our UI resizes, the column model breaks down a little bit on the right side of larger screens.

When we add new elements to the UI we can use the grid to align them into columns. For example, the navigation bar will line up with the footer text. The grid gives the entire page layout a sense of purpose.

Grids also make our application easier to use. The different pages in the application all feel familiar to the user. When they switch to a new screen they spend less time trying to understand it and more time doing real work.

Vertical rhythm

The grid handles the horizontal columns of our layout, now let’s look at the rows. Our rows use a pattern of 12/14. That means we are using a 12 pixel font size with a 14 pixel line height. These numbers define the vertical rhythm of our UI.

The rhythm provides a guide to make all of our text and other elements line up. For example, if you add a title using a 48 pixel font size then you make that line height 56 pixels tall because 14 times 4 makes 56. Your line height should always be an integer multiple of 14.

When you add an image or a form control you adjust the spacing around it so that the total height of the element is an even multiple of 14. The separator in our navigation bar is a good example.

The text in the navigation bar is 18 pixels tall so the line height is 28 pixels. We’re also using a separator image that is 15 pixels tall. For that image we use a top margin of five pixels and a bottom margin of eight pixels. 5 + 15 + 8 = 28 and 28 / 2 = 14.

GridFox

There is a nice FireFox extension for checking the grid called GridFox. The entire reporting tool UI team uses GridFox to make sure we stick to the grid. If you’re curious, this is our GridFox configuration:

Note the value for the column widths. This value is “155, 20″ repeated about a dozen times. The number of times you need it depends on the width of your browser window. I know this is a little hacky, but GridFox doesn’t really support fluid grids.

The grid might seem a little restrictive, but it actually makes it easier to create new designs. The grid is our metronome. It helps us stay in rhythm, even when we’re improvising.

CSS blocking

Now that we’ve looked at some of the general principles of the reporting tool UI let’s put them into action. The reporting tool follows a common UI pattern with a header, navigation bar, content area, and footer. These are all positioned out using CSS.

These basic blocks have some fixed dimensions, like the height of the header and footer or the width of the navigation bar, and many fluid dimensions. Most blocks grow to fill the browser window.

The blocks are also set up with a strong separation of layout. Our intention is that making changes to a single block should only affect that block. If you change the header layout you don’t want to accidentally break the footer.

Each block uses a different internal layout scheme.

  • The header uses absolute positioning to set the logo, Novell logo, and actions blocks.
  • The navigation bar uses list items and div to provide a programmable tree menu structure.
  • The footer is just a string of text with some span elements for styling.
  • The main content areas use different layouts depending on which item is select in the navigation menu.

These blocks provide a framework we can build on. For example, the error log can align to the top of the footer and expand upward as needed.

CSS file structure

The styles for the reporting tool are defined in five different style sheets in a very specific order.

NovellGWTLib.css contains the styles for the shared GWT library project. It provides common widgets and utilities we use in the reporting tool.

base.css is where most of our CSS goes. It contains our cross-browser CSS. It also uses YUI 2: Reset CSS to get a standard starting point across all browsers.

edcal.css comes from an open source editorial calendar for WordPress. We are using this calendar for one of the panes in the reporting tool.

platform.css is actually served with a servlet. This servlet detects the user’s browser and returns a special stylesheet for just that browser. Right now it supports:

  • FireFox 2.x
  • FireFox 3.x
  • Internet Explorer 7
  • Internet Explorer 8
  • Chrome 3

There are patterns to include browser-specific styles without using a servlet, but using a servlet gives us a clean and clear mechanism with a small number of HTTP requests. Most of these files contain only one or two style rules.

custom/custom.css doesn’t have anything in it yet. This is another servlet that serves the contents of a CSS files from outside of our WAR. Customers can edit this file to override any of our styles or completely customize the look and feel of the reporting tool. This is a big part of why we invest the time and effort to make the report tool CSS easy to use.

All five of these files are referenced in idmrpt.css. That file contains import statements for all the rest. This gives us a single place to reference all of the CSS files and keep them in order.

Is it worth it?

You might look at this and think we went overboard. Many people have created user interfaces with a lot less work. They don’t look as good, but does it matter?

We think UI matters. It changes the way people think about your products, how they use it, and ultimately how much they buy. Not convinced? Check out the story of the $300 Million Button. UI really matters.

In addition to making the UI better, this work also makes it more maintainable. Eliminating tables tags and keeping our HTML simple makes it possible for us to make quick changes. You can judge a system by how well it adapts to changes, and this system moves, grows, and adapts very well.

{ 0 comments }

Calling REST from GWT with a little bit of JQuery

by Zack Grossbart on December 21, 2009

GWT is gaining in popularity as an alternative to JavaScript. It’s a little larger and a little more difficult to deal with, but it’s type safe and makes it much easier to write maintainable code.

GWT even extends that type safety to AJAX calls with a built-in RPC mechanism. It wasn’t until I passed an object from client to server with the ease of GWT that I truly understood its appeal.

And that’s why using REST with GWT drives me a little crazy. When you call REST endpoints from GWT you lose type safety and the nice RPC mechanism. You’re also left parsing JSON in GWT which is much clunkier than dealing with it directly in JavaScript. I’ve heard that Google is thinking of adding a REST mechanism for GWT-RPC, but I can’t see how it would ever handle generic JSON data from a generic REST endpoint.

For a new project I’m working on I created a simple pattern to make REST calls from GWT with AJAX and a little JQuery. You still have to parse the JSON, but you only do it in one place and you get a very simple type safe API at the other end. Let’s take a look.

A little bit of JQuery

We’ll start with the generic JQuery AJAX call $.ajax. This simple function is very flexible and even more powerful. It can get you in a little trouble if you aren’t careful.

GWT has a RequestBuilder object that also makes AJAX requests, but it doesn’t support HTTP PUT or DELETE which are commonly required in REST calls. Without them you’re stuck using the JAX-RS extension mechanism which isn’t widely supported by REST endpoints.

Let’s look at some code.

callREST: function(/*string*/ restUrl, /*string*/ data, /*string*/ method, /*string*/id) {
    if (!data) {
        data = "";
    }

    if (!method) {
        method = "GET";
    }

    jQuery.ajax( {
        url: restUrl,
        type: method,
        data: data,
        processData: false,
        timeout: 100000,
        dataType: "text",
        success: function(res) {
            com_novell_idm_rpt.doRESTCallback(res, id);
        },
        error: function (XMLHttpRequest, textStatus, errorThrown) {
             if (XMLHttpRequest.responseText) {
                 com_novell_idm_rpt.doRESTErrorCallback(XMLHttpRequest.status, XMLHttpRequest.responseText, id);
             }
        }
    });
}

This generic wrapper to the JQuery ajax function gives us everything we need to call REST. It also provides a single entry point to all of our REST calls. That makes it easy to add security, logging, or debugging later.

Calling JQuery with GWT

Calling JQuery from GWT is simple with the GWT JavaScript Native Interface. The call looks like this:

private static native void doCallREST(String url, String data, String method, String id)/*-{
    $wnd.com_novell_idm_rpt.callREST(url, data, method, id);
}-*/;

It’s worth noting that all of this JavaScript is inside a Java block comment. That’s how a GWT Java file can contains JavaScript code and still be valid Java. Block comments aren’t a nice place to write code so I always try to make my JSNI code as small as possible.

Calling GWT from JQuery

The code we’ve looked at so far is enough to call a REST API. Now we need to get the response and pass it back to GWT. This is tricky since the response has to go out over the network and will take a little while. JQuery gives us a nice callback function to handle this called success. When that happens we need to call back into the GWT code so we can process the response. That’s where it gets a little complicated.

The problem is we can’t call directly from JQuery back to GWT. GWT has to set up the function for us. The first step is to define pointer placeholders for the functions.

var com_novell_idm_rpt = {
    doRESTCallback: null,
    doRESTErrorCallback: null,
    callREST: function(/*string*/ restUrl, /*string*/ data, /*string*/ method, /*string*/id) {
    ...

We set up the two variables doRESTCallback and doRESTErrorCallback to give our GWT code a place to add the functions.

Now that we have a placeholder we define a method in GWT to add the JavaScript functions there.

final class RESTility {

private static final RESTility RESTILITY = new RESTility();1
private final HashMap m_callbackMap = new HashMap();

static {
    createJSFunctions(RESTILITY);2
}

private static native void createJSFunctions(RESTility util)3 /*-{
    $wnd.com_novell_idm_rpt.doRESTCallback = function(res, id) {
        util.@com.novell.idm.rpt.client.client.rest.RESTility::restCallback(Ljava/lang/String;Ljava/lang/String;)(res, id);
    }

    $wnd.com_novell_idm_rpt.doRESTErrorCallback = function(status, res, id) {
        util.@com.novell.idm.rpt.client.client.rest.RESTility::restErrorCallback(Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;)(status, res, id);
    }
}-*/;

public void restCallback(String response, String id) {4
    RESTCallback callback = RESTILITY.m_callbackMap.remove(id);
    assert callback != null;

    callback.onSuccess(JSONParser.parse(response));
}

public void restErrorCallback(Integer status, String response, String id) {5
    RESTCallback callback = RESTILITY.m_callbackMap.remove(id);
    assert callback != null;

    callback.onError(status.intValue(), response);
}

There’s a lot going on here, let’s go through it step by step. We have a utility class called RESTility. I stole the name from the new YaST/Web project which is also part of Novell. This utility manages the round-trip to JQuery for us.

The RESTility class is mostly static methods, but we need an object instance so GWT can do the callback. We maintain one instance1 using a singleton model. We use that singleton instance to make the method call to create our JavaScript functions2.

The createJSFunctions method3 adds the functions we will call back from JQuery. It uses a complex syntax, but that is just so the GWT compiler knows how to generate the code it needs to call the restCallback4 and restErrorCallback5 methods.

The body of the doRESTCallback and doRESTErrorCallback function has that one long line with the @ symbol. This is the way we tell GWT how to call our GWT code from JavaScript. We reference the object name, then the package of our class, then the type of each of our arguments, and finally the argument values. I know this is a little complex, but we only need to do it twice.

Now our JQuery code can call back into GWT using a simple function call.

success: function(res) {
    com_novell_idm_rpt.doRESTCallback(res, id);
}

Callbacks

You might notice in the previous code that we have a HashMap and we’re passing around an ID. We want to make this mechanism available for multiple calls at once so we define the RESTCallback interface.

interface RESTCallback {
    public void onSuccess(JSONValue val);

    public void onError(int statusCode, String errorResponse);
}

This allows many objects to use our RESTility class and gives us a way to call them back. These kinds of callbacks are very common in JavaScript where you are dealing with network latency and don’t have a first class threading model.

So far our code path takes the following steps:

  1. Setup the GWT callback functions for JQuery
  2. Call the callREST JQuery function
  3. Call back the GWT code
  4. Return the JSON value of the REST call back to the listener

We now have a mechanism that will call REST from GWT, support HTTP PUT and DELETE, and get the JSON data back to GWT. The next step is to turn that JSON data into a type safe JavaBean.

Making JavaBeans from JSON

When the callback gets the JSON data it needs to turn it into a type safe JavaBean. This is an error-prone process so we only want to do it in one place in our code. That means we’ll need another layer of abstraction that just knows about objects and doesn’t pass JSON data out into the rest of our code.

public interface RESTObjectCallBack {
    public void success(T o);

    public void error(String message);
}

The RESTObjectCallBack interface gives us a type safe generic way to call back and pass our parsed object. Once we have this interface we can define a static method that takes the interface, parses the JSON, and returns the populated JavaBean.

It’’s easy to combine the JavaBean and the JSON parsing into one class. I defined a class named Reports with the fields name, date, and time. It also defines a static function to parse the JSON and return the JavaBean called loadReports.

public static void loadReports(final RESTObjectCallBack callback) {
    RESTility.callREST("/IDMRPT-CORE/reports", new RESTCallback() {
            public void onSuccess(JSONValue val) {
                Reports reports = new Reports();

                JSONArray reportsArray = val.isArray();
                for (int i = 0; i < reportsArray.size(); i++) {
                    JSONObject rval = reportsArray.get(i).isObject();
                    Report report = new Report();
                    report.setName(rval.get("name").isString().stringValue());
                    report.setTime(rval.get("time").isString().stringValue());
                    report.setDate(rval.get("date").isString().stringValue());

                    reports.addReport(report);

                }

                callback.success(reports);
            }

            public void onError(int statusCode, String errorResponse) {
                callback.error(errorResponse);
            }
        });
}

Putting it all together

GWT-REST diagram

  1. The Reports bean calls RESTility.
  2. RESTility (written in GWT) calls callREST JQuery to execute the AJAX call.
  3. JQuery calls the REST endpoint.
  4. The end point returns data that is caught in the success function from JQuery.
  5. We call the GWT REST callback from JQuery.
  6. The GWT REST callback gives the final data back to the Reports JavaBean.

Does it work in the real world?

A big benefit of this mechanism is the support for HTTP PUT and DELETE. JQuery gives you access to these HTTP methods, but it requires support from the browser to make it work. So far I’ve tested this successfully with:

  • Firefox 2
  • Firefox 3
  • Firefox 3.5
  • Internet Explorer 7
  • Internet Explorer 8
  • Chrome 3
  • Safari 4.0.4

I’ve also tested it on Windows, Linux, and Mac. I don’t have a copy of IE 6 to test with, but if anyone else does please let me know how it turns out.

Is it worth it?

I know this mechanism seems a little convoluted, so let’s look at some of the benefits.

Typesafe code. Let’s not forget that this is all type safe. That means the GWT compiler can find many of our errors at compile time. That’s important because compile-time errors happen at 10:00 AM in your office and run-time errors happen at 3:00 AM in your customer’s server room.

PUT and DELETE support. Avoiding the JAX-RS extensions is worth a lot and most REST APIs require HTTP PUT and DELETE.

A simple API. Let’s not forget that this call can be used over and over again. So what does it look like to call a REST endpoint from GWT?

Reports.loadReports(new RESTObjectCallBack() {
    public void success(Reports reports) {
        Window.alert("our reports: " + reports);
    }

    public void error(String message) {
        Window.alert("error: " + message);
    }
});

That is all it takes. It’s even easier than calling GWT-RPC.

Should we just write the whole thing in JQuery? JQuery is the best technology for many applications, but many JQuery applications suffer from poor error handling with JSON data. This pattern gives us a single place to handle JSON data and turn it into a type safe object.

Writing JQuery code is fast, and that’s always appealing, but most of the cost of software comes from code maintenance. It doesn’t matter how fast you can write the code if you can’t change it easily.

Update, Removing the JavaScript

After some of the great responses to this article I did a little more investigation into GWT and I found two interesting facts.

1. When GWT converts JavaScript values into GWT objects it calls the JavaScript eval function. This is problematic because the eval function could run arbitraty JavaScript. From the JSLint documentation:

The eval function (and its relatives, Function, setTimeout, and setInterval) provide access to the JavaScript compiler. This is sometimes necessary, but in most cases it indicates the presence of extremely bad coding. The eval function is the most misused feature of JavaScript.

2. GWT RequestBuilder does support HTTP PUT and DELETE. It blocks them by default because of a Webkit bug on Safari on Mac, but that bug has been fixed. All you need to do is extends RequestBuilder to make this work.

class RESTRequestBuilder extends RequestBuilder {
    public RESTRequestBuilder(String method, String url) {
        super(method, url);
    }
}

Combining these two pieces of information I removed all of the JavaScript and implemented the REST call using RequestBuilder. This gives us more type safety, skips the eval function, and makes the code smaller.

{ 7 comments }

Creating a JQuery Powered Posts Calendar for WordPress

November 21, 2009

Hackito Ergo Sum was my first blog and I never intended to post regularly. I write a long article every few months and when I’m happy with it I post it. Often in the middle of the night.

Then I started a new blog and wanted [...]

Read the full article →

Give Your Next Presentation In Your Browser With JQuery

November 5, 2009

I’d rather watch linoleum curl than sit through one more robotic technology presentations. A monotone drone over poorly organized slides turns even the most interesting topics sour. There are many great blogs about giving better presentations. Presentation Zen and the Duarte Design blog are two worth reading. I’ve even written a little [...]

Read the full article →

My New Book The One Minute Commute

October 8, 2009

Some of you may have heard that I’m writing a book called The One Minute Commute. It shows all the great work software engineers do to make remote teams successful and tells people how to use the lessons we’ve learned in their companies.
I also started a new blog to support that book. [...]

Read the full article →

Create Your Own Sliding Resizable Grid

August 12, 2009

I’ve focused on web programming for a while now, but I still miss GridBagLayout. GridBag is a Java layout manager and one of the best form layout managers I’ve used in any language. It makes it possible to create forms where any screen size is the perfect size.

[...]

Read the full article →

5 GWT Anti-patterns

July 11, 2009

As GWT evolves into a senior technology we are developing some good patterns for writing applications and finding some anti-patterns too. This article presents five GWT anti-patterns that are short-term gains and long-term losses. They are found in many applications, and even some of the GWT documentation, but they [...]

Read the full article →

Dynamic Grid Layout In JavaScript

June 6, 2009

You don’t see layout managers much in web applications. Most web pages are positioned with a combination of CSS and <table> tags. Higher end sites are switching to totally CSS based layouts, but it is still a [...]

Read the full article →

Tags First GWT

May 31, 2009

The Google Web Toolkit (GWT) speaks to all the Java programmers left petrified by the thought of web programming. GWT has a siren’s call: forget about cross browser issues, don’t bother with JavaScript, stay away from HTML. In reality, GWT requires deft piloting to stay off the rocks.

[...]

Read the full article →

JSONP and The Same Origin Policy

April 18, 2009

AJAX connections from JavaScript are a little technology that is revolutionizing the Internet, but they have a severe limitation with the same origin policy. In Java, C++, C#, or any other fat client language I can call out to any server I want, but not in JavaScript.

Calling out to other [...]

Read the full article →