<!-- base css -->
<!-- for my content styling and css variables used within the navigation.scss -->
<link rel="stylesheet" href="https://codepen.io/RYJASM/pen/OVLRvZ.css">
<!-- fonts -->
<link rel="stylesheet" type="text/css" href="https://codepen.io/RYJASM/pen/6428d62fbf04420ad3bd1150c2949ae6.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
<!-- jquery -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<div class="main_navigation">
<ul class="navigation charm_nav">
<li><a href="#"><i class="fa fa-map-marker"></i>Campus Map</a></li>
<li><a href="#"><i class="fa fa-users"></i>Find People</a></li>
<li><a href="#"><i class="fa fa-calendar"></i>Calendar</a></li>
<li><a href="#"><i class="fa fa-sitemap"></i>A to Z Index</a></li>
</ul>
<ul class="navigation main_nav">
<div class="logo_holder">
<!-- this is where a logo could go -->
</div>
<li class="has_search">
<form class="search main_search">
<input class="search_box" type="text" placeholder="Search" />
<button class="search_button" type="submit" value><i class="fa fa-search"></i></button>
</form>
</li>
<li><a href="#">Future Students</a>
<ul>
<li><a href="http://futurestudents.mst.edu/">Information for Future Students</a></li>
<li class="special"><a href="http://futurestudents.mst.edu/degrees/">Majors and Degrees</a></li>
<li class="special"><a href="http://futurestudents.mst.edu/visit/">Campus Visit Programs</a></li>
<li class="special"><a href="http://futurestudents.mst.edu/apply/">Apply for Admission</a></li>
<li class="special"><a href="http://futurestudents.mst.edu/costs/">Costs and Fees</a></li>
<li class="special"><a href="http://futurestudents.mst.edu/requestinfo/">Request Information</a></li>
<li><a href="http://futurestudents.mst.edu/">Admissions</a></li>
<li><a href="http://dce.mst.edu/index.html">Distance and Continuing Education</a></li>
<li><a href="http://sfa.mst.edu/">Financial Aid and Scholarships</a></li>
<li><a href="http://reslife.mst.edu/">Student Housing</a></li>
<li><a href="http://pro.mst.edu/">New Student Orientation</a></li>
<li><a href="http://futurestudents.mst.edu/summercamps/">Summer Camps and Pre-college Programs</a></li>
<li><a href="http://ugs.mst.edu/">Undergraduate Studies</a></li>
<li><a href="http://grad.mst.edu/">Graduate Studies</a></li>
<li><a href="http://studentlife.mst.edu/">Student Life and Campus Activities</a></li>
</ul>
</li>
<li><a href="#">Current Students</a></li>
<li><a href="#">Alumni</a></li>
<li><a href="#">Faculty and Staff</a></li>
<li><a href="#">Community</a></li>
<li><a href="#">Giving</a></li>
</ul>
</div>
<div class="site add_margins content_item">
<h2>Basic Overview:</h2>
<p>Responsive, collapsing navbar, with a mobile expanding menu as well. It also supports dropdown menus.</p>
<p>
The SCSS includes a mixin that allows you to customize the colors and mobile menu label.
</p>
<h2>To use:</h2>
<ul>
<li>Create a ul->li list of links.</li>
<li>Apply the .navigation and a custom class to the top most ul</li>
<li>Use the Mixin to define settings for your custom class</li>
</ul>
<h2>Dependencies</h2>
<ul><li>Must define a mobile width stop point (because of mobile menu) originally defined in my page_structure.scss
<li>Depends on navigation.scss: the whole concept is dependent on a right aligned navigation
<ul>
<li>For left aligned, you must switch to a <total child widths>:<parent width> comparison technique
<li>I assume this takes more processing time, so I opted for position</li>
</ul>
</li>
<li>Must define customization options for each menu, using mixin provided in the navigation.scss</li>
</div>
<div class="site_navigation">
<ul class="navigation site_nav">
<li class="has_search">
<form class="search page_search">
<input class="search_box" type="text" placeholder="Search this site" />
<button class="search_button" type="submit" value><i class="fa fa-search"></i></button>
</form>
</li>
<li class="selected"><a href="#">Department Overview</a>
<ul>
<li><a href="#">From the Department Chair</a></li>
<li><a href="#">Accreditation</a></li>
<li><a href="#">Our Mission</a></li>
</ul>
</li>
<li><a href="#">Academic Programs</a>
<ul>
<li><a href="#">Undergraduate</a></li>
<li><a href="#">Graduate</a></li>
</ul>
</li>
<li><a href="#">Student Opportunities</a></li>
<li><a href="#">Research</a></li>
<li><a href="#">Faculty and Staff</a></li>
<li><a href="#">Department Activities</a></li>
</ul>
</div>
<br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br>
</body>
</html>
// Navigation Class - Drop Down Navigation System
// The Speicific Colors and Customization
@mixin navigation(
$nav_bg,
$nav_heading,
$nav_sel_bg,
$nav_sel_highlight,
$nav_sel_color,
$nav_hover_bg,
$nav_color,
$nav_color_hover,
$nav_search_bg,
$nav_search_color,
$nav_expand_text: "Menu"
) {
& {
background: $nav_bg;
// general list items
li {
a {
&:hover {
background: $nav_hover_bg;
color: $nav_color_hover;
}
}
&.has_search {
.search {
.search_box {
background: $nav_search_bg;
color: $nav_search_color;
&:focus, &:hover {
box-shadow:
-0.125rem 0 0 $nav_hover_bg,
0.125rem 0 0 $nav_hover_bg,
0 -0.125rem 0 $nav_hover_bg,
0 0.125rem 0 $nav_hover_bg;
}
&::-webkit-input-placeholder {
color: $nav_search_color;
}
&:-moz-placeholder { /* Firefox 18- */
color: $nav_search_color;
}
&::-moz-placeholder { /* Firefox 19+ */
color: $nav_search_color;
}
&:-ms-input-placeholder {
color: $nav_search_color;
}
}
.search_button {
color: $nav_search_color;
}
}
}
}
// 1st tier dropdown holder
ul {
// item in first dropdown
li {
a {
&:hover {
color: $nav_color_hover !important;
background: $nav_hover_bg !important;
}
}
}
}
.overflow.dropdown {
color: $nav_color_hover;
}
.menu_expander {
.expand_button {
background: $nav_search_bg;
&:before {
color: $nav_search_color;
}
&:after {
content: $nav_expand_text;
color: $nav_color;
font-family: $heading_font !important;
}
}
}
}
@media screen and (min-width: $main_break_point) {
// make the nav bg expand past the page margins
@include bleed_edges($nav_bg);
& {
li {
&:hover {
> a {
background: $nav_hover_bg !important;
color: $nav_color_hover !important;
}
}
&.selected {
> a {
background: $nav_sel_bg !important;
box-shadow: 0 -0.125rem 0 $nav_sel_highlight;
color: $nav_sel_color;
}
&:hover {
> a {
background: $nav_hover_bg !important;
color: $nav_color_hover !important;
}
}
}
a {
color: $nav_color;
}
// list item containing a list (aka: a dropdown)
&.dropdown {
// show the dropdown holder ul, that we define next, on hover
ul {
li {
a {
color: $nav_color;
&:hover {
background: $nav_hover_bg;
color: $nav_color_hover;
}
}
}
}
}
}
> li {
> a {
color: $nav_heading;
//text-transform: uppercase;
}
}
&.charm_nav {
li a span {
color: $nav_heading;
}
}
}
}
}
// The Global Structure
%static_nav_settings {
display: block;
width: 100%;
position: relative;
list-style-type: none;
text-align: right;
padding: 0 !important;
margin: 0 !important;
a:hover {
text-decoration: none !important;
}
// general list items
li {
max-height: 0;
overflow: hidden;
&.dropdown {
> a {
// make room for the dropdown caret
padding-right: 4rem;
}
}
a {
display: block;
background: #333;
color: #fff;
padding: 0 $page_margin;
padding-right: 4rem;
border-bottom: 0.125rem solid rgba(0,0,0,0.15);
box-sizing: border-box;
text-decoration: none;
position: relative;
font: $action_font_weight 0.9375rem/2.75em $action_font; // aka: 15px / 50px
// add space to the icons, if they exist
i {
margin-right: 0.25rem;
}
.drop_caret{
position: absolute;
line-height: 2.75rem;
right: 0;
top: 0;
bottom: 0;
width: 3rem;
}
.drop_caret:after {
content: '\f0d7';
font-family: FontAwesome;
text-align: center;
color: inherit;
position: absolute;
line-height: 2.75rem;
right: 0em;
top: 0;
bottom: 0;
width: 3rem;
background: rgba(0,0,0,0.15);
}
}
// list item containing the search box
&.has_search {
padding: 0 0.5rem;
position: relative;
&:hover {
background: none !important;
}
.search {
position: relative;
.search_box {
width: 100%;
height: 2rem;
margin: 0.5667rem 0;
border: none;
box-sizing: border-box;
padding: 0 3em 0em 1em;
font: $action_font_weight 0.875rem/2rem $heading_font; // aka: 15px / 50px
border-radius: 1.125rem;
outline: none !important;
&:-moz-placeholder { /* Firefox 18- */
font: $action_font_weight 0.875rem/2rem $heading_font;
opacity: 1;
}
&::-moz-placeholder { /* Firefox 19+ */
font: $action_font_weight 0.875rem/2rem $heading_font;
opacity: 1;
}
&:-ms-input-placeholder {
font: $action_font_weight 0.875rem/2rem $heading_font;
opacity: 1;
}
}
.search_button {
outline: none !important;
width: 2rem;
content: '\f002';
display: block;
font: 1rem/1em $icon_font;
color: #fff;
position: absolute;
background: none;
border: none;
padding: 0;
margin: 0;
top: 0;
bottom: 0;
right: 0.15rem;
}
}
}
}
// this is the main nav item only
> li {
> a {
font-family: $heading_font;
letter-spacing: 0.025rem;
font-family: $heading_font;
letter-spacing: 0.025rem;
font-size: 0.875rem;
border-right: 0.1rem solid rgba(0,0,0,0.1);
}
&:last-child {
> a { border: none; }
}
}
// 1st tier dropdown holder
ul {
max-height: 0;
overflow: hidden;
padding: 0 !important;
margin: 0 !important;
&.expanded {
transition: max-height 500ms ease-out ;
max-height: 999px !important;
}
// item in first dropdown
li {
a {
background: #ddd;
color: #333 !important;
}
// second tier dropdown holder
ul {
// second tier dropdown item
li {
// color is managaged here
a {
background: #fff;
}
}
}
}
}
&.charm_nav {
display: table;
table-layout: fixed;
.menu_expander {
display: none;
}
li {
display: table-cell;
&:last-child a {
border: none;
}
a {
white-space: nowrap;
display: block;
padding: 0;
border: none;
background: none;
position: relative;
border-right: 0.1rem solid rgba(0,0,0,0.1);
line-height: 3.5rem;
text-align: center;
color: transparent;
i {
position: absolute;
left: calc(50% - 0.5rem);
top: 0;
line-height: 3.5rem;
font-size: 1.75rem;
color: #8D9898;
transition: top 133ms linear;
}
&:hover {
i {
top: -1rem;
transition: top 133ms linear;
}
transition: color 80ms linear 200ms;
background: none;
}
}
}
}
.overflow.dropdown {
width: 2rem;
}
.menu_expander {
padding: 0.5rem 0.5rem;
.expand_button {
display: inline-block;
clear: both;
right: 0;
position: relative;
border-radius: 1.25rem;
&:before {
content: '\f0c9';
display: block;
font: 1em/1em $icon_font;
padding: 0.5rem 0.5rem;
height: 1rem;
width: 1rem;
text-align: center;
}
&:after {
position: absolute;
right: 3rem;
width: 50vw;
top: 0;
bottom: 0;
@extend %action_font;
line-height: 2rem;
}
}
}
// the collapse function will adjust for the width of this automatically :)
// this is where you put a logo or logo div
.logo_holder {
overflow: hidden;
// this allows the logo to slide up in mobile widths
// here it is a zero height element, on expand it will be
// a negative height, sliding the logo up
&:before {
content: '';
margin-top: 0em;
display: block;
transition: margin 200ms ease-in-out;
}
}
// This controls the the mobile menu opening
&.expanded {
max-height: 900px;
display: block;
overflow: visible;
.logo_holder {
&:before {
margin-top: -5rem !important;
transition: margin 200ms ease-in-out;
}
}
li {
max-height: 999px !important;
}
}
@media screen and (min-width: $main_break_point) {
text-align: right;
white-space: nowrap;
font-size: 0;
// fix inline block spacing
// the horizontal navigation bar
.menu_expander { display: none; }
li {
display: inline-block;
max-height: 9999px;
overflow: visible;
position: relative;
font-size: 1rem; // reset for inline block spacing fix
&:hover {
//background: $nav_hover_bg !important;
background: none;
}
&.selected {
&:hover {
background: none;
}
}
a {
background: none;
border: none;
padding-left: 1rem;
padding-right: 1rem;
font: $action_font_weight 0.9375rem/3.125rem $action_font; // aka: 15px / 50px
}
// list item containing a list (aka: a dropdown)
&.dropdown {
// left_side is a class applied by javascript function: theDropSide();
// when applied it makes the dropdown menu open on the left instead of the right
&.left_side {
li {
&:hover {
> ul {
top: 0;
left: -100%;
}
}
}
}
> a {
// make room for the caret
padding-right: 2rem;
.drop_caret, .drop_dots {
&:after {
content: '\f0d7';
font-family: FontAwesome;
color: inherit;
position: absolute;
background: none !important;
line-height: 3.125rem;
right: 0.5rem;
width: 1rem;
top: 0;
bottom: 0;
}
}
.drop_dots:after {
content: '\f142';
}
}
// show the dropdown holder ul, that we define next, on hover
&:hover {
//background: $nav_hover_bg !important;
> ul {
max-height: 999px;
overflow: visible;
z-index: 9001; // it's over 9000! make sure dropdowns are on top!
}
}
// hide the dropdown holder, until the parent list item is hovered, defined above
ul {
display: block;
position: absolute;
max-height: 0px;
top: 100%;
min-width: 100%;
left: 0;
box-shadow: 0 0.0125rem 0.0125rem rgba(0,0,0,0.3), 0 0.125rem 0.25rem rgba(0,0,0,0.25), 0 0.25em 2em rgba(0,0,0,0.25);
// item in first dropdown
li {
display: block;
&:hover {
// the second dropdown that pops out of the side
> ul {
top: 0;
left: 100%;
}
}
// hide bottom border for the last item in the menu
&:last-child {
> a {
border: none;
}
}
a {
background: rgba(#fff, 0.93);
display: block;
text-align: left;
white-space: nowrap;
border-bottom: 0.125rem solid rgba(0,0,0,0.1);
line-height: 2.25rem;
.drop_caret:after {
line-height: 2.5rem;
content: '\f0da';
}
}
}
}
}
// Search Field Storage into Navigation
&.has_search {
float: right;
overflow: hidden;
padding: 0 0.5rem;
.search {
.search_button {
pointer-events: none;
right: 0;
}
}
}
}
// this is the main nav item only
> li {
> a {
font-family: $heading_font;
letter-spacing: 0.025rem;
font-family: $heading_font;
letter-spacing: 0.025rem;
font-size: 0.875rem;
position: relative;
/*&:after, &:before {
content: '';
position: absolute;
top: 0;
bottom: 0;
border: 0.025rem solid rgba(0,0,0,0.1);
}
&:after {
right: -0.05rem;
}
&:before {
left: -0.05rem;
}*/
}
&:first-child {
> a:before { display: none; }
}
&:last-child {
> a:after { display: none; }
}
}
&.charm_nav {
display: block;
li {
display: inline-block;
a {
border: none;
padding: 0 2rem;
i {
position: relative;
display: inline-block;
left: initial;
font-size: 1.25rem;
padding-right: 0.25rem;
}
&:hover {
i {
top: 0;
}
}
}
}
}
}
}
.navigation {
@extend %static_nav_settings;
}
// Define the different settings for each nav
.main_nav.navigation {
@include navigation(
$nav_bg: #e7e7e7,
$nav_heading: #333,
$nav_sel_bg: #e7e7e7,
$nav_sel_highlight: transparent,
$nav_sel_color: #333,
$nav_hover_bg: #77BE0C,
$nav_color: #333,
$nav_color_hover: #fff,
$nav_search_bg: #333,
$nav_search_color: #fff,
$nav_expand_text: "Expand Menu"
);
}
.site_nav.navigation {
@include navigation(
$nav_bg: #77BE0C,
$nav_heading: #fff,
$nav_sel_bg: #77BE0C,
$nav_sel_highlight: transparent,
$nav_sel_color: #fff,
$nav_hover_bg: #367B08,
$nav_color: #fff,
$nav_color_hover: #fff,
$nav_search_bg: #fff,
$nav_search_color: #333,
$nav_expand_text: "Menu"
);
}
.charm_nav.navigation {
@include navigation(
$nav_bg: #333,
$nav_heading: #fff,
$nav_sel_bg: #fff,
$nav_sel_highlight: transparent,
$nav_sel_color: #333,
$nav_hover_bg: #222,
$nav_color: #ddd,
$nav_color_hover: #eee,
$nav_search_bg: none,
$nav_search_color: none,
$nav_expand_text: ""
);
}
View Compiled
////////////////// Navigation ////////////////////
//// Overview: A responsive, collapsing, mobile menu enabled, drop down menu system
//
// * Applies functions to ul.navigation elements on the page
// * Collapses menu items into a "more" menu
//// Dependencies
//
// Must define mobile width stop point, originally defined in my page_structure.scss
// - Depends on navigation.scss: the whole concept is dependent on a right aligned navigation
// -- For left aligned, you must switch to a <total child widths>:<parent width> comparison technique
// -- I assume this takes more processing time, so I opted for position
// - Must define customization options for each menu, using mixin provided in the navigation.scss
//// Functions: details on each function are inline as the function progresses
//
// Add elements to navigation
// --> function addNavigationElements( selectedNav )
//
// Collapse the navigation into a "more" menu
// --> function collapseNavigationElements( selectedNav )
//
// Add actions to the navigation elements
// --> function addNavigationActions( selectedNav )
//
// Make sure that dropdowns don't fall off the screen
// --> function theDropSide( selectedNav )
//////////////// End Navigation ////////////////////
// Determine the best side for the drop down menus to open on
function theDropSide( dropdown_holder ) {
var pageWidth = $(window).width();
dropdown_holder.each( function() {
// convert menu position from left side into a percentage
var dropSide = 100 * ( $(this).offset().left / pageWidth );
// if it's more than half way across the page, drop to the left, else right
if( dropSide < 50 ) {
$(this).removeClass('left_side');
}
if( dropSide > 50 ) {
$(this).addClass('left_side');
}
});
}
//// Navigation Functions
// Add any extra elements for UI to navigation
function addNavigationElements( selectedNav ) {
var dropdown_holder = selectedNav.find('ul').parent();
// Add the Menu Expander at the top of the navigation list
selectedNav.prepend('<div class="menu_expander"><span class="expand_button"></span></div>');
// Add the dropdown class to any li that has a ul inside of it
dropdown_holder.toggleClass("dropdown");
// Add the dropdown caret icon
dropdown_holder.children('a').prepend('<span class="drop_caret"></span>');
}
// Collapse navigation elements that don't fit the navigation width into an overflow menu
function collapseNavigation( selectedNav ) {
// ignore the charm navigation: will probably pull the charm navigation out
// since it has developed into a different mini-beast (rabid hamster?) all together
if( !selectedNav.hasClass('charm_nav') ){
var windowWidth = $(window).outerWidth();
// if you want a little left padding in pixels, increase this
var navAdjustment = 0;
// adjust for the logo being in the way
if( selectedNav.hasClass('main_nav') ) {
var mainNavPadding = $('.logo_holder').outerWidth();
navAdjustment += mainNavPadding;
}
// navigation item elements
var lastMenuItem = selectedNav.children('li:not(".overflow_holder")').last();
var firstMenuItem = selectedNav.children('li:not(".has_search")').first();
// overflow elements
var overflowHTML = '<li class="overflow_holder dropdown"><a href="#">More<span class="drop_dots"></span></i></a><ul class="overflow_menu"></ul></li>';
var overflowHolder = selectedNav.children('li.overflow_holder');
var overflowMenu = overflowHolder.children('ul.overflow_menu');
// distance of 1st item from menu edge
var positionFromLeft = selectedNav.children('li:not(".has_search")').first().position().left;
// overflow item elements
var firstInList = overflowMenu.children('li:first-of-type');
var firstInListWidth = firstInList.outerWidth();
if( positionFromLeft <= navAdjustment && windowWidth != firstMenuItem.outerWidth() ) {
if( overflowMenu.length === 0 ) {
// if overflow menu doesn't exist, add it
selectedNav.append( overflowHTML );
}
// if 1st menu item is too close to menu edge,
// add it to overflow menu
lastMenuItem.prependTo( overflowMenu );
if( windowWidth > 900 ) {
// if there isn't a menu item and the window isn't in mobile mode, run again
// mobile break point is 800px
collapseNavigation( selectedNav );
}
}
if( positionFromLeft > ( firstInListWidth + navAdjustment) ) {
// if 1st menu is far enough away fromm menu edge
// for the 1st overflow item to fit, move it back out
firstInList.insertAfter( lastMenuItem );
}
if( ( overflowMenu.children().length === 0 ) || ( windowWidth <= firstInListWidth ) ) {
// if the overflow menu is empty and the list is the same width or
// great (aka mobile mode), drop the overflow menu
overflowMenu.children().appendTo(selectedNav);
overflowHolder.remove();
}
}
}
function addNavigationActions( selectedNav ) {
var dropdown_caret = selectedNav.find('.drop_caret');
var expand_button = selectedNav.find('.expand_button');
var dropdown_holder = selectedNav.find('.dropdown');
// attach click handler to expand button
expand_button.click( function(){
// add expanded to the ul.navigation element
$(this).parent().parent().toggleClass("expanded");
});
// attach click handler to the dropdown caret
dropdown_caret.click( function(event) {
event.preventDefault();
// close other expanded menus
// dropdown_holder.children('.expanded').removeClass('expanded')
$(this).parent().parent().children('ul').toggleClass('expanded');
});
dropdown_holder.hover( function() {
theDropSide($(this));
});
}
// Activate Navigation Functions
var navigation = $('ul.navigation');
// when the html structure has loaded
$(window).ready(function() {
navigation.each( function(){
addNavigationElements( $(this) );
addNavigationActions( $(this) );
// push non fitting menu items into overflow/more menu
collapseNavigation( $(this) );
});
});
// when everything has loaded
$(window).on('load', function(){
navigation.each( function(){
// make sure dropdowns don't go offscreen
// choose the dropdown positions
dropdown_holder = $(this).find('.dropdown');
theDropSide( dropdown_holder );
});
});
$(window).on('resize', function(){
navigation.each( function(){
// push non fitting menu items into overflow/more menu
collapseNavigation( $(this) );
// make sure dropdowns don't go offscreen
// choose the dropdown positions
var dropdown_holder = $(this).find('.dropdown');
theDropSide( dropdown_holder );
});
});
This Pen doesn't use any external JavaScript resources.