Hover-Down Submenus for Casper Here

This is the most rudimentary of drop downs, just copy-and-paste code into your Site’s Header and Footer Code Injections in the Admin area of your Ghost site, and add a dash and a space to a Primary Navigation Menu Item to make that item appear in a drop down menu below the Menu Item above it.

So this can be installed and configured on hosted sites or in other circumstances where you only have Admin access.

Credit goes to @ahmadajmi at Aspire Themes where I got the idea and the inspiration for the code.

If you want or need a more robust menu system that can also be copy-and-pasted in the Admin, @themeix has kindly provided a full mega-menu system that can also be used for simple drop downs as well:

This is the view from my Desktop…

And this is the view on my iPhone 13 Pro…


OK SO – HERE GOES THE “HOW-TO”…

This is how we use Ghost’s built-in Primary Navigation settings to set up the links we want in the dropdowns…

HERE IS THE CODE TO PASTE INTO THE SITE HEADER CODE INJECTION

<style>
    
@media (max-width: 991px) {
    .has-cover.gh-head {
        display: flex;
        align-items: center;
        flex-direction: column;
        position: fixed;
        top: 0;
        bottom: 0;
        right: 0;
        left: 0;
        z-index: 10;
        width: 100%;
        height: 100vh;
        padding-top: 72px;
        background-color: var(--background-secondary);
        opacity: 0;
        visibility: hidden;
        transform: scale(0.96);
    }
    .has-cover.gh-head-open {
        opacity: 1;
        visibility: visible;
        transform: scale(1);
        transition: all half(var(--motion-duration)) cubic-bezier(0.694, 0, 0.335, 1);
    }
}

 @media (min-width: 991.1px) {
    .has-cover.gh-head {
        display: block;
        flex: 2;
        display: flex;
        align-items: center;
        justify-content: flex-end;
    }
}

@media (max-width: 991px) {
    .has-cover.gh-head-menu {
        width: 100%;
        padding-left: 32px;
        padding-right: 32px;
    }
}

@media (min-width: 991.1px) {
    .has-cover.gh-head-menu {
        display: flex;
        align-items: center;
        justify-content: flex-end;
    }
}    

@media (min-width: 991.1px) {
    li[class*="nav-"]:not(:last-child) {
        margin-right: 24px;
    }
}

@media (max-width: 991px) {
    li[class*="nav-"] {
        margin-bottom: 16px;
    }
}

@media (min-width: 991.1px) {
    li[class*="nav-"][class*="--hasDropDown"] {
        position: relative;
    }
	li[class*="nav-"][class*="--hasDropDown"] a:after {
		all: unset;
		content: "▼";
		padding-left: 5px;
		font-size: 12px;
		color: inherit;
	}
    li[class*="nav-"][class*="--hasDropDown"] .isDropDown a:after {
		display:none;
	}
    li[class*="nav-"][class*="--hasDropDown"]:focus-within > li[class*="nav-"]:after,
    li[class*="nav-"][class*="--hasDropDown"]:hover > li[class*="nav-"]:after {
        background-color: transparent;
    }
    li[class*="nav-"][class*="--hasDropDown"]:focus-within .isDropDown,
    li[class*="nav-"][class*="--hasDropDown"]:hover .isDropDown {
        opacity: 1;
        visibility: visible;
    }
}    

@media (min-width: 991.1px) {
	.isDropDown {
		z-index: 1;
		opacity: 0;
		visibility: hidden;
		position: absolute;
		margin: 0;
		max-width: unset;
		list-style: none;
		/* The padding inside the drop down (the space surrounding the links) */
		padding: 10px;
		/* The rounded corners of the drop down */
		border-radius: 6px;
		/* The background color of the drop down */
		background: #000;
		/* The color of the links in the drop down */
		color: inherit;
	}
	.isDropDown li[class*="nav-"] {
	    margin-right: 0 !important;
	}
	.isDropDown li[class*="nav-"]:not(:last-child) {
	    margin-bottom: 0;
	}    
} 

li[class*="nav-"] a {
    display: flex;
    align-items: center;
    width: -webkit-fit-content;
    width: -moz-fit-content;
    width: fit-content;
    font-size: 16px;
    line-height: 1.5;
    font-weight: inherit;
    white-space: nowrap;
}    

@media (max-width: 991px) {
    li[class*="nav-"] a {
        font-size: 2.5rem;
        line-height: 1.5;
    }
}  

@media (min-width: 991.1px) {
    li[class*="nav-"] a {
        position: relative;
    }
    li[class*="nav-"] a:after {
        content: "";
        display: block;
        width: 100%;
        height: 2px;
        position: absolute;
        bottom: -2px;
        background-color: transparent;
    }
}    

