snippet

Smart Tooltip Like DropDown Menu by

A drop down menu bassed on CSS and JS that shows a tooltip like sub-menu on hover. Navigation tooltip submenu will appear either above or below the menu, depending on where more space is available.


Tags: menu responsive menu dropdown menu bootstrap menu menu select animated menu

The MIT License (MIT)

Copyright (c) 2017

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
/* Iconfont made with icomoon.com */ @font-face { font-family: 'cbp-tmicons'; src:url('../fonts/tmicons/cbp-tmicons.eot'); src:url('../fonts/tmicons/cbp-tmicons.eot?#iefix') format('embedded-opentype'), url('../fonts/tmicons/cbp-tmicons.woff') format('woff'), url('../fonts/tmicons/cbp-tmicons.ttf') format('truetype'), url('../fonts/tmicons/cbp-tmicons.svg#cbp-tmicons') format('svg'); font-weight: normal; font-style: normal; } /* reset list style */ .cbp-tm-menu, .cbp-tm-menu ul { list-style: none; } /* set menu position; change here to set to relative or float, etc. */ .cbp-tm-menu { display: block; position: absolute; z-index: 1000; top: 0; width: 100%; background: #47a3da; text-align: right; padding: 0 2em; margin: 0; text-transform: capitalize; } /* first level menu items */ .cbp-tm-menu > li { display: inline-block; margin: 0 2.6em; position: relative; } .cbp-tm-menu > li > a { line-height: 4em; padding: 0 0.3em; font-size: 1.2em; display: block; color: #fff; } .no-touch .cbp-tm-menu > li > a:hover, .no-touch .cbp-tm-menu > li > a:active { color: #02639d; } /* sumbenu with transitions */ .cbp-tm-submenu { position: absolute; display: block; visibility: hidden; opacity: 0; padding: 0; text-align: left; pointer-events: none; -webkit-transition: visibility 0s, opacity 0s; -moz-transition: visibility 0s, opacity 0s; transition: visibility 0s, opacity 0s; } .cbp-tm-show .cbp-tm-submenu { width: 16em; left: 50%; margin: 0 0 0 -8em; opacity: 1; visibility: visible; pointer-events: auto; -webkit-transition: visibility 0s, opacity 0.3s; -moz-transition: visibility 0s, opacity 0.3s; transition: visibility 0s, opacity 0.3s; } .cbp-tm-show-above .cbp-tm-submenu { bottom: 100%; padding-bottom: 10px; } .cbp-tm-show-below .cbp-tm-submenu { top: 100%; padding-top: 10px; } /* extreme cases: not enough space on the sides */ .cbp-tm-nospace-right .cbp-tm-submenu { right: 0; left: auto; } .cbp-tm-nospace-left .cbp-tm-submenu { left: 0; } /* last menu item has to fit on the screen */ .cbp-tm-menu > li:last-child .cbp-tm-submenu { right: 0; } /* arrow: depending on where the menu will be shown, we set the right position for the arrow */ .cbp-tm-submenu:after { border: solid transparent; content: " "; height: 0; width: 0; position: absolute; pointer-events: none; } .cbp-tm-show-above .cbp-tm-submenu:after { top: 100%; margin-top: -10px; } .cbp-tm-show-below .cbp-tm-submenu:after { bottom: 100%; margin-bottom: -10px; } .cbp-tm-submenu:after { border-color: transparent; border-width: 16px; margin-left: -16px; left: 50%; } .cbp-tm-show-above .cbp-tm-submenu:after { border-top-color: #fff; } .cbp-tm-show-below .cbp-tm-submenu:after { border-bottom-color: #fff; } .cbp-tm-submenu > li { display: block; background: #fff; } .cbp-tm-submenu > li > a { padding: 5px 2.3em 5px 0.6em; /* top/bottom paddings in 'em' cause a tiny "jump" in Chrome on Win */ display: block; font-size: 1.2em; position: relative; color: #47a3da; border: 4px solid #fff; -webkit-transition: all 0.2s; -moz-transition: all 0.2s; transition: all 0.2s; } .no-touch .cbp-tm-submenu > li > a:hover, .no-touch .cbp-tm-submenu > li > a:active { color: #fff; background: #47a3da; } /* the icons (main level menu icon and sublevel icons) */ .cbp-tm-submenu li a:before, .cbp-tm-menu > li > a:before { font-family: 'cbp-tmicons'; speak: none; font-style: normal; font-weight: normal; font-variant: normal; text-transform: none; line-height: 1; vertical-align: middle; margin-right: 0.6em; -webkit-font-smoothing: antialiased; } .cbp-tm-submenu li a:before { position: absolute; top: 50%; margin-top: -0.5em; right: 0.5em; } .cbp-tm-menu > li > a:not(:only-child):before { content: "\f0c9"; font-size: 60%; opacity: 0.3; } .cbp-tm-icon-archive:before { content: "\e002"; } .cbp-tm-icon-cog:before { content: "\e003"; } .cbp-tm-icon-users:before { content: "\e004"; } .cbp-tm-icon-earth:before { content: "\e005"; } .cbp-tm-icon-location:before { content: "\e006"; } .cbp-tm-icon-mobile:before { content: "\e007"; } .cbp-tm-icon-screen:before { content: "\e008"; } .cbp-tm-icon-mail:before { content: "\e009"; } .cbp-tm-icon-contract:before { content: "\e00a"; } .cbp-tm-icon-pencil:before { content: "\e00b"; } .cbp-tm-icon-article:before { content: "\e00c"; } .cbp-tm-icon-clock:before { content: "\e00d"; } .cbp-tm-icon-videos:before { content: "\e00e"; } .cbp-tm-icon-pictures:before { content: "\e00f"; } .cbp-tm-icon-link:before { content: "\e010"; } .cbp-tm-icon-refresh:before { content: "\e011"; } .cbp-tm-icon-help:before { content: "\e012"; } /* Media Queries */ @media screen and (max-width: 55.6875em) { .cbp-tm-menu { font-size: 80%; } } @media screen and (max-height: 25.25em), screen and (max-width: 44.3125em) { .cbp-tm-menu { font-size: 100%; position: relative; text-align: center; padding: 0; top: auto; } .cbp-tm-menu > li { display: block; margin: 0; border-bottom: 4px solid #3793ca; } .cbp-tm-menu > li:first-child { border-top: 4px solid #3793ca; } li.cbp-tm-show > a, .no-touch .cbp-tm-menu > li > a:hover, .no-touch .cbp-tm-menu > li > a:active { color: #fff; background: #02639d; } .cbp-tm-submenu { position: relative; display: none; width: 100%; } .cbp-tm-submenu > li { padding: 0; } .cbp-tm-submenu > li > a { padding: 0.6em 2.3em 0.6em 0.6em; border: none; border-bottom: 2px solid #6fbbe9; } .cbp-tm-submenu:after { display: none; } .cbp-tm-menu .cbp-tm-show .cbp-tm-submenu { display: block; width: 100%; left: 0; margin: 0; padding: 0; bottom: auto; top: auto; } }/** * cbpTooltipMenu.js v1.0.0 * http://www.codrops.com * * Licensed under the MIT license. * http://www.opensource.org/licenses/mit-license.php * * Copyright 2013, Codrops * http://www.codrops.com */ ;( function( window ) { 'use strict'; var document = window.document, docElem = document.documentElement; function extend( a, b ) { for( var key in b ) { if( b.hasOwnProperty( key ) ) { a[key] = b[key]; } } return a; } // from https://github.com/ryanve/response.js/blob/master/response.js function getViewportH() { var client = docElem['clientHeight'], inner = window['innerHeight']; if( client < inner ) return inner; else return client; } // http://stackoverflow.com/a/11396681/989439 function getOffset( el ) { return el.getBoundingClientRect(); } // http://snipplr.com/view.php?codeview&id=5259 function isMouseLeaveOrEnter(e, handler) { if (e.type != 'mouseout' && e.type != 'mouseover') return false; var reltg = e.relatedTarget ? e.relatedTarget : e.type == 'mouseout' ? e.toElement : e.fromElement; while (reltg && reltg != handler) reltg = reltg.parentNode; return (reltg != handler); } function cbpTooltipMenu( el, options ) { this.el = el; this.options = extend( this.defaults, options ); this._init(); } cbpTooltipMenu.prototype = { defaults : { // add a timeout to avoid the menu to open instantly delayMenu : 100 }, _init : function() { this.touch = Modernizr.touch; this.menuItems = document.querySelectorAll( '#' + this.el.id + ' > li' ); this._initEvents(); }, _initEvents : function() { var self = this; Array.prototype.slice.call( this.menuItems ).forEach( function( el, i ) { var trigger = el.querySelector( 'a' ); if( self.touch ) { trigger.addEventListener( 'click', function( ev ) { self._handleClick( this, ev ); } ); } else { trigger.addEventListener( 'click', function( ev ) { if( this.parentNode.querySelector( 'ul.cbp-tm-submenu' ) ) { ev.preventDefault(); } } ); el.addEventListener( 'mouseover', function(ev) { if( isMouseLeaveOrEnter( ev, this ) ) self._openMenu( this ); } ); el.addEventListener( 'mouseout', function(ev) { if( isMouseLeaveOrEnter( ev, this ) ) self._closeMenu( this ); } ); } } ); }, _openMenu : function( el ) { var self = this; clearTimeout( this.omtimeout ); this.omtimeout = setTimeout( function() { var submenu = el.querySelector( 'ul.cbp-tm-submenu' ); if( submenu ) { el.className = 'cbp-tm-show'; if( self._positionMenu( el ) === 'top' ) { el.className += ' cbp-tm-show-above'; } else { el.className += ' cbp-tm-show-below'; } } }, this.touch ? 0 : this.options.delayMenu ); }, _closeMenu : function( el ) { clearTimeout( this.omtimeout ); var submenu = el.querySelector( 'ul.cbp-tm-submenu' ); if( submenu ) { // based on https://github.com/desandro/classie/blob/master/classie.js el.className = el.className.replace(new RegExp("(^|\\s+)" + "cbp-tm-show" + "(\\s+|$)"), ' '); el.className = el.className.replace(new RegExp("(^|\\s+)" + "cbp-tm-show-below" + "(\\s+|$)"), ' '); el.className = el.className.replace(new RegExp("(^|\\s+)" + "cbp-tm-show-above" + "(\\s+|$)"), ' '); } }, _handleClick : function( el, ev ) { var item = el.parentNode, items = Array.prototype.slice.call( this.menuItems ), submenu = item.querySelector( 'ul.cbp-tm-submenu' ) // first close any opened one.. if( this.current && items.indexOf( item ) !== this.current ) { this._closeMenu( this.el.children[ this.current ] ); this.el.children[ this.current ].querySelector( 'ul.cbp-tm-submenu' ).setAttribute( 'data-open', 'false' ); } if( submenu ) { ev.preventDefault(); var isOpen = submenu.getAttribute( 'data-open' ); if( isOpen === 'true' ) { this._closeMenu( item ); submenu.setAttribute( 'data-open', 'false' ); } else { this._openMenu( item ); this.current = items.indexOf( item ); submenu.setAttribute( 'data-open', 'true' ); } } }, _positionMenu : function( el ) { // checking where's more space left in the viewport: above or below the element var vH = getViewportH(), ot = getOffset(el), spaceUp = ot.top , spaceDown = vH - spaceUp - el.offsetHeight; return ( spaceDown <= spaceUp ? 'top' : 'bottom' ); } } // add to global namespace window.cbpTooltipMenu = cbpTooltipMenu; } )( window ); $(document).ready(function () { //make Bootstrap dropdown to behave like select //this is enough for most people! When user selects an option, a hidden input named "fruit" with the selected value is created. var menu = new cbpTooltipMenu( document.getElementById( 'cbp-tm-menu' ) ); });