SharePoint 2013 – Animated Hiding Ribbon

This is part three of my series on modifying the SharePoint 2013 suite bar and ribbon in a safe and SharePoint friendly manner.

Part one: “Collapse the Suite Bar and Ribbon to One Line
Part two: “On Demanding Hiding the Suite Bar and Ribbon

In part three, I will extend my previous post that investigated dynamically hiding or showing the suite bar / ribbon by providing animation for the given event. I will base the Master Page, CSS and JavaScript modifications on my previous post, thus I recommend you first familiarize yourself with that post to see how I customized the HTML Master Page and provided custom CSS and JavaScript.

There are multiple methods to provide animation on a webpage. I am going to look at three techniques. First I will use jQuery, then I will use CSS3 transitions and finally I will look at a preferred hybrid solution.

Animation with jQuery

jQuery provides an easy to use function to allow the animation of CSS properties, “animate()“. By adding a little JavaScript and CSS to my previous post, I can achieve reasonable animation while hiding or showing the suite bar / ribbon.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/*style our custom, clickable ribbon toggle bar*/
#pm-ribbon-toggle-bar {
   background: #0072c6 none;
   display: block;
   height: 10px;
   width: 100%;
}
#pm-ribbon-toggle-bar:hover {
   cursor: pointer;
}

/*fix OOTB bug, this box may need to be taller to take into account a ribbon with additional controls*/
#globalNavBox {
   height: auto;
   min-height: 35px;
}

#ms-designer-ribbon > div:first-child {
   max-height: 200px;
   display: block;
}

/*Remove the additonal space under the status bar if it appears, tightens up design*/
#pageStatusBar[class], .ms-status-msg {
   margin-bottom: 0px;
}

/*requested to hide the suitebar/ribbon*/
#ms-designer-ribbon.hidden > div:first-child {
   display: none;
}

/*class used to ensure overflow hidden when animation occurring, controlled by jQuery and delay*/
#ms-designer-ribbon.hidden-overflow > div:first-child {
   overflow: hidden;
}

In the above CSS, I added two new styles, #ms-designer-ribbon > div:first-child and #ms-designer-ribbon.hidden-overflow > div:first-child. The first style provides an initial max-height, giving us the ability to animate the max-height of our main wrapper. The second style will be used to make sure that while the wrapper max-height is being modified, the only aspects of the suite bar / ribbon that shows is that which fits within the current wrapper.

Next we need to modify the custom JavaScript.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/*custom*/
jQuery(document).ready(function($) {
   var ribbonWrapper = $('#ms-designer-ribbon');
   
   //create a bar that we can show or hide
   var ribbonToggleBar = $('<div id="pm-ribbon-toggle-bar"></div>');
   
   //bind "click" to this bar, when clicked we will toggle the class "hidden" on the #ms-designer-ribbon selector
   //Using css, we can then style the ribbon elements to display or hide
   ribbonToggleBar.bind('click', function(e) {
      e.preventDefault();
      var t = $(this);
     
      //get the new max height property based on if hidden or not
      var maxHeight = $(this).parent().hasClass('hidden') ? 200 : 0;
     
      //if currently hidden, then need to show
      if (t.parent().hasClass('hidden')) {
         //allow ribbon to appear
         t.parent().toggleClass('hidden');
               
         t.siblings('div').eq(0).animate({
            'maxHeight': maxHeight},
            1000,
            'swing',
            function() {           
               //toggle our overfow hidden class
               t.parent().toggleClass('hidden-overflow');

               //and always make sure to execute OOTB function to have workspace resize
               FixRibbonAndWorkspaceDimensions();
         });
      }
      else { //we need to hide
         //toggle our overfow hidden class
         t.parent().toggleClass('hidden-overflow');

         t.siblings('div').eq(0).animate({
            'maxHeight': maxHeight},
            1000,
            'swing',
            function() {           
               //record that ribbon is hidden
               t.parent().toggleClass('hidden');
               
               //and always make sure to execute OOTB function to have workspace resize
               FixRibbonAndWorkspaceDimensions();
         });
      }
   });
   
   //finally add our bar to the dom
   ribbonWrapper.append(ribbonToggleBar);
   //and make sure to execute OOTB function to have workspace resize
   FixRibbonAndWorkspaceDimensions();
});

There is now more going on in the JavaScript code than my previous post. In particular I modified the click event. First, notice that I created a new var t which points to the element that has been clicked. I use this reference later when another event finishes, i.e. after an animation completes.

Second, I figure out what size the new max-height should be, either 0 or 200. 200 refers to max-height of the visible ribbon. OOTB, SharePoint does not provide a max-height style but we need a value that will reasonably contain the entire suite bar / ribbon. You may change this value to meet your needs based on how many expected status messages you end up expecting.

