Managing your CSS (GSS) files with variables and a theme

My previous article showed you how to use CSS inside your GWT application. Today, we will introduce the concept of variables, and show you how to manage them effectively using theme files.

Variables

One of the best examples of variable use in CSS is probably color management. If your application has a default blue color, let’s say #2054e8, and it is used in multiple places, you will need to remember this particular color code every time you specify that color. Then if you decide to make your default color the lovely #f31ae5 shade of pink, you will need to do a find and replace across your whole project, and hope that everything went well.

All these hassles can be avoided if you use variables for your colors, so let’s do that!

Creating the Colors file

We will create Colors.java in src/main/java/com/company/project/client/resources.

We will discuss variable naming conventions later. Right now, you only need to understand that we can define a variable, like C_PRIMARY, and assign it a value, such as our initial shade of blue #2054e8.

The main purpose of this file is to contain all color values in the same place. It will then be easy to replace them later, and create different themes for our app.

Creating the associated GSS file

This is where we start to feel the real power of GSS over regular CSS files. After compilation, GSS files output basic CSS, transforming variables into the values associated with them.

In order to easily use our variables, we need to define them in a file. We will name that file colors.gss and put it into src/main/resources/com/company/project/client/resources/css.

We define variable names, and point them to the associated variables inside Colors.java.

The most important part is the very first line: @provide 'colors';

We are providing this file with a name that we will be able to import later on, making the variables defined in this file accessible in other contexts.

Binding it with your default resources style file

Before we can use this file, we need to supply it to our style’s resource file. My default style file is named style.gss and it uses the AppResources.java resource file, located in src/main/java/com/company/project/client/resources.

You can probably guess what you’ll find in this file:

We can see that we are using style() with the file located at css/style.gss. We need to add the color.gss to @Source, so it’s accessible. Instead of a string, we need to pass an array of strings, pointing to the desired files.

Note that we need to declare colors.gss before style.gss. Otherwise, style.gss will try to load the colors.gss file, but it will not yet be defined, causing an error.

Using variables inside of the style file

Remember when we defined @provide 'colors'? It is now required inside style.gss. Once that’s done, you will have access to your variables!

Structure

You can define variables for a lot of things beside colors, like sizes and fonts. You could decide to create a variables.gss file and add all your variables there, but this can pose a problem as your application grows. I prefer to structure my files by what they do, giving each set of variables their own file:

// src/main/java/com/company/project/client/resources/variables
    -> Colors.java
    -> Fonts.java
    -> Sizes.java

// src/main/resources/com/company/project/client/resources/variables
    -> colors.gss
    -> fonts.gss
    -> sizes.gss

This way, if you only need to use Colors inside of a specific style sheet, you can import them alone. Variable types become more modular.

Naming Conventions

As variables are not prefixed with any symbols, it helps to write them in uppercase. That way it’s easy to spot them in your CSS.

I also like to prefix them with a single letter that represents the type of variable that it is.

- Colors.java   -> C_VARIABLE_NAME (C_PRIMARY, C_BACKGROUND, C_TEXT ...)
- Fonts.java    -> F_VARIABLE_NAME (F_PRIMARY, F_SECONDARY_BOLD ...)
- Sizes.java    -> S_VARIABLE_NAME (S_SECTION_PADDING, S_LINE_HEIGHT ...)

Give your variables meaningful names, something that you will be able to remember and understand upon reading. Describe the purpose of the variable, not its value.

For example, F_PRIMARY is the primary font used inside the app, the most common one that will be almost everywhere. I find the use of primary / secondary easy to remember. It has a strong meaning, and it’s about what the variable is used for, and not about the value held by the variable. A bad example would be F_ARIAL for the same variable with the same purpose. It’s bad because if, in the middle of the project, you decide to change the main font from Arial to Helvetica, you will need to refactor the name of your variable. This is what we are trying to avoid.

Instead of C_RED for an error message color, go for C_ERROR. Or even better : C_STATE_ERROR. You will be able to manage your state colors easily, like C_STATE_SUCCESS and C_STATE_DEFAULT without worrying about the color it is.

Theme

The problem

If you create different variable files, you gain the ability to only load the ones you want. This is both good and bad. If you need several variable types, you have to specify each one of them inside of your resource loader, and then require them in your GSS file. This can quickly become annoying, and it makes your code harder to maintain.

As you can see, if you have multiple GSS files, you need to include required variables inside each of those files. And if you need to add another variable set, or remove one, you will need to go inside each of your Resource and GSS files and adapt them accordingly. And that sucks.

The solution

Faced with the above problem, you might think going back to having just one Variables.java file and a variables.gss file is not a bad idea after all. But we can have our cake and eat it too. We can keep the separation in our Java files and have only one GSS to rule them all. This way, variable files will remain modular, and yet we will still have only one file to require in each GSS file that need to access variables. If we need to change the structure, like adding a new subset of variables, we will only need to update one file, and that’s all!

I call this super GSS file theme.gss because it will be used to produce different themes, but you could name it variables.gss and it would still be totally accurate.

