<!--[If Ie]> Conditional Comments Are Rendered HTML-Escaped in Facelets

!--[if IE] conditional comments are rendered HTML-escaped in Facelets

This indeed won't work as Facelets implicitly HTML-escapes the comment's contents. Your best bet is to put it in a <h:outputText escape="false"> as follows:

<h:outputText value="<!--[if IE]><link rel="stylesheet" type="text/css" href="/#{resource['css:ie.css']}" /><![endif]-->" escape="false" />

This is however a line of ugliness. The OmniFaces JSF utility library has a <o:conditionalComment> for exactly this purpose:

<o:conditionalComment if="IE">
<link rel="stylesheet" type="text/css" href="#{resource['css:ie.css']}" />
</o:conditionalComment>

Unrelated to the concrete problem, you are not really using the library attribute the right way. It should identify a common "theme", not the subfolder where the files are placed in, just put that subfolder in the name attribute instead. See also What is the JSF resource library for and how should it be used?

<h:outputStylesheet name="css/common.css" />
<o:conditionalComment if="IE">
<link rel="stylesheet" type="text/css" href="#{resource['css/ie.css']}" />
</o:conditionalComment>

How to use Internet Explorer conditional comments in JSF?

Known issue, JSF rendering escapes the comments. You can solve it by using <h:outputText escape="false"> and HTML entities. You can also use OmniFaces <o:conditionalComment> to solve it in a nicer manner. See also the showcase site:

The <o:conditionalComment> renders a conditional comment. Conditional comments are an IE specific feature which enables the developer to (out)comment blocks of HTML depending on whether the client is using IE and if so even which version. They are often seen in combination with CSS stylesheets like so:

<!--[if lte IE 7]>
<link rel="stylesheet" href="ie6-ie7.css" />
<![endif]-->

However, Facelets renders the comment's contents HTML-escaped which makes it unusable.

<!--[if lte IE 7]>
<link rel="stylesheet" href="ie6-ie7.css" />
<![endif]-->

Also, if javax.faces.FACELETS_SKIP_COMMENTS context param is set to true then it will even not be rendered at all. You would need to workaround this with an ugly <h:outputText escape="false">.

<h:outputText 
value="<!--[if lte IE 7]><link rel="stylesheet" href="ie6-ie7.css" /><![endif]-->"
escape="false" />

This component is designed to solve this problem.

<o:conditionalComment if="lte IE 7">
<link rel="stylesheet" href="ie6-ie7.css" />
</o:conditionalComment>

Note that you cannot use this with <h:outputStylesheet> as it would implicitly be relocated as direct child of <h:head>.

How can I remove HTML comments in my Facelets?

There are actually two ways:

  1. To remove ALL comments, add this to web.xml:

    <context-param>
    <param-name>javax.faces.FACELETS_SKIP_COMMENTS</param-name>
    <param-value>true</param-value>
    </context-param>

    or when you're still on JSF 1.2 which doesn't use Facelets as default view technology yet:

    <context-param>
    <param-name>facelets.SKIP_COMMENTS</param-name>
    <param-value>true</param-value>
    </context-param>
  2. To remove specific comments only, use <ui:remove>.

    <ui:remove><!-- This is a HTML comment. --></ui:remove>

jsf and javascript, are incompatible?

Facelets is a XML based view technology. < and > are reserved characters in XML, indicating start and end of an element. However, you're attempting to output it plain vanilla as part of a JavaScript string variable. You need to represent them as < and > instead.

<script>window.jQuery || document.write('<script src="../js/vendor/jquery-1.8.0.min.js"><\/script>')</script>

The same applies to the & character further down in the code, which represents the start of an entity. You've by the way a new problem with the IE conditional comment once you fix this which is answered here: <!--[if IE]> conditional comments are rendered HTML-escaped in Facelets.

JSF 2 how to set html style depending on browser version

It's not true that the <o:conditionalComment> is for CSS files only. That's a misconception. It's technically simply not possible to achieve your requirement with pure Facelets tags/components as it would result in malformed XML syntax and thus a Facelets compile error.

<o:conditionalComment if="lt IE 7">
<html lang="en" class="lt-ie9 lt-ie8 lt-ie7">
</o:conditionalComment>
<o:conditionalComment if="IE 7">
<html lang="en" class="lt-ie9 lt-ie8">
</o:conditionalComment>
<o:conditionalComment if="IE 8">
<html lang="en" class="lt-ie9">
</o:conditionalComment>
<o:conditionalComment if="gt IE 8">
<h:outputText value="<!-->" escape="false" />
<html lang="en" class="no-js">
<h:outputText value="<!--" escape="false" />
</o:conditionalComment>
...
</html>

This is not well formed XML. You know, the XML end element should be in the very same scope as XML start element. It would be valid XML if every <html> has its own </html> in the same parent XML element. But this is in turn not valid HTML.

Just use <h:outputText escape="false"> on all <html> tags. Don't forget to do the same for the closing </html> tag.

<o:conditionalComment if="lt IE 7">
<h:outputText value="<html lang="en" class="lt-ie9 lt-ie8 lt-ie7">" escape="false" />
</o:conditionalComment>
<o:conditionalComment if="IE 7">
<h:outputText value="<html lang="en" class="lt-ie9 lt-ie8">" escape="false" />
</o:conditionalComment>
<o:conditionalComment if="IE 8">
<h:outputText value="<html lang="en" class="lt-ie9">" escape="false" />
</o:conditionalComment>
<o:conditionalComment if="gt IE 8">
<h:outputText value="<!--><html lang="en" class="no-js"><!--" escape="false" />
</o:conditionalComment>
...
<h:outputText value="</html>" escape="false" />

Pretty awkward, but the HTML5 boilerplate (where this approach originated) is at its whole own also awkward, IMO.

Alternatively, you could consider creating a custom <my:html> component yourself which generates the desired markup so that you can just suffice with <my:html>...</my:html>.

Browser-dependent CSS switch with JSF

The only way is using <h:outputText escape="false">.

<h:outputText value="<!--[if IE 8]><link rel="stylesheet" type="text/css" href="#{cfgs.externalCssUrlIE8}" /><![endif]-->" escape="false" />

Yes, this is a line of ugliness. But there's no other standard way.


Update: the JSF utility library OmniFaces offers a <o:conditionalComment> for exactly this purpose so that you don't need the ugly <h:outputText escape="false"> anymore:

<o:conditionalComment if="IE 8">
<link rel="stylesheet" type="text/css" href="#{cfgs.externalCssUrlIE8}" />
</o:conditionalComment>

Strange issue with and being converted to and in javascript in my jsf app

You're using Facelets, which is a XML based view technology. JavaScript operators like >, &, etc are special characters in XML and are illegal when used for other purposes inside a XML file. Facelets is taking care of them this way.

I strongly recommend to put all that JS code in its own .js file and reference it by a <script src> or a <h:outputScript>.

E.g.

<script src="#{request.contextPath}/js/global.js"></script>

or

<h:outputScript name="js/global.js" />

Additional advantage is that you can finetune browser caching this way and end up in a more efficiently served website.


Unrelated to the concrete problem: please note how I referenced the libraries. You should prefer domain-relative paths over URI-relative paths. Using ../ is a maintenance pain. If you move the view or change the request URI, it'll break.



Related Topics



Leave a reply



Submit