Finally I hide or show the suite bar / ribbon based on if it is currently shown of hidden.

If the ribbon is hidden, then we will remove the class hidden from the wrapper, thus allowing our ribbon to display. Next we use animate() to change the max-height CSS property of the wrapper to provide space for the suite bar / ribbon. Once the animation is complete, we need to remove the class hidden-overflow from the wrapper so that ribbon menus may appear.

If the ribbon is shown, then we need to hide all overflow first by adding hidden-overflow to the wrapper, then animate the max-height style of the wrapper to begin hiding the suite bar / ribbon. Once the animation is complete we finally record that the suite bar / ribbon is hidden by adding the hidden class to the wrapper.

Pretty simple. You can add different easing functions if you also include the jQuery UI suite to jQuery. Refer to the jQuery animate() function page for more details.

My major issue with this technique is that we are using jQuery. This can be clunky and CPU intensive for mobile devices. It would be better is we could use only CSS for animation. Luckily we can with CSS3 capable browsers (IE9+, most other browsers and most smartphones). Let’s recode our solution by using CSS3 Transitions.

Animation with CSS3 Transition

First in the CSS there is one major change, I added the style transition: max-height .5s ease 0s; to the selector #ms-designer-ribbon > div:first-child. Learn more about how to use CSS3 Transitions at W3 Schools.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/*style our custom, clickable ribbon toggle bar*/
#pm-ribbon-toggle-bar {
   background: #0072c6 none;
   display: block;
   height: 10px;
   width: 100%;
}
#pm-ribbon-toggle-bar:hover {
   cursor: pointer;
}

/*fix OOTB bug, this box may need to be taller to take into account a ribbon with additional controls*/
#globalNavBox {
   height: auto;
   min-height: 35px;
}

#ms-designer-ribbon > div:first-child {
   transition: max-height .5s ease 0s;
   max-height: 200px;
   display: block;
}


/*Remove the additional space under the status bar if it appears, tightens up design*/
#pageStatusBar[class], .ms-status-msg {
   margin-bottom: 0px;
}

/*requested to hide the suitebar/ribbon*/
#ms-designer-ribbon.hidden > div:first-child {
   max-height: 0px;
   overflow: hidden;
}
/*class used to ensure overflow hidden when animation occurring, controlled by jQuery and delay*/
#ms-designer-ribbon.hidden-overflow > div:first-child {
   overflow: hidden;
}

In general if a browser such as IE8 cannot handle the transition style, it will be ignored. But we can use Modernizr to feature detect CSS3 transitions, which I will address in our hybrid solution.

There is one issue with the above CSS. Remember how in the jQuery only solution we toggled the hidden-overflow class? This is important as we need to hide overflow of the ribbon when the ribbon is collapsed, or while we are animating the ribbon. Once the suite bar / ribbon is fully displayed, we need to make sure that this class has been removed. We need to do the same with with transitions, so we will use the jQuery delay() function to help us.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/*custom*/
jQuery(document).ready(function($) {
   var ribbonWrapper = $('#ms-designer-ribbon');
   
   //create a bar that we can show or hide
   var ribbonToggleBar = $('<div id="pm-ribbon-toggle-bar"></div>');
   
   //bind "click" to this bar, when clicked we will toggle the class "hidden" on the #ms-designer-ribbon selector
   //Using css, we can then style the ribbon elements to display or hide
   ribbonToggleBar.bind('click', function(e) {
      e.preventDefault();
      $(this).parent().toggleClass('hidden');

      //wait until our transition is complete      
      $(this).parent().delay(500).queue(function(next) {
         //now toggle our overfow hidden class
         $(this).toggleClass('hidden-overflow');

         //and always make sure to execute OOTB function to have workspace resize
         FixRibbonAndWorkspaceDimensions();
         next();
      });
   });

   //finally add our bar to the dom
   ribbonWrapper.append(ribbonToggleBar);
   //and make sure to execute OOTB function to have workspace resize
   FixRibbonAndWorkspaceDimensions();
});

I was able to get ride of all of the jQuery click logic from the jQuery only solution and simply queue up new logic to occur 500 ms after a click as occurred. This 500 ms corresponds to the CSS3 transition property in our CSS.

The Hybrid Approach

Using CSS3 transitions means that IE8 users will not see any animation, the suite bar / ribbon will just appear or disappear. That is possibly OK for many, but if we include Modernizr, a feature detection library, we can update our solution to use CSS3 for transition capable browsers yet revert to JavaScript for the rest (i.e. IE8).

First we will update our HTML Master Page to reference the Modernizr library. If you create your own Modernizr build, be sure it includes CSS Transitions.

1
2
3
4
   <link rel="stylesheet" type="text/css" href="custom/css/styles.css" />
   <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
   <script src="custom/js/modernizr.custom.min.js"></script>
   <script src="custom/js/header.js"></script>

