Sencha Inc. | HTML5 Apps

Blog

Migrating Styles & Themes from Ext GWT 2 to Sencha GXT 3

August 22, 2012 | Tony Stuart

Background

In Ext GWT 2, component styles were defined in a single large CSS file. Developers could extend or redefine the styles in this file to control the appearance of a component or define a custom theme. Although this made it easy to give components a new look, it was hard to determine the relationship between the styles in the CSS file and the components in the library. Furthermore, there was no assurance that all of the styles in the CSS file were needed, or that the styles needed for a particular component were actually defined in the CSS file.

Let’s say you wanted to determine whether a particular style was no longer used and could be removed from the CSS file. The easiest approach would be to search the Java source files for string literals containing the style class name. However, there’s a catch. Not all of the class names occur as string literals. Some are generated dynamically (e.g. through string concatenation or template formatting), as the following simplified snippet from the Ext GWT 2.2.5 DataList.java illustrates:

 
StringBuffer sb = new StringBuffer();
sb.append("<table id='{id}' class='{style}'><tbody><tr>");
sb.append("<td class='{style}-l'><div>&nbsp;</div></td>");
sb.append("<td class='{style}-icon' style='{icon}'></td>");
sb.append("<td class='{style}-c'><span class='{style}-text'>{text}</span></td>");
sb.append("<td class='{style}-r'><div>&nbsp;</div></td>");
sb.append("</tr></tbody></table>");
 

As you can see, the style class name is generated dynamically by taking the value of the style property and concatenating an -l, -icon, -c, -text or -r to it.

These types of things make it difficult to generate style cross references, and without style cross references it is hard to maintain the CSS files for a large project. You can’t tell what will be affected by changing a style, nor can you tell whether a style is unused and can be removed. And even if the style is no longer used in Sencha code, it may still be used in customer code, meaning Sencha can’t remove it without the risk of breaking something. The result is that it is generally safer to add a new style, and CSS files grow over time.

To appreciate the scale of this problem, consider that gxt-all.css, the main stylesheet for Ext GWT 2, contains over 7,000 lines, with over 1,500 style rules that reference more than 800 unique class names, of which over 400 cannot be found as string literals in the java source files. Clearly, a new approach was needed.

The Appearance Pattern

In 2011, Google unveiled the GWT Appearance Pattern. The Appearance Pattern defines the contract between the component and how it looks on the screen (its appearance). This pattern offers many benefits for developers who define or style widgets, enabling them to:

  1. Replace the style of a widget
  2. Replace the DOM structure of a widget
  3. Reskin an entire application
  4. Isolate CSS code for each widget
  5. Ensure CSS styles defined are used
  6. Inject only CSS that is actually used
  7. Use conditional CSS and hide browser differences
  8. Encourage a separation of concerns

Much of the power of the Appearance Pattern is derived from its use of the GWT ClientBundle and CssResource interfaces. These interfaces work with the GWT generator feature to make it easy to manage client resources.

ClientBundle is the umbrella and provides a means of bundling content and sending it efficiently to the client. This content can include images, text files, generated URLs and CSS resources.

CssResource provides the CSS resource support for ClientBundle. It includes a powerful CSS preprocessing capability with image spriting, conditional processing, named constants and function calls. The conditional processing can utilize both deferred binding properties, such as the browser type, as well as values that are returned by function calls that are evaluated on the client at the point the styles are injected.

CssResource defines a one-to-one mapping between CSS class names and Java method names. Style classes that do not have a corresponding method trigger a compilation error. This makes it easy to detect missing style rules or styles that are not used, and is consistent with the Java approach in general: strongly typed methods and compile-time errors instead of runtime errors. When used with a modern IDE, you also get support for cross references as well as code completion (which eliminates typos that can occur easily in string literal class names).

So, to net it out, the Appearance Pattern brings Java-style strong typing to HTML and CSS. Although the Appearance Pattern requires some additional initial effort to use, it pays off in the long run due to reduced total development and maintenance costs.