With this new method, things are now easier to maintain:

As the constants’ values are stocked in Java files, these constants can be modified easily. With this technique, it is now super easy to create different themes that can be user-based or changed at compile time.

Updated Structure

Using a theme file, my structure now looks like this:

src/main/java/com/company/project/client/resources/
    -> elements/
    -> pages/
    -> theme/
        -> Colors.java
        -> Fonts.java
        -> Sizes.java
    -> AppResources.java
    -> ResourcesLoader.java

src/main/resources/com/company/project/client/resources/css
    -> elements/
    -> pages/
    -> style.gss
    -> theme.gss

Tips

A variable will output the string of text inside of it into your CSS. Sometimes, you will need a variable to output more then one set of properties. You can do so this way:

Can you spot the trick in F_PRIMARY_BOLD? The variable is defining the font-family, closed with the semicolon ;, then define the font-weight, without a closing semicolon ; because the closure will be handled in the CSS.

Conclusion

You now understand the true power of variables. When used with a theme file, the management of your application becomes a breeze. Things can be made even easier, using a tool to manage the generation of your theme and the associated files. But that, my friends, is a topic for another blog post.

 

  • Ed

    Thanks for the inspiration.
    I am missing some practical details like how to switch between Themes or how to output app’s with different themes (further details about ResourceLoader maybe)
    You might want to have a look at the Theming comment (with code example) in this post: https://groups.google.com/forum/#!topic/google-web-toolkit/mrBctJ2BGtI (posted in detail before).
    It’s component based, flexible, dynamic (usage of instance methods), and use of the java compiler (GSS not detect errors while typing).
    Currently I use a mixture of GSS and the Preference mechanism. The theme gwt config files include the required preference classes.

    Keep up the good work.

  • Lu

    There is a similar way using the old CssResources (different sintax) for creating themes.
    I did something similar using .css. (instead of colors called palette)

  • Mohammed Alhammouri

    Can I use java files to make translation even easier with UIBinder?
    Here is I want to do it :
    1-Give a value for each java field passed on Constant.
    2-Then declare these values in gss file.
    3-Use them later with other files.

    Is it a good , or bad (especially on performance)?

  • Gilberto Torrezan

    For the record, to be able to use the theme constants on UiBinder, you can use (on GWT 2.7.0):

    .yay {
    background-color: C_BACKGROUND;
    }

    No need for @require or @import. The only downside is that the incremental compiler doesn’t apply the changes of the source Java file (with the constants) when you modify it. You need to restart the super dev mode for the changes to the effect on the final style.

  • Gilberto Torrezan

    Ok, in my last comment the UiBinder tags was removed… The tag is:

    ui:style gss=”true” src=”css/theme.gss”

    More about it on: http://www.gwtproject.org/doc/latest/DevGuideUiBinder.html#Hello_Stylish_World

  • Jason Lemay

    Petit test de commentaire!

    • Olivier Lafleur

      Is work!

  • James Nelson

    There is a typo at the end of this article;

    /* will output : */

    font-family: ‘My Cool Typo’, sans-serif;
    /* Is missing the font-weight: 700; */

    • Jason Lemay

      Hi James

      Only F_PRIMARY_BOLD have a font-weight defined. F_PRIMARY only have the font defined, so I think the output in my example is right. Let me know if it’s not clear 🙂

  • Jimmy Pannier

    Hi

    I’d like to generate a style with GSS for an INSTANCE OF A WIDGET

    Any idea how to do that ?

    StyleElement styleElement = com.google.gwt.dom.client.StyleInjector.injectStylesheet(cssResource.getText());

    is giving always the same classnames. (so reinject this, change color of all widgets shown)

    How to generate new classNames (example with id of widget as suffix) and apply this new classnames to the widget instance only ?

    I precise that gss has eval on a enum value (that changes on the fly)

  • Matthieu Dumont

    Hi,

    Is it possible to concatenate multiple constants ?

    I’m trying to set a background-image like this :

    @def THEME_ID eval(“aClass.CURRENT_THEME”);
    @def BG_IMAGE eval(“anEnum.MAIN_BG_IMG.getImageName()”);

    .content-panel {
    background-image: url(images/THEME_ID/BG_IMAGE);
    }

    But the result is :

    http://xxx/images/THEME_ID/BG_IMAGE Failed to load resource: the server responded with a status of 404 (Not Found)

    Same result if I put quotes like this url(‘images/THEME_ID/BG_IMAGE’);
    Same result again with :

    .content-panel {
    background-image: url(concat(“images/” , THEME_ID , “/” , BG_IMAGE));
    }

    Am I missing something or is it just impossible ?

    Thanks in advance,
    Matthieu

  • Matthieu Dumont

    @def THEME_ID eval(“anEnum.CURRENT_THEME.name()”);

    .content-panel {
    background-image: url(“images/THEME_ID/main_bg.png”);
    }

    Doesn’t work much better. The compiler seems not understand THEME_ID is a constant, maybe because there is no whitespace after.