Monday, May 24, 2010

Customizing Ribbon Positioning in SharePoint 2010 Master Pages

As you’ll likely notice in SharePoint 2010, the Ribbon is specially positioned to always be visible on the screen, even if you scroll down the page contents. This is accomplished by placing the Ribbon into its own container and then using client-side script to make the rest of the page contents take up the remainder of the browser’s height. You can see this in action by switching between the “Browse” tab and the “Page” tab on the SharePoint default homepage: The top of the scrollbar on the right side of the browser window will move up and down depending on whether the Ribbon is opened or not.
One of the questions we hear most often is how to enable or disable this behavior on a custom master page. To answer this question, I need to explain more about how the system works. There are three parts of the system: The markup on the master page, the CSS styles in the stylesheet, and the ECMAScript code linked to on the page.

Master Page Markup


Let’s start with the markup. SharePoint 2010 compatible master pages require many components, but there are a few key components that are used by the Ribbon positioning system. Going from top to bottom, the first component of note is the “_fV4UI” ECMAScript variable. In v4.master, it looks like this:

<script type=”text/javascript”>

var _fV4UI = true;

</script>

This block tells the rest of the ECMAScript code in SharePoint that this master page is operating in SharePoint version 4 mode (version 4 corresponds to SharePoint 2010). This variable is used in the script that handles Ribbon positioning which I’ll discuss later on.
Moving down the master page source code, the next interesting component is the “body” tag. In v4.master, it looks like this:
<body scroll=”no” onload=”...” class=”v4master”>

The two important parts of the tag are the “scroll” and “class” attributes. The “scroll” attribute is used to force IE to hide the page scrollbar. Since SharePoint handles the scrollbar independently, we need to stop the browser from interfering. For other browsers, the scrollbar is hidden using CSS styles which are explained later in this post. The CSS class applied to the “body” tag is used to apply CSS styles in the corev4.css stylesheet which are part of the Ribbon positioning system. If you are using a custom stylesheet, you may leave this out; but make sure to apply the needed CSS styles in some other way (perhaps by referencing “body” directly in your stylesheet).

The next important component on the master page is the Ribbon container. In v4.master, it looks like this:


<div id=”s4-ribbonrow” class=”s4-pr s4-ribbonrowhidetitle”>
</div>


Let’s look at this piece by piece. First, you’ll notice that the element is a div so that it takes up the width of the browser and acts as a block-level HTML element. After that, is the ID which is a mandatory part of the system: the ECMAScript logic for Ribbon positioning uses this ID to find the Ribbon container. If you omit or change this ID, the Ribbon positioning system will abort and your Ribbon will not stay docked to the top of the page. I’ll discuss the steps to enable and disable the system later on in this post. The next part of the Ribbon container element is the “class” attribute which lists the CSS classes applied to it. The first one is just a layout class used to make the container full width and block displayed. “pr” stands for Page Row. The second CSS class is used in the Ribbon positioning system to tell what state the Ribbon is in currently. It is set to “s4-ribbonrowhidetitle” by default, but that is changed to the correct value once the ECMAScript code on the page initializes.

The Ribbon control itself lives inside the Ribbon container. Also present are the controls that appear in the top row of the ribbon (e.g. Site Actions, breadcrumb navigation button, edit/save button, the Personal Actions menu, etc.), the notifications area, Publishing Console, and Web Part adder. Nothing else should be placed into this container as its height is set using static values that will not adjust to additional content. To add more chrome above the Ribbon, you should add a new element above the Ribbon container.

Immediately following the Ribbon container are two other important elements on the master page: the Workspace element and the Body Container. These elements look like this in v4.master:

<div id=”s4-workspace”>

<div id=”s4-bodyContainer”>
</div>

</div>
 
The Workspace container is the element that remains scrollable when the Ribbon positioning system is enabled. Like the Ribbon container, its ID is mandatory as it must be referenced from ECMAScript code during page load. Directly inside of the Workspace container is the Body Container. Its ID is also required. Body Container is used to determine the width of the page content within the client-side script. Both of these elements must be present on the master page for the Ribbon positioning system to run. If one or both are missing, the system will abort.



There is one more interesting element on the master page: The Title container. As you’ll notice in v4.master, opening a Ribbon tab other than Browse will hide the page title and top navigation and replace it with the appropriate Ribbon tab. The important distinction to note here is that the “Browse tab” is not actually a tab. In reality, it is simply an empty Ribbon tab with normal HTML below it. In v4.master, the Title container looks like this:

<div id=”s4-titlerow” class=”s4-pr s4-notdlg s4-titlerowhidetitle”>
</div>

Like the other containers discussed above, the Title container must have a specific ID, in this case “s4-titlerow.” However, unlike the other containers, if the Title row ID is not present, the Ribbon positioning system will still run. If you leave out the ID or remove the element completely, the system will just ignore it and handle everything else appropriately. This means that if you leave the element but remove the ID, the Title area will not be removed from the page when you open a Ribbon tab. The CSS classes are also worth noting: As I explained above, “s4-pr” just makes the element take up the full browser width and display as a block element; “s4-notdlg” is used to stop the element from appearing if the page is being loaded in a Modal Dialog; “s4-titlerowhidetitle” is used by the Ribbon positioning ECMAScript to handle the current state of the Ribbon - just like the corresponding class on the Ribbon container, it is updated accordingly when the client-side script initializes at page load.
 
