Making seattle.master Responsive

“Sonny, true love is the greatest thing in the world. Except for a nice M.L.T., a mutton, lettuce and tomato sandwich, where the mutton is nice and lean and the tomato is ripe. They’re so perky. I love that.”

You know what else would be the greatest thing in the world? A responsive version of SharePoint 2013’s Seattle master page. While an ETA continues to be dodged for this juicy addition for SharePoint on-premises and SharePoint Online, we can play Miracle Max and do it ourselves.  Yes really.  At the end of the day, it is just CSS.  That we can do. 

The Mutton

Media queries.  These little gems can light up your life and SharePoint design at various viewport sizes like no other.  Here is a basic media query. The max-width value is what we will be utilizing today. At every viewport width that your site breaks, we will create a new media query with the identified width value (known as a breakpoint).

@media screen and (max-width: 768px) {
New CSS goes here
}

The Lettuce

Looking at your site.  Don’t get hung up on devices. You will forever be hopelessly stabbing with your sword at Inigo trying to hit a moving target if you get too wrapped up with the devices you need to support.  Instead look at your site and identify at what viewport sizes does your site break.  Find a break, make a fix, move on. You can even do it left-handed.

The Tomato

Totally awesome CSS. Restack, reflow, remove, redo, resize… all things R possible (see what I did there?) with CSS.  Using media queries, our eyeballs and CSS we will reformat the web page on an as needed basis.

The Knife

Sandwiches are hard to make with your fingers.  Possible, but messy. Get yourself set up with Firefox or Firefox Developer Edition now so you can use their handy responsive design tool that is built into the browser.

  1. Install Firefox or Firefox Developer Edition if you don’t already have it.
  2. Open your SharePoint site in Firefox.
  3. Right click on the web page and select Inspect Element.
  4. In the far top right area is a row of icons.  You want to see the icon that looks like nested boxes that is highlighted in blue below. This is the Responsive Design Mode option. If you have it skip to step 6.
    Responsive Design Mode button in Inspector
  5. If you don’t see it, select the gear (settings) icon. Scroll down to the Available Toolbox Buttons section and check Responsive Design Mode. Exit out of settings by clicking the Inspector tab in the upper left.
  6. Select the Responsive Design Mode icon. Your site will be framed on top of a black background and there will be a row of options across the top.  There is also a resize handle on the far right. You will use the resize handle to manually resize the viewport, or you can use the canned dimensions in the options across the top.Responsive Design Pane in Firefox

The Plate

Let’s see how long I can keep this metaphor going. Bigger plate, more food. Tiny plate, less food. Responsive design is no different. At larger viewports you can fit more stuff. At a smaller viewport you have to start dumping things or stacking them on top of each other to fit all of your yummy web site content goodness.  Let’s start by identifying what overflows on your plate as you reduce the size.

Using the resize handle provided by the Responsive Design Mode in Firefox, start reducing the width of your web site.  In seattle.master the thing that usually causes the first problem is your navigation. Depending on the length of your top nav bar (global navigation) the web page will start forcing a horizontal scroll.  In my sample site this happens for me at 1044 pixels.  I have exaggerated the size some in the following screenshot so it is easier to see.

SharePoint navigation getting cut off at smaller viewport size

As you continue to resize your site you can see other potential issues.

SharePoint components getting cut off at smaller viewport size

The Recipe

Let’s get down to fixing this mess. Using the Style Editor tab in Firefox, you can write CSS and see an immediate live preview of your changes.

  1. Select the Style Editor tab in the inspector.
  2. Select the New button on the far left. This gives you a fresh file for your changes, that is applied after all other CSS files that are being loaded by the web page.

Wrap the navigation and search

In responsive design the navigation bars are typically moved to a new line or location once space becomes tight.  The next step as space is further reduced is to collapse it down into a fly out menu that appears when you select an icon (typically the hamburger icon or text that says “Menu”).

The following CSS moves the top nav bar and search to under the SharePoint site logo and title text. Depending on the length of your navigation bar, the max-length value in the media query on line 1 may need to be altered to match where your SharePoint site starts to break at a smaller viewport size. If your site is currently displaying at a larger width than what is listed for the max-width value, you will not see the changes.  You have to be viewing the site at a smaller viewport size in order to see the CSS changes.

