Can I use EL for external CSS files with JSF?
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.
Background url path in a jsf template
CSS background images are loaded relative to the request URL of the CSS file (and thus not immediately relative to its physical location in the web content). If you explore the generated HTML output of the <h:outputStylesheet>
, then you'll see that the request URL has become different. Assuming a context path of /somecontext
and a FacesServlet
mapping of *.xhtml
, it'll look like this:
<link rel="stylesheet" type="text/css" href="/somecontext/javax.faces.resource/cssLayout.css.xhtml?ln=css" />
Note that your (improper btw) usage of the library
has moved the /css
to ?ln=css
. You'd need to fix the background image url()
accordingly so that it's properly relative to the real request URL of the CSS. E.g.
background-image: url("../resources/css/imgSite/sisLogo.png");
A more reliable way, which takes JSF resource identifier rules and FacesServlet
mapping into account, is to use #{resource}
in EL:
background-image: url("#{resource['css:imgSite/sisLogo.png']}");
See also:
- Changing JSF prefix to suffix mapping forces me to reapply the mapping on CSS background images
- What is the JSF resource library for and how should it be used?
How to reference CSS / JS / image resource in Facelets template?
Introduction
The proper JSF 2.x way is using <h:outputStylesheet>
, <h:outputScript>
and <h:graphicImage>
with a name
referring the path relative to webapp's /resources
folder. This way you don't need to worry about the context path as you would do in JSF 1.x. See also How to include CSS relative to context path in JSF 1.x?
Folder structure
Drop the CSS/JS/image files in /resources
folder of the public webcontent as below (just create one if not already exist at the same level as /WEB-INF
and /META-INF
).
WebContent
|-- resources
| |-- css
| | |-- other.css
| | `-- style.css
| |-- js
| | `-- script.js
| `-- images
| |-- background.png
| |-- favicon.ico
| `-- logo.png
|-- META-INF
| `-- MANIFEST.MF
|-- WEB-INF
| |-- faces-config.xml
| `-- web.xml
|-- page.xhtml
:
In case of Maven, it should be in /main/webapp/resources
and thus not /main/resources
(those are for Java resources (properties/xml/text/config files) which must end up in runtime classpath, not in webcontent). See also Maven and JSF webapp structure, where exactly to put JSF resources.
Referencing in Facelets
Ultimately, those resources are available as below everywhere without the need to fiddle with relative paths:
<h:head>
...
<h:outputStylesheet name="css/style.css" />
<h:outputScript name="js/script.js" />
</h:head>
<h:body>
...
<h:graphicImage name="images/logo.png" />
...
</h:body>
The name
attribute must represent the full path relative to the /resources
folder. It does not need to start with /
. You do not need the library
attribute as long as you aren't developing a component library like PrimeFaces or a common module JAR file which is shared by multiple webapps.
You can reference the <h:outputStylesheet>
anywhere, also in <ui:define>
of template clients without the need for an additional <h:head>
. It will via the <h:head>
component of master template automatically end up in generated <head>
.
<ui:define name="...">
<h:outputStylesheet name="css/style.css" />
...
</ui:define>
You can reference <h:outputScript>
also anywhere, but it will by default end up in the HTML exactly there where you declared it. If you want it to end up in <head>
via <h:head>
, then add target="head"
attribute.
<ui:define name="...">
<h:outputScript name="js/script.js" target="head" />
...
</ui:define>
Or, if you want it to end up at the end of <body>
(right before </body>
, so that e.g. window.onload
and $(document).ready()
etc isn't necessary) via <h:body>
, then add target="body"
attribute.
<ui:define name="...">
<h:outputScript name="js/script.js" target="body" />
...
</ui:define>
PrimeFaces HeadRenderer
In case you're using PrimeFaces, its HeadRenderer
will messup the default <h:head>
script ordering as described above. You're basically forced to force the order via PrimeFaces-specific <f:facet name="first|middle|last">
, which may end up in messy and "untemplateable" code. You may want to turn off it as described in this answer.
Packaging in JAR
You can even package the resources in a JAR file. See also Structure for multiple JSF projects with shared code.
Referencing in EL
You can in EL use the #{resource}
mapping to let JSF basically print a resource URL like /context/javax.faces.resource/folder/file.ext.xhtml?ln=library
so that you could use it as e.g. CSS background image or favicon. Only requirement is that the CSS file itself should also be served as a JSF resource, otherwise EL expressions won't evaluate. See also How to reference JSF image resource as CSS background image url.
.some {
background-image: url("#{resource['images/background.png']}");
}
Here's the @import
example.
@import url("#{resource['css/other.css']}");
Here's the favicon example. See also Add favicon to JSF project and reference it in <link>.
<link rel="shortcut icon" href="#{resource['images/favicon.ico']}" />
In case you're using a SCSS compiler (e.g. Sass Compiler Plugin for Maven), keep in mind that the SCSS processor might interpret #
as a special character. In that case you would need to escape it with \
.
.some {
background-image: url("\#{resource['images/background.png']}");
}
Referencing third-party CSS files
Third party CSS files loaded via <h:outputStylesheet>
which in turn reference fonts and/or images may need to be altered to use #{resource}
expressions as described in previous section, otherwise an UnmappedResourceHandler
needs to be installed in order to be able to serve those using JSF. See also a.o. Bootsfaces page shows up in browser without any styling and How to use Font Awesome 4.x CSS file with JSF? Browser can't find font files.
Hiding in /WEB-INF
If you intend to hide the resources from public access by moving the whole /resources
folder into /WEB-INF
, then you can since JSF 2.2 optionally change the webcontent-relative path via a new web.xml
context parameter as follows:
<context-param>
<param-name>javax.faces.WEBAPP_RESOURCES_DIRECTORY</param-name>
<param-value>/WEB-INF/resources</param-value>
</context-param>
In older JSF versions this is not possible.
See also:
- Java EE 6 tutorial - Facelets - Resources (which is only 2 chapters away from your link)
- What is the JSF resource library for and how should it be used?
- How do I override default PrimeFaces CSS with custom styles?
Can't link to images from CSS in JSF
You can use el expressions in your css as long as your WAR structure includes the resources folder under which you have your css folder. See my answer here.
In short, this:
.someClass {
background-image: url('#{resource['images/image1.png']}');
}
Or something similar
JSF Navigation with Different CSS Class for Current/Active Path
You can use #{request.requestURI}
to get the current request URI. You can if necessary use several EL functions from JSTL fn
taglib to do some string comparisons/manipulations in EL.
Your proposed EL styleClass
suggestion is perfectly fine. There is no other easy way anyway. Best optimization which you could do so far is to render those links in a loop by an <ui:repeat>
so that code duplication is at least eliminated.
How can I embed an CSS background image link with JSF?
If I correctly understood your question:
In my project I've used this style:
<h1
class="logo"
style="background:url( #{mainMenuNavigationBean.headerImage} ) no-repeat;">
where mainMenuNavigationBean
is a session bean where I set the headerImage based on some conditions.
Changing JSF prefix to suffix mapping forces me to reapply the mapping on CSS background images
and then I see that everything going through FacesServlet has .xhtml appended to it, so that the browser is requesting .png.xhtml files, .css.xhtml file - is this right?
This only applies to resources included by <h:outputStylesheet>
and <h:outputScript>
. This is not related to the change in the URL mapping. This is related to the change from JSF 1.x to JSF 2.x and the change from <link rel="stylesheet">
and <script>
to the aforementioned JSF2 tags.
For your own scripts, stylesheets and other static stuff which is to be served from the public webcontent, you should not manually add the .xhtml
extension. You should not need to change anything with regard to existing static resources.
Only for CSS background images and other url()
references in CSS files which is to be included using the <h:outputStylesheet>
tag (and thus not for <link rel="stylesheet>
), you would need to change the url()
location to be dynamically resolved by EL. You would need to use the following syntax instead:
body {
background-image: url("#{resource['libraryname:path/to/image.png']}");
}
Imagine that you have the following /resources
folder structure:
WebContent
|-- META-INF
|-- resources
| `-- default
| |-- images
| | `-- background.png
| `-- css
| `-- style.css
|-- WEB-INF
`-- test.xhtml
and that you're including the style.css
in test.xhtml
as follows
<h:outputStylesheet library="default" name="css/style.css" />
then you should be defining the background image URL as follows
body {
background-image: url("#{resource['default:images/background.png']}");
}
Or when you're relying on the default library, thus you aren't using the library
, then it should rather look like this:
WebContent
|-- META-INF
|-- resources
| |-- images
| | `-- background.png
| `-- css
| `-- style.css
|-- WEB-INF
`-- test.xhtml
test.xhtml
:
<h:outputStylesheet name="css/style.css" />
style.css
:
body {
background-image: url("#{resource['images/background.png']}");
}
As to the securiry constraint, it is not needed when you're already using the *.xhtml
mapping. The security constraint is intended to prevent the enduser from seeing the raw XHTML source code when the FacesServlet
is mapped on a pattern other then *.xhtml
. The enduser would be able to see the XHTML source code by just removing /faces
part from the URL in case of a /faces/*
mapping or renaming .jsf
to .xhtml
in case of a *.jsf
mapping. Get rid of the security constraint, it makes in your case things worse as you're already using a *.xhtml
mapping which makes it already impossible to see the raw XHTML source code by hacking the URL.
Related Topics
Absolute Positioning Inside Relative Positioning
Is There a Way via CSS to Set the Image Height to the Line-Height
How to Create Custom Scrollbar for Mozilla Firefox with CSS
What Does Unset Value Mean in CSS
Add a Text Suffix to <Input Type="Number">
How to Draw a Checkmark/Tick Using CSS
How to Create Multiple Box-Shadow Values in Less CSS
My Fixed Background Made Scrolling the Site Very Slow, What How to Do to Improve It
How to Hide Element Label by Element Id in CSS
Compiling Issue in Bootstrap 3 with Namespace
Dynamically Define a Variable in Less CSS
Increase Size of List-Style-Bullet Type
CSS Transform: Scale Does Not Change Dom Size
Jekyll Site Works Locally But Not on Github Pages
<Div> Blur of Part of Background Image with CSS