Display footer in PrimeFaces template, when fullPage of p:layout is set to false

Tiny picture Tiny · Mar 23, 2014 · Viewed 11.8k times · Source

Footer is not displayed (actually, it is incorrectly displayed on top of the page), when fullPage is set to false in PrimeFaces template.

<p:layout fullPage="false">
    <p:layoutUnit position="north" size="135">
        <!--Put north content here, if any-->
    </p:layoutUnit>

    <p:layoutUnit position="west" size="225" header="Menu Item" collapsible="true">
        <!--Put west content here, if any-->
    </p:layoutUnit>

    <p:layoutUnit position="center" size="2500" maxSize="2500">
        <!--Put center content here, if any-->
    </p:layoutUnit>

    <p:layoutUnit position="east" size="175">
        <!--Put east content here, if any-->
    </p:layoutUnit>

    <p:layoutUnit position="south" size="90">
        <!--Put south/footer content here, if any-->
    </p:layoutUnit>
</p:layout>

How to display footer, when fullpage is set to false?


EDIT :

if <p:layout> is given a height like as follows,

<p:layout fullPage="false" style="height: 2000px;">

then the footer is displayed at the bottom of the page based on the value of the height CSS attribute but it is still not a sticky footer - it does not adjust according to the page contents.

So, Is there a way to make it sticky?


Update :

The behaviour remains stationary on PrimeFaces 5.3 final (community release), when fullPage is set to false as said previously throughout the question.

Answer

BalusC picture BalusC · Apr 29, 2014

To easily visualize what you ultimately need (and to confirm your needs for myself), here's in SSCCE flavor a pure HTML/CSS solution of what you're (apparently) asking for. The sticky footer solution is largely based on Ryan Fait's approach (a min-height:100% and a negative margin on the container element which covers everything but footer), it only doesn't support IE6/7 anymore (due to :after pseudoselector), hereby simplifying the HTML markup (no non-semantic clutter like <div id="pushfooter"> needed). Note: background colors are purely for visualization.

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Stack Overflow Question 22584920</title>
        <style>
            html, body {
                height: 100%;
                min-width: 800px;
                margin: 0;
            }
            #container {
                min-height: 100%;
                margin: 0 auto -90px; /* Negative of #footer.height */
            }
            #header {
                height: 135px;
                background: pink;
            }
            #menu {
                float: left;
                width: 225px;
                background: khaki;
            }
            #content {
                margin-left: 225px; /* Same as #menu.width */
                margin-right: 175px; /* Same as #side.width */
                background: lemonchiffon;
                padding: 1px 1em; /* Fixes collapsing margin of p's on div, feel free to remove it */
            }
            #side {
                float: right;
                width: 175px;
                background: palegreen;
            }
            #footer, #container:after {
                height: 90px;
            }
            #footer {
                background: orange;
            }
            .clearfix:after {
                display: block;
                content: " ";
                clear: both;
            }
        </style>
    </head>
    <body>
        <div id="container" class="clearfix">
            <div id="header">Header</div>
            <div id="menu">Menu</div>
            <div id="side">Side</div>
            <div id="content">
                <p>Content</p><p>Content</p><p>Content</p><p>Content</p><p>Content</p>
            </div>
        </div>
        <div id="footer">Footer</div>
    </body>
</html>

Note: due to the way how floats work, the <div id="side"> (the "east unit") has in the HTML markup to be placed before all non-floating elements at the same "row", such as the <div id="content"> (the "center unit"), otherwise it will be aligned relative to the bottom of the last non-floating element.

Now, in order to achieve exactly the same with the <p:layout> thing, which basically renders almost the same HTML structure, only with the footer still inside the container and the east unit after the center unit, you need to make sure that no one of the layout units are collapsible/closable/resizable (those attributes all already default to false and can thus be omitted for brevity) and that you apply the PrimeFaces-builtin clearfix style class ui-helper-clearfix on the container unit to clear the floats (otherwise the menu, content and side would overlap the footer when the screen is shrunk vertically):

<p:layout styleClass="ui-helper-clearfix">
    <p:layoutUnit position="north" size="135">
        <p>Header</p>
    </p:layoutUnit>
    <p:layoutUnit position="west" size="225" header="Menu Item">
        <p>Menu</p>
    </p:layoutUnit>
    <p:layoutUnit position="center">
        <p>Content</p>
        <p>Content</p>
        <p>Content</p>
        <p>Content</p>
        <p>Content</p>
    </p:layoutUnit>
    <p:layoutUnit position="east" size="175">
        <p>Side</p>
    </p:layoutUnit>
    <p:layoutUnit position="south" size="90">
        <p>Footer</p>
    </p:layoutUnit>
</p:layout>

Then you can apply the following CSS in your PrimeFaces-override stylesheet to remove/override all "irrelevant" PrimeFaces-generated CSS properties on those layout units by setting the absolute positioning with fixed offsets/dimensions back to initial/default values (note: the exact purpose of !important is being able to override hardcoded/inline style properties from a true stylesheet on, there's in this particular case simply no other option as long as you don't want to rewrite PrimeFaces components and renderers). Key point is that you should end up with exactly the same HTML/CSS (defaults) as the SSCCE:

html, body {
    height: 100%;
    min-width: 800px;
    margin: 0;
}
.ui-layout-container {
    min-height: 100%;
    height: auto !important;
    margin: 5px;
    margin-bottom: -90px; /* Negative of footer height. */
}
.ui-layout-unit {
    position: static !important;
    top: auto !important;
    bottom: auto !important;
    left: auto !important;
    right: auto !important;
    height: auto !important;
}
.ui-layout-unit-content {
    display: block !important;
    height: auto !important;
}
.ui-layout-west {
    float: left;
    margin: 5px 0 !important;
}
.ui-layout-center {
    margin: 5px 0 !important;
    margin-left: 230px !important; /* Menu width plus margin between panels. */
    margin-right: 180px !important; /* Side width plus margin between panels. */
}
.ui-layout-east {
    float: right;
    margin: 5px 0 !important;
}
.ui-layout-container:after {
    height: 85px; /* Footer height minus margin between panels. */
}
.ui-layout-south {
    margin: 5px !important;
    visibility: visible !important;
}

And finally add the following script in order to move the side (east unit) before the content (center unit), so that the floats go as intented, and to move the footer to end of body, so that it's outside the container element:

$(function() { 
    $(".ui-layout-east").insertBefore(".ui-layout-center");
    $(".ui-layout-south").appendTo("body");
});

Make sure that this script is re-executed when you do an ajax update with @all on the same view for some reason (which is at its own a bad idea though).

With this "solution" (I'd rather call it a hack and just throw it all away and go for a sane and clean HTML/CSS solution, if necessary with <p:panel>s instead of <div>s), it's still somewhat brittle; the auto-included layout.js script auto-adjusts the layout units on every window resize. But so far they don't seem to break anything in all modern browsers I tried (IE>8).