Jsf2 Add Custom Font to CSS Stylesheet

JSF2 add custom font to css stylesheet

My stylesheet.css located in META-INF/resources/css/stylesheet.css file

META-INF? So this is bundled in a JAR file which is in turn dropped in webapp's /WEB-INF/lib?

Regardless, you need to use the #{resource} resolver instead to resolve classpath resources to proper /javax.faces.resource URLs .

src: url("#{resource['css:websymbols-regular-webfont.eot']}");
src: url("#{resource['css:websymbols-regular-webfont.eot']}?#iefix") format('embedded-opentype'),
url("#{resource['css:websymbols-regular-webfont.woff']}") format('woff'),
url("#{resource['css:websymbols-regular-webfont.ttf']}") format('truetype'),
url("#{resource['css:websymbols-regular-webfont.svg']}#WebSymbolsRegular") format('svg');

Further, I recommend to put one additional path in /resources folder which can then represent the real library name. The library="css" is namely the wrong usage of the resource library. It should not represent specific resource types (CSS/JS/images) at all, but a real common library name. For example, /common. You can then reference the stylesheet and the resources as follows:

<h:outputStylesheet library="common" name="css/stylesheet.css" />

and

src: url("#{resource['common:css/websymbols-regular-webfont.eot']}");
src: url("#{resource['common:css/websymbols-regular-webfont.eot']}?#iefix") format('embedded-opentype'),
url("#{resource['common:css/websymbols-regular-webfont.woff']}") format('woff'),
url("#{resource['common:css/websymbols-regular-webfont.ttf']}") format('truetype'),
url("#{resource['common:css/websymbols-regular-webfont.svg']}#WebSymbolsRegular") format('svg');

See also:

  • What is the JSF resource library for and how should it be used?
  • How to reference CSS / JS / image resource in Facelets template?

JSF Custom font with CSS

The final solution: apparently my browser (Chrome) was loading old cached CSS, so I wasn't being able to see the updates I was developing on my styles. Just cleaned Chrome's cache and everything was working perfectly. I just need to figure how to change that behavior on the browser, since I don't want to clean it for every change on my CSS.

Biggest facepalm ever.

EDIT:

Found the solution by opening Devtools -> Settings -> Checked Disable cache (while DevTool is open)

Now I can edit my CSS and refresh the page to normally see the results. Thanks.

Import custom fonts to JSF

