Skinning in JSF

Why Skinning?

CSS is the tool for webdevelopers (or more likely designers) to customize sites without having to alter code. This allows for visual variability without the need to compile/test/deploy/… things. It also allows user-specific theming where the user can decide which theme looks best.
However there is one thing notably lacking in css: variables. They may be introduced in CSS3 but it will be a ways before they are actually picked up by all major browsers. Until then we can look at other frameworks to see how they achieve skinning in JSF, most notably Richfaces. This document is written using richfaces as a guideline but does not actually require any richfaces components to be present so it can be used with any JSF framework.

Richfaces skinning

Richfaces supports skinning by using a simple properties file to represent the variables. The properties file must:

  • be located in META-INF/skins
  • have the extension “skin.properties”

For example you might create a skin “META-INF/skins/test.skin.properties”. To tell richfaces to use this skin, you have to configure a context parameter in the web.xml file:

You can take an existing skin file to see which variables exist or you can browse the component pages to see which variables they reference. Additionally richfaces will by default (you can turn this off) style regular jsf components as well in order to create a single theme for the entire application.

Using the variables yourself

Of course you don’t only want to skin existing richfaces components, you may want to use the variables in the css of your own components/pages. In order to do this, you need to create a file with an extension “.ecss” instead of “.css”. This will be automatically picked up by richfaces and the variables inside it will be replaced with the properties available in the skin file. Each variable must be written like this:

The quotes are mandatory. There are however a number of caveats.

Library lookups are wonkyRichfaces will translate your ecss outputStylesheet to something like this:

Which is fine unless you add the style sheet to a library, then it will generate this (note the escaped ampersand):

I’m not entirely sure if the problem lies with richfaces (I don’t really see an obvious bug in the code with regards to URI encoding) or with jsf in general but either way it is a bit off. This may work depending on the browser, not sure how well supported this is though. Anyway, you can easily sidestep this by not putting it in a resource library and simply adding stuff on the root.

Eclipse does not like ecss files

Eclipse does not always like the variable format ecss uses. Depending on your level of bad luck you either get badly highlighted css or continuous parsing errors resulting in error popups.

Custom css properties are dropped

It is a long standing tradition to introduce new css features in browsers with a prefix for said browsers. For example take this bit of css which includes a chrome/firefox gradient and a firefox/general box-sizing declaration:

When I browsed the resulting compiled ecss, I got this:

As you can see, it dropped the mozilla gradient and both the mozilla and default box-sizing properties. This is likely because richfaces actually interprets the css instead of merely replacing the variables. The colors were also defined as hexadecimal and converted to their rgb equivalent. Apart from validation, I’m not entirely sure why richfaces bothers parsing the css.

Custom variable styling

To work around the issues mentioned above, I wrote my own stylesheet compiler. It requires a few things to function:

  • stylesheets must use the extension “.compiled.css” instead of “.css”, so for example “mystyle.compiled.css” will be picked up by the stylesheet compiler
  • it currently uses the richfaces web.xml property mentioned above to determine which skin file you want and also scans for the “META-INF/skins/<name>.skin.properties” file, in that respect it is compatible with richfaces

The variable format is slightly more lightweight, it uses “$”, the css fragment in the above would become:

Bits and pieces

The stylesheet compiler is a standalone jar file which can be plugged into any war file. It contains the following things.

CSSResourceHandler.java

First off you need to provide a custom implementation of the jsf resource handler. Based on this tutorial and the richfaces implementation it looks like this:

As you can see, it simply delegates most resource calls to the wrapper that it was initiated with. Only when the extension “.compiled.css” is found does it kick in. If the web.xml context parameter is not set, it will fall back to the richfaces default.

CompiledCSS.java

The compiled css class extends resource and much like the handler, delegates nearly all calls. It intercepts the request for content though and performs a replace on the original content before sending it back:

META-INF/faces-config.xml

You need to tell JSF to use your custom resource handler, you can do this in the faces-config file:

At this point I’m not entirely sure how this works. Apart from the mandatory faces-config.xml file in your main war, you can apparantly have faces-config.xml files in your libraries as well. Richfaces registers its own resource handler and since both frameworks still work, JSF must register both instead of having a “the last setting wins” policy. How this plays out at runtime (are all the handlers stacked in order of appearance? Is it a flat list of handlers that is looped through?…) is unclear at this point.

Putting it together

Suppose you have a separate jar which defines some templates/components and most notably: some styling. The jar layout is as follows:

  • META-INF: everything must be in meta-inf for jsf to pick it up
    • resources: all jsf-related resources including templates must be available in the resources folder
      • style: the library “style”
        • default.compiled.css
      • templates
        • layout.xhtml
    • skins
      • custom.skin.properties

Suppose we define a very simple layout.xhtml:

As you can see, we can reference the compiled stylesheet as we would a normal stylesheet. Now suppose we have this bit in the stylesheet:

Then we need to add the properties to the custom.skin.properties file:

When you open the css as it is retrieved by the browser, you will see:

If you package this as a “theme” library for your jsf applications, you can create an index.xhtml in your main war file that contains:

Author: Alexander Verbruggen

blogger

blogger

Curious to know more about this topic?

Working at i8c

i8c is a system integrator that strives for an informal atmosphere between its employees, who have an average age of approx 30 years old. We invest a lot of effort in the professional development of each individual, through a direct connection between the consultants and the management (no multiple layers of middle management). We are based in Kontich, near Antwerp, but our customers are mainly located in the triangle Ghent-Antwerp-Brussels and belong to the top 500 companies in Belgium (Securex, Electrabel, UCB, etc…).

Quality Assurance

i8c is committed to delivering quality services and providing customer satisfaction. That’s why we invested in the introduction of a Quality Management System, which resulted in our ISO9001:2000 certification. This guarantees that we will meet your expectations, as a reliable, efficient and mature partner for your SOA & integration projects.

i8c - ISO9001-2015

Also worth reading

Apigee Scope Validation using OpenAPI Specification

In API security and management, we often use a lot of different security mechanisms to protect the requested resource behind the API Gateway. One of these mechanisms is the validation of scopes to authorize a client on a specific sub-resource of the API. Most of

Read More »

Integrating with TIBCO CLOUD

Our experts Glenn, Jason, Jurgen, and Kevin dedicated an i8c FastTrack Day to examining the TIBCO iPaaS offering. Check out their Research & Development day report to learn what they uncovered. 👇  TIBCO CLOUD™ The TIBCO Cloud™ Integration enterprise integration platform-as-a-service (iPaaS) provides self-service integration

Read More »