Bootstrap affix on fluid design

Goal

Using an affixed bootstrap side menu on a fluid design that keeps its width during page scroll

Description

In one of the projects I worked on, lately, I had the need to create a left side menu that would move with the page during a page scroll. I was using Bootstrap 2 on that application and therefore I started using the affix plugin.

However, there was a bug on that menu because, when the left side menu was changed to the affix-top with position fixed on top (I also realized that if I had the left menu with a specific width right on the beginning, that would solve my problem but that width was not easy to specify on a fluid design, because I wanted that width to be adaptable – for different screen resolutions, the menu should occupy as much as possible of the left side of the page), the width of the menu was not maintained. After some google research, I found out an issue regarding “Bootstrap Affix plugin with fluid layout” reported on stackoverfow. After following that link, I found out the solution, which is explained next.

How to

Use Javascript to fetch the initial left side menu width and specify it later on the component so that the width is maintained during page scroll. The following snippet shows the page structure containing the left side menu:

<?xml version="1.0"?>
<!DOCTYPE html>
<f:view xmlns="http://www.w3.org/1999/xhtml"
    xmlns:c="http://java.sun.com/jsp/jstl/core"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:p="http://primefaces.org/ui"
    xmlns:ui="http://java.sun.com/jsf/facelets">
  ...
  <h:body>
    <h:panelGroup layout="block" styleClass="row-fluid">
      <h:panelGroup layout="block" styleClass="span3">
        <div id="affixed_element" class="scrollspy" 
          data-spy="affix"
          data-offset-top="129">
          <section id="topic-bar" class="topic-bar">
            <h2>
              <i class="fa #{portlet_page_icon}" /> #{portlet_page_title}
            </h2>
            <ui:insert name="page_menu"></ui:insert>
          </section>
        </div>
      </h:panelGroup>
      <h:panelGroup layout="block" styleClass="span9">
        ...
      </h:panelGroup>
    </h:panelGroup>
  </h:body>
</f:view>

Notice the specification of an id for the div containing the data-spy element. That id is what will be looked for with JQuery to get the div’s width and specify it explicitly later on (the function is specified in a namespace named ENGAGE which is the project’s name):

var ENGAGE = (function() {
    return {
        affixWidth : function() {
            // ensure the affix element maintains its width
            var affix = $('#affixed_element');
            var width = affix.width();
            affix.width(width);
        }
    };
})();

Finally, all we need to do is to include the call to the function at the end of the page containing the affixed div (the first code snipped shown):

<?xml version="1.0"?>
<!DOCTYPE html>
<f:view xmlns="http://www.w3.org/1999/xhtml"
    xmlns:c="http://java.sun.com/jsp/jstl/core"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:p="http://primefaces.org/ui"
    xmlns:ui="http://java.sun.com/jsf/facelets">
  <h:body>
    <script type="text/javascript">
      /**
       * This makes it possible for the affixed 
       * element to maintain its width during scroll
       */
      $(document).ready(function() {
        ENGAGE.affixWidth();
      });
    </script>
  </h:body>
</f:view>

Finally, in case you want to deal with browser resize, the following is something you may add to your page:

$( window ).resize(function() {
  $('#affixed_element.affix-top').width('100%');
  ENGAGE.affixWidth();
});
            
$( window ).resize(function() {
  $('#affixed_element.affix').width('inherit');
  ENGAGE.affixWidth();
});

Explanations

With this solution, we wait for the left side menu to be displayed with the appropriate width, according to the browser’s resolution and, on document ready, we explicitly specify the menu with that width. Therefore, during page scroll, the menu keeps its width.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s