Tag Archives: faces

Bootstrap, Glyphicons, and JavaServer Faces 2.x

Having trouble getting Glyphicons to work with JavaServer Faces (JSF) 2.x?

The Problem

You’re probably using the JSF resource mechanism to include the Bootstrap stylesheets and scripts:

[xml]


[/xml]

When you use these tags, the resulting link that is included in the page looks like this:

[html]
[/html]

Note that the href doesn’t contain the actual path to the stylesheet resource. When the browser requests this resource, the Faces servlet is going to interpret the request URI and query parameters to figure out which resource is needed.

So now what happens if this stylesheet contains relative URLs? Glyphicons are defined by font resources that need to be loaded by the browser. If we look at the non-minified bootstrap.css, we can see that it uses relative URLs to reference the necessary font resources:

[css]
@font-face {
font-family: ‘Glyphicons Halflings’;
src: url(‘../fonts/glyphicons-halflings-regular.eot’);
src: url(‘../fonts/glyphicons-halflings-regular.eot?#iefix’)
format(’embedded-opentype’),
url(‘../fonts/glyphicons-halflings-regular.woff’)
format(‘woff’),
url(‘../fonts/glyphicons-halflings-regular.ttf’)
format(‘truetype’),
url(‘../fonts/glyphicons-halflingsregular.svg#glyphicons_halflingsregular’)
format(‘svg’);
}
[/css]

These URLs are relative to the URL for the stylesheet itself, so when the browser request the first font resource here, it’s going to use this URL:

[html]
/myapp/javax.faces.resource/fonts/glyphicons-halflings-regular.eot
[/html]

Of course, the Faces servlet doesn’t know how to interpret this request. In fact, depending on how you’ve configured the <servlet-mapping/> for the Faces servlet, it might not even be asked to handle this request.

Since the URL for the font resource doesn’t correspond to the path of an actual resource in your Faces application, the browser gets a 404 when it makes this request, and consequently the Glyphicons in your application are all broken.

Solution 1

The easy solution is to use an ordinary <link> instead of using <h:outputStylesheet>. In this case:

[html]
[/html]

Note that I’m using an EL expression to get the context path, and simply appending the path to the actual stylesheet resource in my application. Now, the relative URLs in the stylesheet will work just fine (assuming that I put Bootstrap’s fonts folder alongside the css folder).

Solution 2

If you really want to use the JSF resource mechanism, you’re going to need to modify the URLs in the Bootstrap’s font face definition. Obviously, you’re going to want to work with the non-minified version of the stylesheet here.

You might be surprised that you can use an EL expression inside of a stylesheet, in the same way that you would in a facelet page. The idea here is to replace each of the relative URLs in the font face definition with an EL expression that will produce a Faces-compatible URL:

[css]
@font-face {
font-family: ‘Glyphicons Halflings’;
src: url(“#{resource[‘fonts:glyphicons-halflings-regular.eot’]}”);
src: url(“#{resource[‘fonts:glyphicons-halflings-regular.eot?#iefix’]}”)
format(’embedded-opentype’),
url(“#{resource[‘fonts:glyphicons-halflings-regular.woff’]}”)
format(‘woff’),
url(“#{resource[‘fonts:glyphicons-halflings-regular.ttf’]}”)
format(‘truetype’),
url(“#{resource[‘fonts:glyphicons-halflings-regular.svg#glyphicons_halflingsregular’]}”)
format(‘svg’);
}
[/css]

Each expression uses the resource EL implicit object, which is a Map whose keys are composed of a JSF library name and a resource name, separated with a colon character.

Conclusion

The JSF resource mechanism doesn’t necessarily play well with third-party stylesheets and scripts. In my opinion, the need to modify a third-party stylesheet is sufficient reason to avoid using <h:outputStylesheet/> in such cases. However, if you’re really set on using the JSF resource mechanism, you can use EL expressions to replace relative URLs and make it all work.