/* Underline or other style for the link of the Current Page you are on  */    
li[class*="nav-"].nav-current a:after {
    background-color: transparent;
}

/* Underline or other style for the Home link when you are on the Home page */
.home-template li[class*="nav-"].nav-current a:after {
    background-color: transparent;
}

/* Underline or other style for the links in certain states */
li[class*="nav-"] a:active:after,
li[class*="nav-"] a:focus:after,
li[class*="nav-"] a:hover:after {
    background-color: transparent;
}
    
@media (max-width: 991px) {
    #gh-head .gh-head-inner {
        grid-template-columns: 1fr;
    	height: auto;
	}
	.gh-head-open #gh-head .gh-head-menu,
    #gh-head .gh-head-menu .nav {
    	align-items: flex-start;
    	display: flex;
    	flex-direction: column;
        margin: 0 auto;
	}
    .gh-head-menu .nav li {
        text-align: left;
	}
    .gh-head-menu .nav li.hasDropDown {
        margin: 0;
    	padding: 0;
    	display: flex;
    	flex-direction: column;
    	align-items: flex-start;
	}
    .gh-head-menu ul.isDropDown {
    	list-style: none;
    	text-align: left;
    	margin: 0;
    	padding: 0 0 0 10px;
	} 
    .gh-head-menu ul.isDropDown li {
    	margin: 0;
    	padding: 0;
    	text-align: left;
	} 
    .gh-head-menu ul.isDropDown li a:before {
		all: unset;
		content: " - ";
    	}
    .gh-head-menu ul.isDropDown li a {
    	font-size: 2rem;
    	line-height: 1.5;
	}
}

</style>

AND HERE IS THE CODE TO PASTE INTO THE SITE FOOTER CODE INJECTION

<script>
var dropDown_list = [],
latest_navigation_item,
// IMPORTANT: For themes other than Casper, change the selector just below to select your themes Primary Navigation links
nav_list = document.querySelectorAll('.gh-head-menu li');
var newMenuList = [];
var menuTree = {};
nav_list.forEach( (item, index) => {
if(item.childNodes[0].innerText.startsWith('-')) {
if(menuTree[newMenuList.length - 1]) {
menuTree[newMenuList.length - 1].push(item);
} else {
menuTree[newMenuList.length - 1] = [item];
}
} else {
newMenuList.push(item);
}
});
nav_list = newMenuList.map((item, index) => {
if(menuTree[index]) {
let dropdown = document.createElement('ul');
dropdown.className = 'isDropDown';
menuTree[index].forEach(child => {
dropDown_item_text = child.childNodes[0].innerText;
child.childNodes[0].innerText = dropDown_item_text.replace('- ', '');
dropdown.appendChild(child);
});
item.className += '--hasDropDown';
item.appendChild(dropdown);
}
return item;
});
</script>
5 Likes

This code need jQuery to run. If your theme doesn’t have jQuery, you’ll need to load it before the footer script.

I have a non-jQuery version kicking around here somewhere…

Hi @denvergeeks , thanks for your guide!
I have a problem with your code. See the image please
It’s a bug?

imagen

And another bug i think…

imagen

@Joan what theme are you using?

Can you provide a live site link?

It’s nearly impossible to help without seeing your code.

(It looks like just needs some CSS adjustment)

@Cathy_Sarisky – please do share it with the class :smiley:

Oh and BTW – on page refresh this one has no page flash or jumpy or jiggly, right? Can you confirm this?

As an FYI for folks – Casper is the theme this is designed for out-of-the-box, and the Casper Theme does already include jQuery built-in.

1 Like

Of course :slight_smile: (Solo Theme)

https://blog.hdsplus.co/

@Joan I could help you but your site is behind a Login wall.

Also, as of 10:30 MST I replaced the Header and Footer Code Injections in the first post up top, so that now all of the menu items show in mobile as well.

You might want to copy and paste that more complete release.

Please do let me know how it goes. Again, the menu is pre-configured for Casper. But if you need some help configuring it for your theme I can help with that.

Thanks for the reply!
With Casper theme your code works perfectly!
With Solo Theme not.

It’s possible adding dividers between items?
Thanks for all!

Thank you @Joan for testing this for me!

It really does help me a lot to have others put my new toys through their own personal usage process.

I can add those dividers for you, but first I’d like you to try it yourself…

We’re going to use the same method we used to add those dividers in the @themeix menu here…

Give it a go, and let me know how it goes!

Hint: I have it working on my testing site here:

Screenshot 2022-11-10 093805

See if you can find the code!

1 Like

Thanks you so much!
Working with “isDropDown” class :stuck_out_tongue:

:muscle: :facepunch:

I tried to keep the design and CSS simple and intuitive.

1 Like