*Please note: The comments provided for the individual CSS declarations in this blog post are there to help you understand what is happening and do not need to stay in production code.*

@media screen and (max-width: 1044px) {
	/* Hide unnecessary page elements */
	.ms-core-listMenu-horizontalBox .ms-listMenu-editLink  /* Global navigation "Edit Links" when managed navigation is in use */ {
		display: none;
	}

	/* Undo the crazy that SharePoint creates with table display set to DIVs*/
	#s4-titlerow .ms-table,
	#s4-titlerow .ms-tableRow,
	#s4-titlerow .ms-tableCell {
		display: block;
	}

	/* Site logo wrapper */
	#siteIcon {
		float: none;  /* Remove OOTB float - this allows title row elements to return to typical block elements along with the table display changes above */
		text-align: left;  /* Alter OOTB alignment */
	}

	/* Page title text */
	#pageTitle {
		position: absolute;  /* Remove from content flow and create precise placement based on parent container */
		top: 30px;  /* Position from top */
		left: 220px;   /* Positioning from left */
	}

  	/* Top nav bar size */
	.ms-breadcrumb-box {
		height: 30px;   /* Alter OOTB height */
	}

	/* Top nav bar placement & formatting */
	.ms-breadcrumb-top > .ms-core-navigation {
		display: block;  /* Force respect of some declarations */
		margin-top: 20px;  /* Create space between the site logo/title and nav bar */
	}

  	/* Search placement */
	.ms-mpSearchBox.ms-floatRight,
	#searchInputBox  {
		float: none;  /* Remove OOTB float - this allows the search to move to the left under the top nav bar */
	} 

  	/* Adjust padding for content containers */
	#s4-bodyContainer {
		padding-bottom: 60px;  /* Alter OOTB padding */
	}
  	#contentRow {
		padding-top: 80px;  /* Alter OOTB padding */
	}
}

Here is the result:

Wrap the nav and search at smaller viewports

We will come back to collapsing the navigation further as we get to smaller viewport sizes.

Wrap the content areas

The content areas that will need to be adjusted will be dependent on the type of site you are using (enterprise wiki, publishing, team site, blog, etc.), what your content is within the page, and the applied page layout (publishing sites only).  The following code bits can help get you pointed in the right direction. Please note that sites based on the publishing template likely don’t need any adjustments, unless the applied page layout is forcing widths on any content areas. Additionally, all of this code doesn’t accommodate for web parts, which when in their natural table format will take up whatever width is needed to display all of the columns set to show for the web part.

To wrap the content for an enterprise wiki site, the following CSS is needed. It can be placed within the existing media query you have already started or you can create a new media query specifying a different breakpoint.  For the sake of demonstration, that is what we will do below.

@media screen and (max-width: 926px) {
	/* Content area wrapper, parent of col-fluid-1 and col-fluid-2 */
	#contentBox {
		min-width: inherit;   /* Reset OOTB min-width from fixed value to inherit which will take up the available space */
	}

	/* Alter right column on Enterprise Wiki default page */
	.right-wp-zone-col {
		float: none;  /* Remove OOTB float */
	}

	/* Sub content area wrappers, sibling to right-wp-zone-col */
	.col-fluid-1,
	.col-fluid-2 {
		margin-right: 10px;  /* Alter OOTB margin */
	}
}

Here are the results:

Wrap the content area at smaller viewports

For blog sites, you would use this:

@media screen and (max-width: 926px) {
	/* Reset min-widths on content containers */
	#contentBox,
	.ms-blog-MainArea {
		min-width: inherit;   /* Reset OOTB min-width from fixed value to inherit which will take up the available space */
	}

	/* Table conversions so table cells will wrap */
	.ms-blog-MainArea {
		display: block;  /* Switch from a table display to a block level display, which forces other elements to be above or below */
	}
	.ms-blog-MainArea td:first-child,
	.ms-blog-LeftColumn {
		display: inline-block;  /* Switch from a table cell display to an inline block level display, which allows other elements to be to the right or left */
		width: auto;
	}
}

And for team sites, you can use this:

