Cool Multi-level Context Menu With jQuery And CSS3
File Size: | 30.7 KB |
---|---|
Views Total: | 2012 |
Last Update: | |
Publish Date: | |
Official Website: | Go to website |
License: | MIT |

A pretty cool multi-level context menu to override the default browser right-click menu. Built using JavaScript (jQuery) and CSS/CSS3.
Features:
- Pretty nice CSS3 animations.
- Cool CSS filters.
- Auto-reposition if it overflows the screen.
- Theme switcher.
- SEO-friendly.
How to use it:
1. Create a multi-level context menu from nested HTML lists as follows:
<ul class="context"> <li class="top"> Menu 1 <ul class="context sub"> <li title="Chosen: Red"> Menu 1-1 </li> <li title="Chosen: Xtra Large"> Menu 1-2 </li> </ul> </li> <li class="hilight"> Menu 2 (Highlighted) </li> <li> Menu 3 </li> <!-- Separator --> <li class="div"></li> <li> Menu 4 <ul class="context sub"> <li class="hilight"> Menu 4-1 </li> <li> Menu 4-2 </li> </ul> </li> </ul>
2. Create two input fields for the theme switcher.
<div class="colors"> <h4>Theme Switcher</h4> <input type="color" name="c1" id="c1" value="#673ab7"/> <input type="color" name="c2" id="c2" value="#3f51b5"/> </div>
3. The required CSS rules for the context menu. Feel free to create your own styles by overriding the variables at the beginning of the following CSS snippets.
:root { --bg: #24262d; --text: #dfe3ff; --color1: #673ab7; --color2: #3f51b5; --divider: rgba(255,255,255,0.16); } .context { font-size: 0.875rem; color: var(--text); list-style: none; margin: 0; padding: 0.05em 0.25em; border: 1px solid transparent; border-right-color: rgba(255, 255, 255, 0.15); border-bottom-color: rgba(255, 255, 255, 0.15); border-left-color: rgba(0, 0, 0, 0.15); border-top-color: rgba(0, 0, 0, 0.15); border-radius: 5px; position: absolute; min-width: 16em; z-index: 1; background: linear-gradient(145deg, var(--color1), var(--color2)); box-shadow: 2px 5px 16px -4px #141321; will-change: transform, opacity, filter; transition: transform, opacity, visibility, filter; transition-duration: 0.5s, 0.2s, 0.4s, 0.3s; transition-delay: 0.1s, 0s, 0.4s, 0.2s; transition-timing-function: ease; transform: rotate3d(-1, -1, 0, 30deg) scale(1); transform-origin: 0 0; opacity: 0; visibility: hidden; filter: blur(6px); } .context, .context * { -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; cursor: default; } .context.is-visible { opacity: 1; transform: none; transition-delay: 0s, 0s, 0s, 0s; visibility: visible; filter: none; } .context.sub { background: var(--color2); width: -webkit-max-content; width: -moz-max-content; width: max-content; min-width: 10em; left: 100%; top: -0.4em; transform: translateX(-0.7em); transition: transform, opacity, width, min-width, visibility; transition-timing-function: ease; transition-duration: 0.4s, 0.25s, 0.15s, 0.15s, 0.01s; transition-delay: 0.4s, 0.25s, 0.3s, 0.3s, 0.35s; overflow: hidden; filter: none; } .context.sub .f { transform: translateX(-2.25em); } .context.sub.oppositeX { right: 100%; left: auto; transform: translateX(0.7em); } .context.sub.oppositeY { top: auto; bottom: -0.4em; } .context > li { padding: 0.3em 1.5em 0.35em 2.8em; border-radius: 3px; position: relative; } .context > li:before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; right: 0; border-radius: 3px; z-index: -1; background-color: rgba(97, 97, 97, 0.37); mix-blend-mode: color-dodge; transition: opacity 0.15s cubic-bezier(0.55, 0.06, 0.68, 0.19); opacity: 0; } .context > li.hilight { font-weight: 500; padding-bottom: 0.5em; color: white; } .context > li:not(.context > li.nope):hover { color: white; } .context > li:not(.context > li.nope):hover:before { opacity: 1; transition: opacity 0.1s cubic-bezier(0.25, 0.46, 0.45, 0.94); } .context > li:not(.context > li.nope):hover .sub { opacity: 1; transform: translateX(0); transition-delay: 0.2s, 0.25s, 0.2s, 0.2s, 0s; border-radius: 0 3px 3px 3px; visibility: visible; } .context > li:hover > .f, .context > li.hilight > .f { opacity: 1; } .context > li:last-child { margin-bottom: 0.25em; } .context > li:first-child { margin-top: 0.25em; } .context > li.nope { color: rgba(255, 255, 255, 0.3); } .context > li.active { -webkit-animation: flash 0.5s ease 1; animation: flash 0.5s ease 1; } .context > li:nth-of-type(1) { margin-top: 0.5em; } .context > li .f { opacity: 0.5; transition: all 0.2s ease; } .context > li i { font-style: normal; text-decoration: underline; -webkit-text-decoration-color: rgba(255, 255, 255, 0.35); text-decoration-color: rgba(255, 255, 255, 0.35); } .context .div { border-bottom: 1px solid var(--divider); padding: 0; margin-top: 0.3em; margin-bottom: 0.35em; } .context .f { font-style: normal; position: absolute; transform: translateX(-2.4em); } .context .f[class*=chevron-right] { right: 0; transform: none; } .f.f-circle { fill: red; } span.size { position: absolute; font-size: 0.675em; left: 1.2em; top: 0.8em; text-shadow: aliceblue; } @-webkit-keyframes flash { 0% { background: rgba(255, 255, 255, 0); } 7% { background: rgba(255, 255, 255, 0.2); } 14% { background: rgba(255, 255, 255, 0); } 21% { background: rgba(255, 255, 255, 0.3); } } @keyframes flash { 0% { background: rgba(255, 255, 255, 0); } 7% { background: rgba(255, 255, 255, 0.2); } 14% { background: rgba(255, 255, 255, 0); } 21% { background: rgba(255, 255, 255, 0.3); } }
4. Load the necessary jQuery library at the end of the document.
<script src="/path/to/cdn/jquery.min.js"></script>
5. Load the necessary jQuery library at the end of the document.
$(function () { var $doc = $(document), $context = $(".context:not(.sub)"), $c1 = $("#c1"), $c2 = $("#c2"); $doc.on("contextmenu", function (e) { var $window = $(window), $sub = $context.find(".sub"); $sub.removeClass("oppositeX oppositeY"); e.preventDefault(); var w = $context.width(); var h = $context.height(); var x = e.clientX; var y = e.clientY; var ww = $window.width(); var wh = $window.height(); var padx = 30; var pady = 20; var fx = x; var fy = y; var hitsRight = (x + w >= ww - padx); var hitsBottom = (y + h >= wh - pady); if (hitsRight) { fx = ww - w - padx; } if (hitsBottom) { fy = wh - h - pady; } $context .css({ left: fx - 1, top: fy - 1 }); var sw = $sub.width(); var sh = $sub.height(); var sx = $sub.offset().left; var sy = $sub.offset().top; var subHitsRight = (sx + sw - padx >= ww - padx); var subHitsBottom = (sy + sh - pady >= wh - pady); if (subHitsRight) { $sub.addClass("oppositeX"); } if (subHitsBottom) { $sub.addClass("oppositeY"); } $context.addClass("is-visible"); $doc.on("mousedown", function (e) { var $tar = $(e.target); console.log($tar) if (!$tar.is($context) && !$tar.closest(".context").length && !$tar.is($c1) && !$tar.is($c2)) { $context.removeClass("is-visible"); $doc.off(e); } }); }); $context.on("mousedown touchstart", "li:not(.nope)", function (e) { if (e.which === 1) { var $item = $(this); $item.removeClass("active"); setTimeout(function () { $item.addClass("active"); }, 10); } }); $c1.on("input change", function (e) { var color = $(this).val(); document.body.style.setProperty("--color1", color); }); $c2.on("input change", function (e) { var color = $(this).val(); document.body.style.setProperty("--color2", color); }); });
This awesome jQuery plugin is developed by simeydotme. For more Advanced Usages, please check the demo page or visit the official website.