If CSS3 transitions are available, Modernizr adds the class csstransitions to the <html> element. Therefore we can change the following CSS:

1
2
3
4
5
#ms-designer-ribbon > div:first-child {
   transition: max-height .5s ease 0s;
   max-height: 200px;
   display: block;
}

to:

1
2
3
4
5
6
7
8
#ms-designer-ribbon > div:first-child {
   max-height: 200px;
   display: block;
}

.csstransitions #ms-designer-ribbon > div:first-child {
   transition: max-height .5s ease 0s;
}

View the complete CSS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/*style our custom, clickable ribbon toggle bar*/
#pm-ribbon-toggle-bar {
   background: #0072c6 none;
   display: block;
   height: 10px;
   width: 100%;
}
#pm-ribbon-toggle-bar:hover {
   cursor: pointer;
}

/*fix OOTB bug, this box may need to be taller to take into account a ribbon with additional controls*/
#globalNavBox {
   height: auto;
   min-height: 35px;
}

#ms-designer-ribbon > div:first-child {
   max-height: 200px;
   display: block;
}

.csstransitions #ms-designer-ribbon > div:first-child {
   transition: max-height .5s ease 0s;
}

/*Remove the additional space under the status bar if it appears, tightens up design*/
#pageStatusBar[class], .ms-status-msg {
   margin-bottom: 0px;
}

/*requested to hide the suitebar/ribbon*/
#ms-designer-ribbon.hidden > div:first-child {
   max-height: 0px;
   overflow: hidden;
}
/*class used to ensure overflow hidden when animation occurring, controlled by jQuery and delay*/
#ms-designer-ribbon.hidden-overflow > div:first-child {
   overflow: hidden;
}

Modernizr also provides us a JavaScript Modernizr object property bag that we can use to check to see if transitions are available, i.e. Modernizr.csstransitions. We can then merge the two JavaScript examples from above to create one script that uses CSS3 transitions when available, otherwise revert to JavaScript for animation.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/*custom*/
jQuery(document).ready(function($) {
   var ribbonWrapper = $('#ms-designer-ribbon');
   
   //create a bar that we can show or hide
   var ribbonToggleBar = $('<div id="pm-ribbon-toggle-bar"></div>');
   
   //bind "click" to this bar, when clicked we will toggle the class "hidden" on the #ms-designer-ribbon selector
   //Using css, we can then style the ribbon elements to display or hide
   ribbonToggleBar.bind('click', function(e) {
      e.preventDefault();
     
      //if transitions allowed
      if (Modernizr.csstransitions) {
         $(this).parent().toggleClass('hidden');
   
         //wait until our transition is complete     
         $(this).parent().delay(500).queue(function(next) {
            //now toggle our overfow hidden class
            $(this).toggleClass('hidden-overflow');
   
            //and always make sure to execute OOTB function to have workspace resize
            FixRibbonAndWorkspaceDimensions();
            next();
         });
      }
      else {
         var t = $(this);
         
         //get the new max height property based on if hidden or not
         var maxHeight = $(this).parent().hasClass('hidden') ? 200 : 0;
         
         //if currently hidden, then need to show
         if (t.parent().hasClass('hidden')) {
            //allow ribbon to appear
            t.parent().toggleClass('hidden');
                 
            t.siblings('div').eq(0).animate({
               'maxHeight': maxHeight},
               1000,
               'swing',
               function() {            
                  //toggle our overfow hidden class
                  t.parent().toggleClass('hidden-overflow');
   
                  //and always make sure to execute OOTB function to have workspace resize
                  FixRibbonAndWorkspaceDimensions();
            });
         }
         else { //we need to hide
            //toggle our overfow hidden class
            t.parent().toggleClass('hidden-overflow');
   
            t.siblings('div').eq(0).animate({
               'maxHeight': maxHeight},
               1000,
               'swing',
               function() {            
                  //record that ribbon is hidden
                  t.parent().toggleClass('hidden');
                 
                  //and always make sure to execute OOTB function to have workspace resize
                  FixRibbonAndWorkspaceDimensions();
            });
         }
      }
   });

   //finally add our bar to the dom
   ribbonWrapper.append(ribbonToggleBar);
   //and make sure to execute OOTB function to have workspace resize
   FixRibbonAndWorkspaceDimensions();
});

There you have it, an animated, hide on demand suite bar / ribbon that is IE8+ friendly that uses CSS3 transitions when available.

Comments

  1. Hi- I was wondering what if you wanted the on click event to default to hide the toggle bar. Rather than having it be on click only but to default to hidden

    • eshera talison says:

      Curious if you every found a way to do this… I would also like the bar to be hidden on load and then display when clicked.

Speak Your Mind

*