@media screen and (max-width: 926px) {
	/* Reset min-widths on content container */
	#contentBox {
		min-width: inherit;   /* Reset OOTB min-width from fixed value to inherit which will take up the available space */
	}

	/* Table conversions so table cells will wrap */
	#layoutsTable {
		display: block;  /* Switch from a table display to a block level display, which forces other elements to be above or below */
	}
	#layoutsTable td {
		display: inline-block;   /* Switch from a table cell display to an inline block level display, which allows other elements to be to the right or left */
		width: auto;
	}

	/* Right side table cell */
	.ms-wiki-columnSpacing {
		padding-left: 0;  /* Alter OOTB padding */
	}
}

Left navigation (Quick Launch)

The left nav gets sticky… most sites don’t have multiple navigation systems in a responsive view for mobile devices. You can choose to just hide the left navigation, or if it is too valuable to pitch for mobile users, decide if the best place for it to go is under the content or above the content

From here you can sort out the best way to treat the formatting and possible nav collapse.

Hide the left navigation bar

This is the easiest approach.  Use the following CSS with a media query set to an appropriate breakpoint where you feel the nav is chewing up too much valuable space on the left.

@media screen and (max-width: 740px) {
	/* Hide the left nav bar */
	#sideNavBox {
		display: none;
	}

	/* Reset the margin of the content area */
	#contentBox {
		margin-left: 20px;
	}

	/* Remove the content area border */
	.right-wp-zone-col {
		border: 0;
	}
}

And this is what you get:

Hide the left navigation at smaller viewports

Move the left nav under the content

Of your options, this is the trickiest because unless you aren’t worried about IE9 and older, you can’t move the left navigation under the content without editing the master page. The left nav is above the content area in the code, so there is no way to float these items into submission. You also can’t use absolute positioning because the length of your content will change from page to page. However if you are working with IE10+ you can use Flexbox (flexible box model).  You can check the latest browser support for Flexbox.  If you are really wanting to do this and have to support IE6-9, you can take a look at Flexie.

@media screen and (max-width: 740px) {
	/* Set the parent as the Flexbox container */
	#contentRow {
		display: flex;
		display: -ms-flexbox;  /* IE10 */
		display: -webkit-box;  /* Safari, Android */
		flex-wrap: wrap;
		-ms-flex-wrap: wrap;  /* IE10 */
	}

	/* Set the order of the Flexbox items */
	#sideNavBox {
		order: 2;
		-ms-flex-order: 2;  /* IE10 */
		-webkit-order: 2; /* Safari, Android */
		margin-top: 20px;  /* Add spacing between content area and left nav */
	}
	#contentBox {
		margin-left: 20px;  /* Reset the margin of the content area */
		order: 1;
		-ms-flex-order: 1;  /* IE10 */
		-webkit-order: 1; /* Safari, Android */
	}

	/* Remove the content area border */
	.right-wp-zone-col {
		border: 0;
	}
}

And the resulting view:

Move left nav under content at smaller viewports

Move the left nav above the content

Moving the left nav above the content is a straightforward thing to do.  What to do with it next is where things get dicey.  Two navigation systems on top of each other can pose usability issues and create confusion for your users.  One thing you can do is change up the formatting so the left nav just looks like simple links for more info, and also hide the second level of navigation, further simplifying the view and reducing the vertical space the navigation takes up.

For this example I have moved two of my navigation links under another one to create a parent/child structure in the nav.

Move two navigation items under an existing one

Hide the second level of navigation

The following CSS will hide the children nav items.

@media screen and (max-width: 740px) {
	/* Hide child level navigation items */
	ul.root ul {
		display: none;
	}
}

Format the remaining navigation to look like simple link list

The left navigation is already simple looking, but we can add a bit more to set it off as just added links for the page and not “navigation”.