Bad news @denvergeeks
With Casper 5.4.0 and new “navbar” your Drop-down menu don’t work very well :frowning:

@Joan maybe you have something else on your site that is messing it up.

Please be specific and provide screenshots of the problem(s) you are seeing!

I am not seeing any problem whatsoever… just now I updated everything on my fresh test site (which has nothing on it but the drop down at https://casper.ghost.pub . . .

Casper 5.4.0 Installed and Running…

Desktop View…

Mobile View…

Site Code Injections…

When there are X more number of items with the new “stacked” distribution of Casper 5.4.0, it automatically switches to the new Casper menu.

Whoah this is the first I’ve seen of a new menu in Casper!

Can you point me to any Documentation so I can read about it?

1 Like

Nothing… only this :slight_smile:

Fantabulous to have (what I would call) a click-down overflow menu addition to the new Casper version!!!

Here below I’ve simplified the CSS for this (what I will call) hover-down hierarchical submenus

(I hope that Team Ghost will build this type of menu into Casper as an option as well! Better yet, I would like to see both menu types being available as options in the core theme settings so they would be built-in options for all themes.)

<style>

li[class*="nav-"][class*="--hasDropDown"] {
	position: relative;
}
li[class*="nav-"][class*="--hasDropDown"] a:after {
	content: "▼";
	padding-left: 5px;
	font-size: 12px;
	color: inherit;
}
li[class*="nav-"][class*="--hasDropDown"] .isDropDown a:after {
	display:none;
}
li[class*="nav-"][class*="--hasDropDown"]:focus-within > li[class*="nav-"]:after,
li[class*="nav-"][class*="--hasDropDown"]:hover > li[class*="nav-"]:after {
	background-color: transparent;
}
li[class*="nav-"][class*="--hasDropDown"]:focus-within .isDropDown,
li[class*="nav-"][class*="--hasDropDown"]:hover .isDropDown {
	opacity: 1;
	visibility: visible;
}
.isDropDown {
	z-index: 1;
	opacity: 0;
	visibility: hidden;
	position: absolute;
	margin: 0;
	max-width: unset;
	list-style: none;
	/* The padding inside the drop down (the space surrounding the links) */
	padding: 10px;
	/* The rounded corners of the drop down */
	border-radius: 6px;
	/* The background color of the drop down */
	background: #000;
	/* The color of the links in the drop down */
	color: inherit;
}
.isDropDown li[class*="nav-"] {
	margin-right: 0 !important;
}
.isDropDown li[class*="nav-"]:not(:last-child) {
	margin-bottom: 0;
    /* Dividers between the dropdown items */
    border-bottom: 1px solid #ddd;
}

@media (max-width: 991px) {
    #gh-head .gh-head-inner {
        grid-template-columns: 1fr;
    	height: auto;
	}
	.gh-head-open #gh-head .gh-head-menu,
    #gh-head .gh-head-menu .nav {
    	align-items: flex-start;
    	display: flex;
    	flex-direction: column;
        margin: 0 auto;
	}
    .gh-head-menu .nav li {
        text-align: left;
	}
    .gh-head-menu .nav li.hasDropDown {
        margin: 0;
    	padding: 0;
    	display: flex;
    	flex-direction: column;
    	align-items: flex-start;
	}
    .gh-head-menu ul.isDropDown {
    	list-style: none;
    	text-align: left;
    	margin: 0;
    	padding: 0 0 0 10px;
	} 
    .gh-head-menu ul.isDropDown li {
    	margin: 0;
    	padding: 0;
    	text-align: left;
	} 
    .gh-head-menu ul.isDropDown li a {
    	font-size: 2rem;
    	line-height: 1.5;
	}
}

</style>
1 Like

If anyone can provide guidance as to why, when the window is resized in any direction, the page needs to be refreshed again for this drop down to take effect, please do post any help or clues…

1 Like

It happens to me too… It is annoying… Sorry I can’t help, I’m not a coding expert :frowning: . Also with Casper 5.4.0, they have removed the “gh-social” div with the social network icons in the header. I’ve opened a ticket on Github…

You can watch the new Nav in my site https://hdsplus.co

OK @Joan I’ve got a new rendition of the script for the footer injection. I’ve also edited and commented a little more in the CSS.