See GXT 3 Appearance Design for more information on how GXT 3 components use the Appearance Pattern. Note that the Appearance Pattern addresses both the structure and the style of the component. In this blog we focus on the style.

Migration: a complete example

Now that we’ve seen some of the issues with the Ext GWT 2 approach to styles as well as some of the benefits of the GXT 3 use of the Appearance Pattern, let’s take a look at how to migrate styles and themes from Ext GWT 2 to GXT 3. In the following sections, we provide an example, starting by creating Ext GWT 2 custom styles for a simple application and then migrating to the GXT 3 Appearance Pattern.

Styling a Ext GWT 2 application

Let’s start by creating a simple set of Ext GWT 2 custom styles. We will use the trial and error approach. It consists of using a browser based web development tool like Firebug to inspect and modify the styles of a running application, recording the changes that produced a desired result until no remnants of the previous style are visible. This approach is fraught with peril: you only style the parts of each component that you know to visit, you may not appreciate how each class contributes its own styles to the hierarchy, and you are exploiting an internal interface. However, it can be done simply by trial and error, without really knowing the details, and it doesn’t require recompiling the application, so this approach was popular and there are many successful applications that were developed this way.

Here’s an example of how it works:

Open the application in the browser

Here we’ve written a simple application that displays a single ContentPanel in the default style provided by the blue theme:

Blue Theme ContentPanel

Start Firebug and display the HTML and Styles

Here we see Firebug with the HTML and Styles views open. You can use any web application development tool for any browser. We’ve used the inspect element feature to view the HTML and styles for the ContentPanel header:

ContentPanel header inspection

Modify a style and check the result

Use the Style view to modify the CSS for the selected element to see what effect each style contributes to the user interface. Here we’ve found that by changing the x-panel-header background-image to a new image we can get a red gradient instead of the default blue gradient:

Changing x-panel-header background-image from blue to red

Define style rules

Repeat this process until you track down all of the related bits of blue style. Then create a stylesheet that selectively overrides the default style rules with a new rule for each change you made:

 
.x-panel {
        border-color: #800000;
}
 
.x-panel-header {
        background-image: url("headerBackground.png");
        border-color: #800000;
        color: #200000;
}
 
.x-panel-body {
        background-color: #fff0f0;
        border-color: #800000;
}
 

Add a link to the new stylesheet to the project HTML

To permanently associate the styles with the component, add a link to the new stylesheet to the project HTML:

 
<!doctype html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Gxt2Style</title>
<link rel="stylesheet" type="text/css" href="resources/css/gxt-all.css" />
<link rel="stylesheet" type="text/css" href="RedTheme.css" />
<script type="text/javascript" language="javascript"
    src="gxt2style/gxt2style.nocache.js"></script>
</head>
<body>
    <iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1'
            style="position: absolute; width: 0; height: 0; border: 0"></iframe>
</body>
</html>
 

Try out the new style

Refresh your browser page and the ContentPanel with the new style appears:

Refreshed ContentPanel with new style

Styling a GXT 3 application

Now that we have a ContentPanel that is styled with a set of Ext GWT 2 styles, let’s see what we need to do to utilize the Appearance Pattern for GXT 3.

Specifying an appearance

Recall that with the Appearance Pattern, the appearance of a component is separate from the component itself. How does an application tell a component which appearance to use? There are two possibilities: via configuration (in the GWT module XML file) or via constructor arguments. Components generally have multiple constructors, one set that creates the component with a default appearance (possibly modified by a configuration in a module file) and one set that allows the caller to pass a custom appearance.

Finding existing appearances (package organization)

So to create a new GXT 3 appearance for a custom style we need to implement an appearance and either configure it in a module file or pass it to the constructor. But how do we implement an appearance, and which one? Let’s see how the library does it. Since we’re styling a ContentPanel we need to look for ContentPanel appearances. A quick search turns up several hits.

 
com.sencha.gxt.theme.blue.client.panel
        BlueContentPanelAppearance.java
        BlueContentPanel.css
        BlueHeaderAppearance.java
        BlueHeader.css
 