@media screen and (max-width: 740px) {
	 /* Reset the margin of the content area */
	#contentBox {
		margin-left: 20px;
	}

	/* Remove the content area border */
	.right-wp-zone-col {
		border: 0;
	}

	/* Format left nav container and items */
	#sideNavBox {
		float: none;  /* Remove OOTB float so content appears beneath the nav */
		border: 1px solid #999;  /* Bounding box */
		border-radius: 15px;  /* Rounded corners */
		padding: 5px 10px;  /* Add padding to space content from border */
		margin-bottom: 15px;  /* Create space between left nav and content underneath */
	}
	.ms-core-sideNavBox-removeLeftMargin {
		margin-left: 0;  /* Alter OOTB margin */
	}
	#sideNavBox .ms-core-listMenu-item {
		padding: 3px 10px;  /* Alter OOTB padding */
	}

	/* Add header text */
	#sideNavBox:before {
		content: "Additional Resources:";  /* Header text */
		padding-bottom: 7px;  /* Space out text from horizontal rule */
		display: block;  /* Required for padding to work */
		border-bottom: 1px solid #999;  /* Horizontal rule */
	}

	/* Hide child level navigation items and other unnecessary items */
	#sideNavBox ul.root ul,
	.ms-core-listMenu-verticalBox .ms-listMenu-editLink,  /* Current navigation "Edit Links" when managed navigation is in use */
	.ms-core-sideNavBox-removeLeftMargin > .ms-core-listMenu-verticalBox  /* Site Contents */ {
		display: none;
	}
}

Here is the result:

Make the left nav look like a list of links

Collapse the navigation

For either navigation system you can collapse the navigation into a typical responsive menu that shows the hamburger menu and when touched, reveals the navigation items. It isn’t as gorgeous as what you can do with JavaScript or jQuery, but it is a working CSS only solution. It can also be modified to work for the left nav or with structured nav. In it’s current state it is written for the top nav bar using managed navigation. Please note the @import statement should be at the *top* of your CSS file.

/* Font Awesome is a free font. http://fontawesome.io
Check for latest version at http://fontawesome.io/get-started
This should be moved to the top of your CSS file, irregardless of media queries */
@import "//netdna.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.css";

@media screen and (max-width: 470px) {
	/* Hide Edit Links (icon and text) */
	div[id$="TopNavigationMenu"] li.static.ms-listMenu-editLink,  /* Desktop view */
	div[id$="TopNavigationMenu"] ul.root:hover li.ms-listMenu-editLink /* Mobile view */ {
		display: none;
	}

	/* Adjust menu placement from previous responsive changes */
	.ms-breadcrumb-box {
		height: 40px; /* Increase height previously set */
		margin: 10px 0 5px -15px;  /* Move nav closer to logo and edge of page */
	}

	/* Remove unnecessary branding from global nav */
	div[id$="TopNavigationMenu"] ul.root {
		border: 0;
		background: #fff;
	}

	/* Add "Menu" text before nav list - necessary to prevent mobile user accidentally jumping to first nav item when menu is activated */
	div[id$="TopNavigationMenu"] ul.root > li.static:first-child:before {
		content: "Menu";
		display: block;
		padding: 5%;
		background: #ccc;
	}

	/* Reset global navigation item formatting */
	div[id$="TopNavigationMenu"] li.static a.static,  /* First level of nav */
	div[id$="TopNavigationMenu"] li.static a.dynamic  /* Second level of nav */ {
		min-width: 100px;  /* Optional */
		width: auto;   /* Can also set to an absolute value */
		padding: 10% 15%;
		border-top: 0;
		border-bottom: 1px solid #dfdfdf;
		margin-right: 0;
		display: block;
		font-size: .8rem;
		line-height: 1.5;
		position: relative;
	}
	div[id$="TopNavigationMenu"] li.static a.dynamic {
		padding-left:25%;
	}
	 div[id$="TopNavigationMenu"] li.static:last-child > a {
		border-bottom: 0;
	}
	div[id$="TopNavigationMenu"] li.static a:hover  {
		background: rgba(205,230,247,0.5);
	}

	 /* Reset positioning of level 2 navigation items */
	div[id$="TopNavigationMenu"] ul.dynamic {
		border: 0;
		box-shadow: none;
		left: 0;
		top: 0;
		position: relative;
		padding: 0;
		width: auto !important;  /* !important required to override inline style */
		left: 0 !important;  /* !important required to override inline style */
		top: 0 !important;  /* !important required to override inline style */
	}

 	/* Hide level 3 navigation items */
	div[id$="TopNavigationMenu"] ul.dynamic ul.dynamic {
		display: none;
	}

	/* Remove drop down arrows on navigation items with dynamic children menus */
	#s4-titlerow div[id$="TopNavigationMenu"] .dynamic-children.additional-background {
		background-image: none;
	}

	/* Insert stacked lines icon to designate global navigation */
	div[id$="TopNavigationMenu"] ul.root:before {
		content: "\f0c9";
		font-family: FontAwesome;
		background: white;
		font-size: 1.4rem;
		width: 2.6rem;
		height: 1.4rem;
		padding: .3rem 0;
		display: block;
		border-radius: 5px;
		text-align: center;
		border: 1px solid #ccc;
		margin: 0 15px;
	}

	/* Hide stacked lines icon on hover */
	div[id$="TopNavigationMenu"] ul.root:hover:before {
		display: none;
	}

	/* Hide global navigation items */
	div[id$="TopNavigationMenu"] ul.root > li {
		display: none;
	}

	/* Display global navigation box on hover */
	div[id$="TopNavigationMenu"] ul.root:hover {
		background: white;
		border: 1px solid #ccc;
		border-radius: 5px;
		margin: 0 0 0 15px;
		position: absolute;
		z-index: 2;
	}

	/* Display global navigation items on hover */
	div[id$="TopNavigationMenu"] ul.root:hover > li {
		display: block;
	}
}

