CSS Fix for Broken DynamicHorizontalOffset and DynamicVerticalOffset in SharePoint 2013 AspMenu Control

That is a mouthful of a title but luckily this is a simple fix for an annoying bug in SharePoint 2013.  Between SharePoint 2010 and 2013, the DynamicHorizontalOffset and DynamicVerticalOffset properties in the AspMenu control became useless because of how the drop down menus are styled in CSS by SharePoint.  You can set these properties all day long and nothing comes of it.  So abandon that and just use the following CSS fix.

The Problem

You are utilizing drop down menus (fly out menus) in your SharePoint 2013 site and you want to change the default location of the menu. Maybe the drop down menu overlaps a larger navigation bar or button styling that you have implemented. For example:

Default placement of drop down menu overlapping styled navigation
Default placement of drop down menu, which is overlapping the styled navigation button.

There are two properties available for the Menu control, DynamicHorizontalOffset and DynamicVerticalOffset, that allow you to control the placement of the dynamic (their fancy word for drop down) menu.  In SharePoint 2010 these worked great.  SharePoint 2010 also had a table based layout for navigation.

With the move to list based navigation in SharePoint 2013, CSS is used more heavily for navigation design and display.  If you dig around in the CSS you will find the following:

  • The drop down menus are hidden from the page using absolute positioning and large, negative top and left values.  If you want proof, add this to your site:
    ul.dynamic {top: 0; left: 0;}
  • When you hover over a static (another fancy word they use that means the stuff that is always showing) navigation list item (LI) that has a child drop down menu, the parent list item gets another class added (hover) and the nested drop down menu list container (UL) has inline styles added. OUCH.
  • When you move back off the static list item (LI) the hover class is removed and a new class is added, hover-off (but only temporarily).
  • These are actual classes that are being added, hover and hover-off, NOT :hover pseudo classes that appear in the CSS file only.

The inline styles are preventing anything the Dynamic Vertical Offset and Dynamic Horizontal Offset values could be doing for you.

The Fix

With a little CSS you can manually set your own positioning for the drop down menu:

.ms-core-listMenu-horizontalBox li.static.dynamic-children.hover > ul.dynamic,
.ms-core-listMenu-horizontalBox li.static.dynamic-children.hover-off > ul.dynamic{
	top: 55px !important;  /* !important added to override inline SharePoint style */
	left: -15px !important;  /* !important added to override inline SharePoint style */
}

And here is the result:

Use CSS to set your own drop down position
After some CSS tweaks, the drop down menu is appearing below the styled navigation item.

A few notes about the above CSS code:

  • You can and may need to alter the opening class in the selector. Right now it is set to .ms-core-listMenu-horizontalBox which will target the top navigation (global nav) in a site using Seattle.master. This may need to be altered if you are using a custom master page or have stripped out the code that generates this class.
  • You will need to tweak the top and left values to fit your design.
  • The further away you set the physical menu placement, the more you increase your chances of losing the hover menu. The placement change is based on the presence of the hover class, which is only added when you hover over the static menu item. Once you move off the static menu item and the hover class is dropped, the drop down menu will disappear before you can get your cursor over an item and select it.  However you can make changes to get around this issue (see below).
  • Including the hover-off as a variation of the selector (line 2 in the above code) helps offset the issue of the menu disappearing too quickly when you hover off the static menu item, but only by a little bit.  However…
  • You need to include the hover-off as a variation of the selector (line 2 in the above code). Without it you will get very ugly menu jumping.

Forcing the Drop Down Menu to Continue to Show with Large Spacing

This whole fix depends on the presence of the hover class when you are mousing over the static item. As long as you stay hovered over that item, you won’t lose the placement of your drop down menu. But what if you want a larger space between the bottom of the static item and the drop down menu? You can increase the size of the static menu item on the sly using a bottom margin.

In the below code sample, the drop down menu is set even further away from the static menu item:

.ms-core-listMenu-horizontalBox li.static.dynamic-children.hover > ul.dynamic,
.ms-core-listMenu-horizontalBox li.static.dynamic-children.hover-off > ul.dynamic{
	top: 75px !important;  /* !important added to override inline SharePoint style */
	left: -15px !important;  /* !important added to override inline SharePoint style */
}

But when you mouse off the static nav item, the drop down menu disappears before you can get to it in order to select something.

If I add a larger bottom margin to the navigation items, this problem clears up.

.ms-core-listMenu-horizontalBox ul.static > li > a {
    margin-bottom: 35px;
}

Adding this bottom margin may cause other issues in your design, but they should be rather easy to patch up.

Increase bottom margin to keep drop down menu visible
Adding a bottom margin to the static navigation item allows for the hover class to stay active between the navigation item and the start of the drop down menu.