com.sencha.gxt.theme.gray.client.panel
        GrayContentPanelAppearance.java
        GrayContentPanel.css
        GrayHeaderAppearance.java
        GrayHeader.css
 
com.sencha.gxt.theme.base.client.panel
        ContentPanelBaseAppearance.java
        ContentPanel.css
 
com.sencha.gxt.theme.base.client.widget
        HeaderDefaultAppearance.java
        Header.html
 

We see that there is a ContentPanelBaseAppearance as well as two derived classes, BlueContentPanelAppearance and GrayContentPanelAppearance. This approach is common throughout the GXT 3 library: appearance aspects that are common to all themes are factored out into a base class, while theme-specific derived classes provide just the deltas necessary to complete the appearance. We also see that the header is styled separately from the remainder of the panel.

Deriving a new appearance

So now the question is, where does the new appearance fit into the class hierarchy? If it was an entirely new appearance, with both HTML structural and CSS style changes, we could create an alternative to ContentPanelBaseAppearance. But really, we just have a new red appearance that is very similar to the blue appearance. Therefore, we can use the blue appearance as a model and create a separate set of files for the red appearance:

 
com.example.gxt3.style.client.theme.red
        RedContentPanelAppearance.java
        RedHeaderAppearance.java
        headerBackground.png
        RedContentPanel.css
        RedHeader.css
 

Then its a matter of updating each file to use the new red styles. Let’s take a moment to step through the changes needed for each file:

RedContentPanelAppearance.java and RedHeaderAppearance.java contain the wiring that makes the Appearance Pattern work. Generally, the base classes do most of the real work and the derived classes, which we’re modifying here, provide only the necessary customization for a particular theme. In our example, it is simply a matter of changing names containing the word blue to red. This will enable the interfaces to pick up the red versions of the .css files. If you’d like to learn more, we encourage you to read GXT 3 Appearance Design. headerBackground.png contains the red gradient we developed for the Ext GWT 2 style. RedContentPanel.css contains the red style rules for the panel and body. RedHeader.css file contains the red style rules for the header.

Using the new appearance

As we saw in "Specifying an appearance", there are two alternatives for using our new appearance: if we want to use it for all the panels in our application, we can do so by modifying the GWT module XML file for the project. On the other hand, if we want to use it for only a selected set of panels, we need to pass it to the ContentPanel constructor when we create the ContentPanel.

Specifying the default appearance in the GWT module XML file

First, let’s look at modifying the module file. GXT 3 components provide constructors that create a default appearance by invoking the GWT.create method. This approach uses the replace-with directives in the module definition file to determine which class to use, in a process that is referred to as deferred binding. To tell GWT.create to create an instance of the new appearance, we add the following to the module file (after any other inherited themes):

 
<replace-with class="com.example.gxt3.style.client.theme.red.RedContentPanelAppearance">
  <when-type-is
     class="com.sencha.gxt.widget.core.client.ContentPanel.ContentPanelAppearance" />
</replace-with>
 

This effectively sets the application wide default appearance for every content panel.

If you have lots of appearance classes, it is a good practice to create a new module file that contains all of the replace-with directives for the new appearances and then add an inherits directive for this new file to module file of each application that will use it.

Specifying the appearance of a particular component using a constructor argument

Now let’s look at the second alternative for using the new appearance. This involves passing an instance of the appearance to the ContentPanel constructor:

ContentPanel redContentPanel = new ContentPanel(new RedContentPanelAppearance());

This is done wherever you need to use the new appearance. Alternatively, you can provide a factory that vends an instance of a content panel, optionally depending on a parameter that defines the desired appearance, or you can create a constructor that takes an enum and uses it to create and pass an instance of the desired appearance to the superclass constructor.

Theses approaches let you dynamically create instances of components, each with its own appearance:

Dynamically created instances

Tips and tricks

Turn off style class name minification during development

One of the features provided by CssResource is to create unique, minified class names for each of the classes it finds in the CssResource derived interface. This approach produces reliable and efficient styles in production mode, but can be difficult to work with during development. To instruct CssResource to create detailed class names for development mode, put the following in the application’s module file:

 
<set-configuration-property name="CssResource.style" value="pretty"/>
 

