如何使用自定义样式覆盖默认的 PrimeFaces CSS?

Posted

技术标签:

【中文标题】如何使用自定义样式覆盖默认的 PrimeFaces CSS?【英文标题】:How do I override default PrimeFaces CSS with custom styles? 【发布时间】:2012-02-04 19:13:45 【问题描述】:

我想更改 PrimeFaces 组件的大小。例如,<p:orderList>。它有一个名为ui-orderlist-list 的类,它在primefaces.css 中定义,尺寸固定为200x200。无论我在theme.css 中做什么,它都会被此属性覆盖,我无法使<p:orderList> 的内容部分更宽。

对于其他组件,我可能只想覆盖组件的一个实例,而不是全部。

谁能告诉我该怎么做?

【问题讨论】:

【参考方案1】:

您需要考虑几件事,其中一项或多项可能与您的具体情况相关

PrimeFaces one

之后加载你的CSS

您需要确保您的 CSS 是在 PrimeFaces 之后加载的。您可以通过将引用您的 CSS 文件的 <h:outputStylesheet> 放置在 <h:body> 而不是 <h:head> 中来实现此目的:

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

JSF 会自动将样式表重新定位到生成的 html &lt;head&gt;end,从而确保样式表在 PrimeFaces 的默认样式之后加载。这样,您的 CSS 文件中与 PrimeFaces CSS 文件中完全相同的选择器将优先于 PrimeFaces。

您可能还会看到将其放入 &lt;f:facet name="last"&gt;&lt;h:head&gt; 的建议,PrimeFaces 特定的 HeadRenderer 可以理解这一点,但这是不必要的笨拙,并且当您拥有自己的 HeadRenderer 时会中断。

了解 CSS 的特殊性

您还需要确保您的 CSS 选择器至少与特定元素上 PrimeFaces 的默认 CSS 选择器一样具体。您需要了解CSS Specificity 和Cascading and Inheritance rules。例如,如果 PrimeFaces 默认声明一个样式如下

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

你把它声明为

.ui-bar 
    color: purple;

并且带有class="ui-bar" 的特定元素恰好有一个带有class="ui-foo" 的父元素,那么PrimeFaces 的元素仍然会获得优先权,因为这是最具体的匹配!

您可以使用 webbrowser 开发者工具来找到准确的 CSS 选择器。在网络浏览器 (IE9/Chrome/Firefox+Firebug) 中右键单击有问题的元素,然后选择 Inspect Element 来查看它。

部分覆盖

如果您只需要为组件的特定实例而不是同一组件的所有实例覆盖样式,请添加自定义 styleClass 并挂钩。这是使用/应用特异性的另一种情况。例如:

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

如果组件不支持 styleClass 而您使用的是 jsf 2.2 或更高版本,您也可以使用 passtrough attributes 并添加 pt:class 并在输出中结束。

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

永远不要使用 !important

如果您未能按顺序正确加载 CSS 文件或无法找到正确的 CSS 选择器,您可能会使用!important 解决方法。这是完全错误的。这是一个丑陋的解决方法,而不是真正的解决方案。从长远来看,它只会混淆你的风格规则和你自己。 !important 应该用于覆盖来自 CSS 样式表文件的 HTML 元素的 style 属性中硬编码的值(这反过来也是一种不好的做法,但在极少数情况下不幸的是不可避免的)。

另见:

How to reference CSS / JS / image resource in Facelets template? Mozilla Developer Network > CSS > Specificity(好文章,必读!) Understanding Style Precedence in CSS: Specificity, Inheritance, and the Cascade

【讨论】:

一个不错的技巧是在 PrimeFaces 选择器前加上 html 前缀,以使它们更具体。 如何根据 p:dialog id="myDialog" 之类的元素 ID 修改 CSS?我已经用它创建了自己的 CSS 样式表,并添加了针对该 ID 的样式,但它看起来不起作用。使用 PF v5.3 的网络应用 使用 !important 覆盖来自外部库(如 Primefaces 或 Bootstrap)的外部 CSS 并不是一个坏习惯。请阅读您参考的文章。 @Luis: 也许你错过了 " !important 应该用于从 CSS 样式表覆盖 HTML 元素的 style 属性中硬编码的值文件在“答案中。【参考方案2】:

您可以创建一个新的 css 文件,例如 cssOverrides.css

并在其中放置您想要的所有覆盖,这样升级primefaces版本不会影响您,

并在您的 h:head 中添加类似的内容

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

如果它不起作用,请尝试将其添加到 h:body

为了检查它是否正常工作,试试这个 css 文件中的简单示例

.ui-widget 
   font-size: 90% !important;

这将减小所有 primefaces 组件 /text 的大小

【讨论】:

【参考方案3】:

我正在使用 PrimeFaces 6.0。以下是我希望了解的一些信息:

如果您使用&lt;h:outputStylesheet/&gt;,它会起作用,但您的 CSS 不会最后加载,即使它在 &lt;h:head&gt;&lt;/h:head&gt; 标记中是最后一个(之后会包含其他 CSS 文件)。我从here 学到的一个技巧是把它放在&lt;f:facet name="last"&gt;&lt;/f:facet&gt; 中,必须进入正文,如下所示:

<h:body>
  <f:facet name="last">
    <h:outputStylesheet name="css/MyCSS.css" />
  </f:facet>
...

那么你的 CSS 将是最后加载的。 注意:您仍然必须遵守 BalusC 概述的特异性规则。

我将“MyCSS.css”放在 WebContent/resources/css/ 中。

更多资源加载顺序:http://www.mkyong.com/jsf2/primefaces/resource-ordering-in-primefaces

【讨论】:

【参考方案4】:

在 PrimeFaces 之后加载你的 CSS?

