Search code examples
htmlcssjsfprimefacesmenubar

How to prevent a p:menubar from being overlapped by the contents of a CSS template?


I have the following kind of layout on the header of the template I'm using.

enter image description here

This layout is made up of <p:panelGrid> which renders an HTML table.


I'm using the following template.

<?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 lang="#{localeBean.language}"
      xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:f="http://java.sun.com/jsf/core">

    <f:view locale="#{localeBean.locale}" encoding="UTF-8" contentType="text/html">

        <f:loadBundle basename="messages.ResourceBundle" var="messages"/>
        <ui:param name="contextPath" value="#{request.contextPath}"/>
        <ui:insert name="metaData"></ui:insert>

        <h:head>
            <title><ui:insert name="title">Default Title</ui:insert></title>
            <h:outputStylesheet library="default" name="css/block-ui.css"/>
            <h:outputStylesheet library="default" name="css/template.css"/>
        </h:head>

        <h:body id="body">
            <div id="container" class="clearfix">
                <div id="north"><ui:include src="/WEB-INF/client_template/content_bars/NorthMain.xhtml"/></div>
                <div id="west"></div>
                <div id="east"></div>
                <div id="content">
                    <ui:insert name="content">Put default content here, if any.</ui:insert>
                </div>
            </div>
            <div id="south"></div>
        </h:body>
    </f:view>
</html>

The CSS used is as follows (template.css).

html, body {
    height: 100%;
    min-width: 800px;
    margin: 0;
    padding: 0;
    font-family: "Helvetica Neue", Helvetica, Arial, Verdana, sans-serif;
    background: #fff;
    font-size: 12px;
}

#container {
    min-height: 100%;
    margin: 0 auto -90px;
}

#north {
    height: 165px;
    background: #fff;
}

#west {
    float: left;
    width: 120px;
    background: #fff;
}

#content {
    margin-left: 120px;
    margin-right: 120px;
    background: #fff;
}

#east {
    float: right;
    width: 120px;
    background: #fff;
}

#south, #container:after {
    height: 90px;
}

.clearfix:after {
    display: block;
    content: " ";
    clear: both;
}

#south {
    height: 300px;
    color: #444;
    background: #777;
    border-top: 7px solid #000;
    clear: both;padding: 15px;
}

This is from this answer.


I'm using a <p:menubar> on the header of the page as indicated the picture above. The menu is overlapped by the content - the menu goes behind the contents.

This happens because I'm using the following CSS class to clip the content of the <p:panelGrid> on the header, when the text it displays does not fit its cells - text-overflow: ellipsis.

.headerElipses {
    table-layout: fixed;
    width: 100%;
    border-collapse: collapse;
}

.headerElipses td {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

If this class is removed then, it works fine - the menu is not overlapped by the contents. I cannot avoid text-overflow: ellipsis because the application is multilingual and there are variable number of characters to be displayed in the <p:panelGrid> columns depending upon the language selected by a user in addition to displaying some dynamic text.

I have tried setting z-index to a higher value like

z-index: 20 !important;
overflow: visible !important;

to the #north CSS class above but it did not work.

How to prevent the <p:menubar> from being overlapped by the contents?


Solution

  • I found an answer but I dropped using <p:menubar> as well and instead chose a plain/vanilla HTML/CSS menu simply because <p:menubar> officially does not support clickable <p:submenu> inside it which also requires some JavaScript/jQuery tricks to make them clickable and even doing so does not function reliably.

    To the answer, I was using the table layout on the header as mentioned in the question that was generated by using <p:panelGrid> which in turn renders an HTML table as follows.

    <p:panelGrid styleClass="headerElipses">
        <p:row>
            <p:column rowspan="3">1</p:column>
            <p:column rowspan="3">2</p:column>
            <p:column>3</p:column>
            <p:column>4</p:column>
            <p:column>5</p:column>
            <p:column>6</p:column>
            <p:column>7</p:column>
            <p:column>8</p:column>
            <p:column>9</p:column>
            <p:column>10</p:column>
            <p:column>11</p:column>
            <p:column rowspan="3">12</p:column>
        </p:row>
    
        <p:row>
            <p:column colspan="5" rowspan="2">13</p:column>
            <p:column rowspan="2">14</p:column>
            <p:column>15</p:column>
            <p:column>16</p:column>
            <p:column>17</p:column>
        </p:row>
    
        <p:row>
            <p:column>18</p:column>
            <p:column>19</p:column>
            <p:column>20</p:column>
        </p:row>
    
        <p:row>
            <p:column>21</p:column>
            <!-- Only the following column is associated with the question -->
            <p:column colspan="10">22 The header menu goes here.</p:column>
            <p:column>23</p:column>
        </p:row>
    </p:panelGrid>
    

    Columns are given a fixed width. I dropped the whole CSS mess from this <p:panelGrid>.


    The CSS class headerElipses (there is a spelling mistake, of course. A class name like header-ellipsis is not recognized by browsers. I don't know the reason).

    .headerElipses {
        table-layout: fixed;
        width: 100%;
        border-collapse: collapse;
    }
    
    .headerElipses td {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
    

    In this CSS class, overflow: hidden; is responsible that prevents the menu from being displayed over the centre container.

    I simply overrode this style in the only table cell which holds the <p:menubar> as follows.

    <p:column colspan="10" style="overflow: visible !important; white-space: normal !important;">
        22 The header menu goes here.
    </p:column>
    

    In this cell, overflow: hidden; and white-space: nowrap; (including others) are not required at all.


    Note : I don't use the <p:layout> (or <pe:layout>) thing which only supports a full page layout util now in which the following CSS attributes need to be overridden in the respective classes to prevent a <p:menubar> on the north unit from being hidden behind the centre unit content.

    .ui-layout-north {
        z-index: 20 !important;
        overflow: visible !important;
    }
    
    .ui-layout-unit-content {
        overflow:visible !important;
    }