Did this using OmniFaces:

  1. Added the dependency (pom.xml):

    <dependency>
    <groupId>org.omnifaces</groupId>
    <artifactId>omnifaces</artifactId>
    <version>1.8.1</version>
    </dependency>

  2. Added OmniFaces' resource handler to faces-config.xml:

    <application>
    <resource-handler>
    org.omnifaces.resourcehandler.UnmappedResourceHandler
    </resource-handler>
    </application>

  3. Mapped /javax.faces.resource/* to FacesServlet as follows (web.xml):

    <servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>/javax.faces.resource/*</url-pattern>
    <url-pattern>*.xhtml</url-pattern>
    </servlet-mapping>

  4. Used #{resource["<path>"]} in CSS, like so:

    @font-face {
    font-family: "Gotham Pro Bold";
    src: url('#{resource["fonts/GothaProBol.otf"]}');
    }

Including Css in jsf

Regarding your XML namespaces declaration, you are using JSF 2.2.

Since JSF 2.0, you can place CSS, JavaScript files and images(and other files) into a resources directory in the root of your web application.

css

Then, you can include your CSS using the h:outputStylesheet :

<h:outputStylesheet library="css" name="styles.css"/>

Reffering to a css stylesheet from an unknown, higher directory

The css file is downloaded and included on the client side, as opposed to the php include statement which includes the file on the server side.

The path for the css should therefor "make sense" from the clients perspective and probably be specified relative to the public_html directory. That is, if it resides directly in the public_html directory the line should read

<link href="/Stylesheet.css" rel="stylesheet" type="text/css" />

Can I make the h:outputStylesheet to load css file that is being retrieved from servlet? (not resources folder)

No, you can't. Even when it has worked, it's the servlet who's responsible for EL resolving, not the <h:outputStylesheet> component.

You need to solve the problem differently. I'd start by just putting all CSS dependencies, such as CSS images, in the very same folder as the CSS file itself and then reference them relatively. This way you don't need to fiddle with the context path.

By the way, the #{request.contextPath} is shorter.

JSF 2.0 Javascript and CSS table

If you don't care about IE6 users, just use :hover pseudoselector. Add the following to your CSS.

table.hovertable tbody tr:hover {
background: #ffff66;
}

If you do care about them for some unobvious reasons, use JavaScript.

var trs = document.getElementById('dataTable').getElementsByTagName('tbody')[0].getElementsByTagName('tr');
for (var i = 0; i < trs.length; i++) {
trs[i].onmouseover = new Function("this.bgColor = '#ffff66'");
trs[i].onmouseout = new Function("this.bgColor = '#d4e3e5'");
}

Call it during onload of the window or at end of the body. Note that the element ID dataTable in the Javascript has to be exactly the same as the generated HTML <table> ID of the <h:dataTable>.

<h:dataTable id="dataTable">

This is fancier possible with jQuery.hover() function, for the case you use jQuery.

$('.hovertable tbody tr').hover(
function() { this.bgColor = '#ffff66'; },
function() { this.bgColor = '#d4e3e5'; }
);

How do I override default PrimeFaces CSS with custom styles?

There are several things you need to take into account of which one or more might be relevant you your specific case

Load your CSS after PrimeFaces one

You need to ensure that your CSS is loaded after the PrimeFaces one. You can achieve this by placing the <h:outputStylesheet> referencing your CSS file inside <h:body> instead of <h:head>:

<h:head>
...
</h:head>
<h:body>
<h:outputStylesheet name="style.css" />
...
</h:body>

JSF will automatically relocate the stylesheet to the end of the generated HTML <head> and this will thus ensure that the stylesheet is loaded after the PrimeFaces' default styles. This way the selectors in your CSS file which are exactly the same as in PrimeFaces CSS file will get precedence over the PrimeFaces one.

You'll probably also see suggestions to put it in <f:facet name="last"> of <h:head> which is understood by PrimeFaces-specific HeadRenderer, but this is unnecessarily clumsy and would break when you have your own HeadRenderer.

Understand CSS specificity

You also need to ensure that your CSS selector is at least as specific as the PrimeFaces' default CSS selector on the particular element. You need to understand CSS Specificity and Cascading and Inheritance rules. For example, if PrimeFaces declares a style by default as follows

.ui-foo .ui-bar {
color: pink;
}

and you declare it as

.ui-bar {
color: purple;
}

and the particular element with class="ui-bar" happen to have a parent element with class="ui-foo", then the PrimeFaces' one will still get precedence because that's the most specific match!

You can use the webbrowser developer tools to find the exact CSS selector. Rightclick the element in question in the webbrowser (IE9/Chrome/Firefox+Firebug) and choose Inspect Element to see it.

Sample Image

Partial overriding

If you need to override a style for only a specific instance of the component and not all instances of the same component, then add a custom styleClass and hook on that instead. It is another case where specificity is used/applied. For example:

<p:dataTable styleClass="borderless">
.ui-datatable.borderless tbody,
.ui-datatable.borderless th
.ui-datatable.borderless td {
border-style: none;
}

If a component does not support a styleClass and you are on jsf 2.2 or up, you can also use passtrough attributes and add a pt:class and have it end-up on the output.

<p:clock pt:class="borderless" />

Never use !important

In case you fail to properly load the CSS file in order or to figure the right CSS selector, you'll probably grab the !important workaround. This is Plain Wrong. It's an ugly workaround and not a real solution. It only confuses your style rules and yourself more in long term. The !important should only be used in order to override the values hardcoded in HTML element's style attribute from a CSS stylesheet file on (which is in turn also a bad practice, but in some rare cases unfortunately unavoidable).

See also:

  • How to reference CSS / JS / image resource in Facelets template?
  • Mozilla Developer Network > CSS > Specificity (great article, a must read!)
  • Understanding Style Precedence in CSS: Specificity, Inheritance, and the Cascade

Absolute path name in my template to get resources

The template path in <ui:composition> is relative to the webapp's own folder structure, not to the domain root (because it does not represent an URL!). So if you start it with /, it's just resolved relative to the context root.

<ui:composition template="/WEB-INF/inc/template.xhtml">

(putting in /WEB-INF has the advantage that the enduser cannot open it directly by guessing the URL)

The name path of <h:outputStylesheet>, <h:outputScript> and <h:graphicImage> is always relative to /resources root folder, regardless of if you start it with / or not.

<h:outputStylesheet name="css/default.css" />
<h:outputScript name="js/default.js" />
<h:graphicImage name="img/logo.png" />

If you want to use plain HTML instead of JSF components to include CSS/JS/images for some reason, then best is to prepend the path with #{request.contextPath} yourself, so that you can make it a domain-relative URL, so that you don't need to fiddle with context-relative URLs. See also: How get the base URL?



Related Topics



Leave a reply



Submit