6

In external style sheets of my current JSF project, there are hard-coded links to external resources like

.someId { background-image:url(/context/resources/images/example.jpg); }

In the JSF xhtml documents, I could use EL expressions like ${request.contextPath} but how can EL processing be applied to CSS files?

(Related: How can I embed an CSS background image link with JSF?)


Hard-coding of context paths has a disadvantage: the context path - /context in the example - of a web application can be changed at deploy time by modifying the web.xml (or by renaming the web application archive file if no context is specified in web.xml), but links to resources in the CSS files would still point to the unchanged hard coded context, and cause resource not found errors.

Community
  • 1
  • 1
mjn
  • 36,362
  • 28
  • 176
  • 378

6 Answers6

12

Maybe I misunderstand your question, but if by external css you just mean your own css that is not inline, then with JSF 2.0 you can use EL in your css as long as you include it with an <h:outputStylesheet>. For example, I have a project with this structure:

war
|__ WEB-INF
|   |__ *standardStuff*
|__ resources
|   |__ css
|   |   |__ style.css
|   |__ images
|       |__ image1.png
|__ xhtml
|   |__ index.xhtml

This is clearly not the complete file list, but should be enough to get the point. Then I have this in my index.xhtml:

<f:view xmlns:f="http://java.sun.com/jsf/core" 
    xmlns:h="http://java.sun.com/jsf/html" 
    xmlns:ui="http://java.sun.com/jsf/facelets">
  <h:head/>
  <h:body>
    <h:outputStylesheet library="css" name="style.css" target="head"/>
    <ui:include src="content.xhtml"/>
  </h:body>
</f:view>

And in my css I have something like this:

.someClass {
    background-image: url('#{resource['images/image1.png']}');
}
Lucas
  • 14,227
  • 9
  • 74
  • 124
10

I put the CSS images always in a subfolder of the CSS folder. E.g.

  • /resources/css/style.css
  • /resources/css/images/example.jpg

This way you just end up like

.someId { background-image:url(images/example.jpg); }

Yes, they are resolved relative to the URL of the CSS file itself, not to the main JSF/HTML page.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • BalusC, I know this comment does not add any useful feedback but I just have to say it. You are a genius. – arg20 Feb 21 '12 at 18:57
  • @arg20: Thank you :) Related answer btw: http://stackoverflow.com/questions/6835499/changing-jsf-prefix-to-suffix-mapping-forces-me-to-reapply-the-mapping-on-css-ba/6835701#6835701 – BalusC Feb 21 '12 at 19:00
7

You can use Expression Language (EL) along with the FacesContext to solve the issue. I use this technique frequently.

background-image: url('#{facesContext.externalContext.requestContextPath}/resources/images/background.gif');

This allows you to take advantage of JSF to provide dynamic content based on application input, or changes.

This technique works on JSF 1.2 and JSF 2.0

John Yeary
  • 1,112
  • 22
  • 45
4

@Bozho's answer pretty much covers your options.

Another possibility is to continue having a static style sheet, and filling in the dynamic parts in the document's head where you have access to your expressions:

<head>

<!-- The style sheet contains 99% of the CSS ->
<link rel="stylesheet" href="static.css" type="text/css">

<!-- The remaining 1% is done here -->
<style type="text/css">
 .someClass { --- your dynamic values  here --- }
</style>

</head>

in the PHP world, this is the best practice because it saves an expensive PHP process from being created for the style sheet call. I don't know how things are in the JSP world but I assume it's similar.

Pekka
  • 442,112
  • 142
  • 972
  • 1,088
3

No, you can't. You have several options:

  • hard-code absolute paths (domain relative, of course) - not that bad
  • use relative paths - can be a problem when you have nested urls like /view/external/foo/bar.jsf
  • preprocess them during build to set the proper paths
  • use a Filter (and both client and server-side caching) to set the proper paths.

(I feel I'm missing something)

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
3

@Bozho: JSF allows to define a ResourceHandler to replace the standard one. You could just subclass javax.faces.application.ResourceHandler, handle specific requests and delegate others to the base class.

For the given example, the custom resource handler should determine the context and replace absolute path definitions. This enables dynamic path resolution on a per-request base.

tasel
  • 629
  • 5
  • 15