虽然在 PrimeFaces CSS 之后加载 CSS 会覆盖现有规则,但我认为这不是一个好主意。最好创建更具体的规则。无论顺序如何,更具体的规则总是会“获胜”。例如,如果您将组合资源处理程序与 PrimeFaces 扩展 LightSwitch 结合使用,则切换后的 PrimeFaces 主题将最后加载,使其以相同的规则“获胜”!

如何创建更具体的规则

PrimeFaces 使用的样式规则可能相当复杂。一个元素可以从多个 CSS 规则中接收其样式。很高兴知道您可以在 DOM 检查器的样式选项卡中使用过滤来搜索您要自定义的属性:

此屏幕截图是使用 Chrome 截取的,但在 Firefox 和 Safari 中也可以进行过滤。

找到要自定义的规则后,只需在规则前加上 html 即可创建更具体的规则。例如,您可以覆盖.ui-corner-all,例如:

html .ui-corner-all 
  border-radius: 10px;

使用style 属性

PrimeFaces 组件可以呈现相当复杂的 HTML。通常,style 属性仅应用于组件呈现的最外层 HTML 节点。此外,style 不可重用,因此最好设置 styleClass 并根据您设置的类创建 CSS 规则。这也允许您为组件呈现的内部 HTML 节点设置样式。

使用styleClass 属性

PrimeFaces 带有许多内置类的主题(和模板)。您可能会发现现有类已经完成了您想要的自定义。例如,要从p:panelGrid 中删除边框,可以简单地应用ui-noborder 类。或者我们最近添加到 PrimeFaces 10 的类来设置按钮样式,例如 ui-button-warning

见:

How to remove border from specific PrimeFaces p:panelGrid? https://www.primefaces.org/showcase/ui/button/commandButton.xhtml

使用ResourceHandler 替换主题值

我通常只想用另一个值替换一些颜色。由于可以在许多不同的规则中使用颜色,因此创建 ResourceHandler 会很有用。

在处理程序中检查 PrimeFaces 主题:

@Override
public Resource createResource(String resourceName,
                               String libraryName) 
  if (isPrimeFacesTheme(resourceName, libraryName)) 
    return new MyResource(super.createResource(resourceName, libraryName), this);
  
  else 
    return getWrapped().createResource(resourceName, libraryName);
  


protected boolean isPrimeFacesTheme(final String resourceName,
                                    final String libraryName) 
  return libraryName != null
                 && libraryName.startsWith("primefaces-")
                 && "theme.css".equals(resourceName);

在资源中,替换颜色:

private static String cache;

public MyResource(Resource wrapped, ResourceHandler handler) 
  this.wrapped = wrapped;
  this.handler = handler;
  this.charset = Charset.forName(FacesContext.getCurrentInstance().getExternalContext().getRequestCharacterEncoding());


@Override
public InputStream getInputStream() throws IOException 
  if (cache == null) 
    cache = readInputStream(getWrapped().getInputStream());
    // Replace values
    cache = cache.replace("#007ad9", "#11dd99");
  
  return new ByteArrayInputStream(cache.getBytes(charset));

并在faces-config.xml中注册如下:

<application>
  <resource-handler>com.example.MyResourceHandler</resource-handler>
</application>

PrimeFaces Extension 10.0.1 中提供了一个资源处理程序,它用 CSS 变量替换 Arya、Saga 和 Vela 主题的强调色,请参阅 https://www.primefaces.org/showcase-ext/sections/utils/themeAccentColorResourceHandler.jsf。

有关资源处理程序的更多信息,请参阅:

How to load dynamic resources in JSF?

【讨论】:

【参考方案5】:

遵循接受答案的相同想法,但不使用

并且使用模板,我必须实现在Primefaces自己之后但在页面的标题块处加载.css文件的目标。

模板.xhtml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
    <h:head>
        <title><ui:insert name="title">TEST</ui:insert></title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
        <ui:insert name="headcontent"></ui:insert>
    </h:head>
    <h:body>
        <div id="content">
            <ui:insert name="content"></ui:insert>
        </div>
        <div id="bottom">
            <ui:insert name="bottom"></ui:insert>
        </div>
    </h:body>
</html>

main.xhtml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition template="template.xhtml"
                xmlns="http://www.w3.org/1999/xhtml"
                xmlns:h="http://xmlns.jcp.org/jsf/html"
                xmlns:f="http://xmlns.jcp.org/jsf/core"
                xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
                xmlns:p="http://primefaces.org/ui"
                xmlns:fn="http://xmlns.jcp.org/jsf/jstl/functions">

    <ui:define name="title">TEST</ui:define>
    <ui:define name="headcontent">
        <link type="text/css" rel="stylesheet" href="../resources/css/index.css"/>
    </ui:define>

    <ui:define name="content">
        ...
    </ui:define>
    
    <ui:define name="bottom">
        ...
    </ui:define>
</ui:composition>

这些是如何使用插入源 .css 或 .scripts 文件的示例

因此,自定义 .css 或 .js 文件在 Primefaces 文件之后加载,如果您在浏览器中查看页面信息,您会看到这些行被插入到页面标题块的末尾。

【讨论】:

归结为***.com/a/8770795/880619 想象有一个很大的自定义 .css 文件。可能在每行之后都有!important; 有点乏味。尽管如此,这并不是一个坏例子,它可能很有用。

以上是关于如何使用自定义样式覆盖默认的 PrimeFaces CSS?的主要内容,如果未能解决你的问题,请参考以下文章

清除primefaces样式

React Antd 中如何修改覆盖默认样式及样式引用

React Antd 中如何修改覆盖默认样式及样式引用

我们可以用angular中的自定义css覆盖选择器的默认样式吗

Primefaces 中全局更改的默认样式

如何扩展而不是覆盖 WPF 样式