This is the result:

Convert the top nav bar to a collapsed mobile menu

Expanded view of mobile menu

Hide Suite Bar Items

To wrap up this responsive buffet of CSS code, we need to hide some Suite Bar components that get in the way of our interface once we crank down the viewport to a very small size, like what would be used for mobile phones (as opposed to tablets).

@media screen and (max-width: 360px) {
	/* Hide right side of Suite Bar links */
	.ms-core-deltaSuiteLinks {
		display: none;
	}
}

The final view:

Hide Suite Bar items at smaller viewport sizes

Plate that MLT!

There is one last thing you need to do in order to make this responsive scrumptiousness show on an actual mobile device. And it may require editing the master page* (or actually the HTML Master Page that is attached to seattle.master). Once you have added your CSS file to the SharePoint site and have it applied, do the following:

  1. Open your SharePoint site in SharePoint Designer or via a mapped network drive.
  2. Navigate to the Master Page Gallery and open seattle. html.
  3. Towards the top of the file, add a return after line number 25.
  4. Paste in the following code on the empty line 26:
    <meta name="viewport" content="width=device-width, initial-scale=1">
  5. Save the file.
  6. Go check out your site on a mobile device. You should see this:

SharePoint site on a mobile device.

 

Please note that the Suite Bar items are still showing in the above screenshot because it was taken on an iPhone 6, which has a slightly larger viewport than older iPhones and other mobile devices.  The media query breakpoint is set to 360 pixels, and the iPhone6 shows 375 pixels. To check out viewport sizes for a bunch of devices, take a look at ViewPortSizes.com.

* You can alternatively add the meta tag via SEO settings for a publishing site.  Check out Stefan Bauer’s post for more info: How to add viewport meta without editing the master page

Compiled Code

You can download all of the code as one file. Please note that everything is in the file, including the code to hide the left navigation so the other navigation tricks won’t work unless you comment out or remove line 137.  Find an issue? Please let me know in the comments so I can make any necessary code corrections.

Want more?

Has your appetite been whetted? There is so much more you can do with SharePoint 2013 and responsive design, and also with CSS.

  • Take your responsive design to the next level with our SharePoint 2013 Responsive Design course. Learn how to incorporate responsive JavaScript, CSS preprocessors and Bootstrap into your SharePoint site.
  • Further your branding with CSS only. This includes the header, navigation and complete redesign of the layout (yes, again with CSS only). Check out our SharePoint CSS Experience course for more details.

Update, April 28, 2015

Vesa Juvonen of Microsoft has created a GitHub project that demonstrates how to make the out of the box seattle.master user experience responsive without a need to modify the mater page as such, but rather to take advantage of the AlternateCssUrl property in Web level.

Check out the GitHub project: OfficeDev/PnP