CSS Styles
 
All of the CSS styles pertinent to the Ribbon positioning system are in corev4.css. They are all required for the Ribbon positioning system to function properly. The first style rule of importance is “body.v4master” which is defined as follows:
body.v4master {

height: 100%;

width: 100%;

overflow: hidden;

}


This makes the body of the page take up the full width and height of the browser and hides the scrollbar for most browsers (remember that the “scroll” attribute on “body” handles this for some versions of IE).
Next is the CSS rule for the Ribbon container:


body #s4-ribbonrow {

min-height: 43px;

background-color: #21374c;

overflow-y: hidden;

}

This makes the Ribbon row take up 43px of vertical space at minimum and allows groups that cannot be fit into the browser (after scaling) to “fall off the edge” of the ribbon.
Below the Ribbon container styles are a set of styles that only apply to printing. I won’t go through each of these, but suffice to say that these styles are meant to undo some of the positioning applied by the system so that the full page displays when printed.
Further down the stylesheet are the styles for the Workspace and Body Container elements:
body s4-workspace {

overflow-y: scroll;

overflow-x: auto;

position: relative;

left: 0px;

}

body #s4-bodyContainer {

min-width: 760px;

}

First, we make the Workspace element always show a vertical scrollbar (to prevent shifting of page contents on load) and show a horizontal scrollbar only if necessary. The other two declarations in this rule are used for other layout purposes. The Body Container gets assigned a minimum width to ensure that shrinking the browser window down won’t render SharePoint unusable.

ECMAScript


The real logic of the Ribbon positioning system is in the ECMAScript code. I won’t go through the actual code that runs, but if you are curious, you can open up init.debug.js in your layouts\1033 folder and look for “FixRibbonAndWorkspaceDimensions()”. The Ribbon positioning logic is triggered in three ways: when the page loads, when the browser is resized, and when the Ribbon is minimized or maximized (for example, by double-clicking a tab title). Note that switching between the “Browse” tab and other tabs is a form of minimizing and maximizing the Ribbon.
The logic generally works like this:


· First, we look for the four interesting elements on the page: the Ribbon container, the Workspace container, the Body Container, and the Title container. If any of the first three cannot be found, the code aborts.


· We then check if the Workspace element has the CSS class “s4-nosetwidth” applied to it. If so, it will not set the width of any elements. This is useful if you have a fixed-width master page design.

· Next, we use static values plus some runtime information to determine the height that should be set on the Ribbon container. If the Ribbon container has its “visibility” style set to “hidden,” the system will set the Ribbon container’s height to 0px. This is the supported way to hide the Ribbon container for certain users but keep the Ribbon positioning logic when the Ribbon is displayed.


· Now, the important calculation occurs: The system gets the browser’s viewport height (the area of the window that contains the SharePoint page) and subtracts the height of the Ribbon container and the top position of the Ribbon container to determine how much space is left below for the Workspace container.


· The calculated height is set to the Workspace element and then some extra logic is run to set width and scroll position information accordingly.


At the very end of the ECMAScript logic, a set of callback functions are run for components that need to know when the Ribbon positioning system has run. If you need to run some code at this point, you can call SP.UI.Workspace.add_resized(handler) which will add your handler to the list.

Enabling and Disabling the System


Now that you have a better idea of how everything works, let’s run through the necessary steps to enable and disable the system for your master page.


Enabling the Ribbon Positioning System

The easiest way to take advantage of the Ribbon positioning system is to derive your custom master page from v4.master. All you have to do is pay attention to the components listed above so that you don’t remove something that’s important. If you end up using a custom CSS file, make sure to include all of the CSS rules shown above. The ECMAScript is included automatically by the ScriptLink control. ScriptLink is required on all SharePoint 2010 compatible master pages, so you get that for free.
If you are retrofitting an old master page to work with the Ribbon positioning system, you can simply follow the steps at Upgrading an Existing Master Page to the SharePoint Foundation Master Page to upgrade your master page. Most of what is discussed on this post is covered briefly in that documentation.
Disabling the Ribbon Positioning System

If you’re customizing v4.master, but wish to let the Ribbon scroll up with the page contents, you’ll need to do a few things:




In your master page:



1) Remove the “_fV4UI” variable from the top of the page. It will still be emitted by the SPWebPartManager later on in the page’s markup, but it will not be present when the on-load events for the Ribbon position system are usually attached. This will stop the code from running when the page loads which will improve rendering performance.



2) Remove or change the Workspace element’s ID to make the ECMAScript code abort early during window resizes and Ribbon minimize/maximize events. You can leave the element, but just change or remove the ID.
3) Remove the “scroll” attribute from the Body tag.
In your CSS stylesheet:
1) Remove or change the width, height, and overflow declarations on the “body” tag.
2) You can optionally remove the s4-workspace and s4-bodyContainer rules since they are no longer necessary.





Pro SharePoint 2010 Solution Development: Combining .NET, SharePoint, and Office

No comments:

Post a Comment