For the script I just followed the example of the new overflow click-down menu in Casper. (The code you linked to at Added navbar options (#906) · TryGhost/Casper@cf30ada · GitHub)

Here’s what I’ve got now that’s working correctly. (This code might have extra cruft that can be removed. Hopefully someone better at JS can tell us.)

The CSS for the Site Header Code Injection…

<style>

li[class*="nav-"][class*="--hasDropDown"] {
	position: relative;
}
li[class*="nav-"][class*="--hasDropDown"] a:after {
	content: "▼";
	padding-left: 5px;
	font-size: 12px;
	color: inherit;
}
li[class*="nav-"][class*="--hasDropDown"] .isDropDown a:after {
	display:none;
}
li[class*="nav-"][class*="--hasDropDown"]:focus-within > li[class*="nav-"]:after,
li[class*="nav-"][class*="--hasDropDown"]:hover > li[class*="nav-"]:after {
	background-color: transparent;
}
li[class*="nav-"][class*="--hasDropDown"]:focus-within .isDropDown,
li[class*="nav-"][class*="--hasDropDown"]:hover .isDropDown {
	opacity: 1;
	visibility: visible;
}
.isDropDown {
	z-index: 1;
	opacity: 0;
	visibility: hidden;
	position: absolute;
	margin: 0;
	max-width: unset;
	list-style: none;
	/* The padding inside the drop down (the space surrounding the links) */
	padding: 10px;
	/* The rounded corners of the drop down */
	border-radius: 6px;
	/* The background color of the drop down */
	background: #000;
	/* The color of the links in the drop down */
	color: inherit;
}
.isDropDown li[class*="nav-"] {
	margin-right: 0 !important;
}
.isDropDown li[class*="nav-"]:not(:last-child) {
	margin-bottom: 0;
    /* Dividers between the dropdown items */
    border-bottom: 1px solid #ddd;
}

/* OPTIONAL: in mobile, left align all menu items and indent submenu items */
@media (max-width: 991px) {
    #gh-head .gh-head-inner {
        grid-template-columns: 1fr;
    	height: auto;
	}
	.gh-head-open #gh-head .gh-head-menu,
    #gh-head .gh-head-menu .nav {
    	align-items: flex-start;
    	display: flex;
    	flex-direction: column;
        margin: 0 auto;
	}
    .gh-head-menu .nav li {
        text-align: left;
	}
    .gh-head-menu .nav li.hasDropDown {
        margin: 0;
    	padding: 0;
    	display: flex;
    	flex-direction: column;
    	align-items: flex-start;
	}
    .gh-head-menu ul.isDropDown {
    	list-style: none;
    	text-align: left;
    	margin: 0;
    	padding: 0 0 0 10px;
	}
    .gh-head-menu ul.isDropDown li {
    	margin: 0;
    	padding: 0;
    	text-align: left;
	}
    .gh-head-menu ul.isDropDown li a {
    	font-size: 2rem;
    	line-height: 1.5;
	}
}
    
</style>

The script for the Site Footer Code Injection…

<script>
    
(function () {
    const mediaQuery = window.matchMedia('(max-width: 991px)');
    
    // IMPORTANT: For themes other than Casper, change the selector just below to select your theme's header menu selector
    const menu = document.querySelector('.gh-head-menu');
    const nav = menu.querySelector('.nav');
    if (!nav) return;

    // IMPORTANT: For themes other than Casper, change the selector just below to select your theme's header logo selector
    const logo = document.querySelector('.gh-head-logo');
    const navHTML = nav.innerHTML;

    if (mediaQuery.matches) {
        const items = nav.querySelectorAll('li');
        items.forEach(function (item, index) {
            item.style.transitionDelay = 0.03 * (index + 1) + 's';
        });
    }
    
    const makeHoverdown = function () {
        if (mediaQuery.matches) return;

        var dropDown_list = [],
        latest_navigation_item,
        // IMPORTANT: For themes other than Casper, change the selector just below to select your theme's header menu item selector 
        nav_list = document.querySelectorAll('.gh-head-menu li');
        var newMenuList = [];
        var menuTree = {};

        nav_list.forEach( (item, index) => {
            if(item.childNodes[0].innerText.startsWith('-')) {
                if(menuTree[newMenuList.length - 1]) {
            menuTree[newMenuList.length - 1].push(item);
                } else {
            menuTree[newMenuList.length - 1] = [item];
            }
        } else {
        newMenuList.push(item);
        }
        });
        
        nav_list = newMenuList.map((item, index) => {
        if(menuTree[index]) {
            let dropdown = document.createElement('ul');
            dropdown.className = 'isDropDown';
            menuTree[index].forEach(child => {
                dropDown_item_text = child.childNodes[0].innerText;
                child.childNodes[0].innerText = dropDown_item_text.replace('- ', '');
                dropdown.appendChild(child);
            });
        item.className += '--hasDropDown';
        item.appendChild(dropdown);
        }
        return item;
        });
    }

    imagesLoaded(logo, function () {
        makeHoverdown();
    });

    window.addEventListener('resize', function () {
        setTimeout(function () {
            nav.innerHTML = navHTML;
            makeHoverdown();
        }, 1);
    });

})();
</script>
1 Like