Let GWT generate the CssResource interface

Keeping the CssResource interface in sync with the CSS file can be time consuming. As an alternative, use the GWT GenerateInterface utility to generate a CssResource interface from an existing CSS file:

 
java -cp gwt-dev.jar:gwt-user.jar com.google.gwt.resources.css.InterfaceGenerator 
  -standalone -typeName some.package.MyCssResource -css input.css
 

Conclusion

In software engineering there are frequently many ways to do something. Choosing the right approach involves weighing the trade-offs and maximizing those that are most important.

In Ext GWT 2, styling was hit or miss, and when you got a hit, it seemed relatively easy. However, it was hard to maintain.

The GXT 3 approach takes advantage of the Appearance Pattern, with ClientBundle and CssResource. It supports the common Java idioms of strong typing and detecting errors at compile-time rather than runtime. However, it requires more moving parts.

You may find that you prefer one approach over the other, but it is important to keep in mind that there is nothing you can do in Ext GWT 2 that you can’t do in GXT 3, and plenty you can do in GXT 3 that you can’t do in Ext GWT 2.

In retrospect, the days of huge monolithic CSS files are over, and large projects are going with something like the Appearance Pattern, or CSS preprocessors, such as Sass and Compass.

One last piece of guidance: if you are in the process of migrating styles and themes from Ext GWT 2 to GXT 3 and run into a problem, or have a question, please do not hesitate to use the GXT forums.

Written by Tony Stuart
Tony Stuart has been working with Sencha technologies since 2007. He joined the Sencha team as a Solutions Architect in 2011 and developed the Desktop Example for the GXT 3 release. Tony previously worked for IBM, including 16 years in the Research, Software, and Printing Systems Divisions as well as three years in England at InfoPrint Solutions, IBM’s joint venture with Ricoh. Tony is an inventor on 13 patents and served as chairman of an international consortium of 22 major manufacturers in the printing and mailing industry. Tony has worked with clients all around the world in the areas of software development, consulting, and training. He now lives in Tampa, Florida.

Share this post:
Leave a reply

There are 5 responses. Add yours.

Lobos

2 years ago

While I love the api, ExtJS, etc will continue to be held back from the lack of an attractive theme… I see mentioned “themes” in the title, but as far as I can see there is only one theme and some ways to change the colors - one theme with boring boxes that look so 2000’s - Take for example this page, would you run the ExtJS theme on this page or the entire Sencha website? Didn’t think so… now if you are looking for some inspiration check out this: http://twitter.github.com/bootstrap/components.html

Thanks!

Hyle Campbell

2 years ago

There are many ways to theme both Touch and Ext JS.  The themes included should not limit the creativity of the app developers. They are just examples.  Most of our clients do create a custom themes for their applications.  We will do more write ups on theming Sencha applications including Ext JS and Touch.

Tony Stuart

2 years ago

@Lobos, this blog is about theming in GXT, which is Sencha’s UI framework for building HTML5 web apps using Java and GWT. This environment provides an opportunity to use Java style static / strong typing for CSS resources.

Sencha’s JavaScript UI frameworks, Ext JS and Touch, are easy to theme using Sass and Compass. For more information see http://www.sencha.com/learn/theming/ and
http://www.sencha.com/blog/an-introduction-to-theming-sencha-touch/

Lucy Kona

2 years ago

Meaningful concept at all! I just pleased to read about this entry and all these information are very helpful to me. Love this entry. Thanks for this allocation. LOL
http://www.mybdproperties.com/

Andreas

2 years ago

I think the appearance pattern is a good thing. It forces you to do you styling things in a sensible way. But it’s a bit complicated in some cases like for TextButtons. And a question: BoxLayoutContainer has an appearance to be set in the constructor, but HBoxLayoutContainer which extends BoxLayoutContainer has no appearance that can be set. Can someone explain the reason why?

Comments are Gravatar enabled. Your email address will not be shown.

Commenting is not available in this channel entry.