Building hover menus in CSS

How to build hover menus in pure HTML/CSS.

Kenneth Reilly
UX Collective

--

Screenshot of the example project with three hover menus
Screenshot of the example project

AA good menu design is an important part of any website or web app UI. Using only modern HTML and CSS, all kinds of menu combinations can be created to handle whatever user interactions are necessary. In this article, we’ll take a look at how to build three different hover menus: a simple column menu, another one with nested sub-menus, and finally a cool radial “pie” menu with emoji icons.

For a copy of the example project used in this article, check out this repo.

Concepts

Hover menus in CSS take advantage of the :hover pseudo-selector and various animations, transitions, and transforms to create the menu interactions. Complex menus can be created by properly sizing the menu components and adding interactions to them as necessary.

The basic idea is simple: when the mouse hovers over a menu, apply whatever effects are desired (such as expanding the menu or changing background color) and display the contents of the menu to the user. The contents of the menu can be arranged in various ways as we will examine shortly.

HTML

First, let’s take a look at the project structure in index.html:

Aside from some basic document structure, we have definitions for three nav menus, each with a header element and varying content. The first menu is simple and contains four choices. The second menu is a little more complex and contains four sub-menus, each with four choices. The third contains emoji device icons that will be displayed around it in a circle.

The HTML for this example is kept simple by design and most of the magic happens in CSS, so let’s take a look at that next.

CSS

The styles for the example project are located in style.css:

First up is the :root block, which contains CSS variables that will be used throughout the rest of the file. Variables are a powerful feature introduced in CSS Level 3 that greatly simplifies the task of organizing CSS code. Here we have a base size for navigation items as --nav-size that will set both the height and width of a closed navigation menu to 12vh(which is 12% of the viewport height). Background colors for the menus are also defined here.

The item-fade-in animation will be used to show the hidden menu items by setting their display property to flex and fading-in the items with opacity.

Next, the body is styled, scaled to 100% height and width of the document, and set to display content in a horizontal flex container. The nav items (the root containers for each menu) are set to --nav-size and styled with various properties, and are also defined as flex containers to allow proper spacing of menu items. Note the transition on this element’s non-hover selector, which will cause the element to smoothly transition back to it’s default state (instead of just snapping back immediately). The nav > header selector sizes the menu header to --nav-size and flex is used once again, in this case to center the text inside the header both horizontally and vertically.

Here’s where we start to get into the actual hover logic of the menu. The selector nav:hover causes the nav item, when hovered over, to transition it’s background color and height, using 120ms and 240ms linear transitions respectively. This demonstrates how multiple transitions can be chained inside a single CSS rule. Next, the first two menus are selected using the nth-child pseudo-class, to extend their transitions with height which will cause the menu to open vertically when activated. Menu items are controlled using the nav > div and related selectors, and these items are also set to center their own content using flex and respond to hover events by applying transitions and animations.

The first menu is straightforward and simply drops upon hover, revealing a list of items that will each change background color when hovered over. The second menu is a little more complex and provides a list of horizontal expanding sub-menus when opened. This is achieved in the same manner as the basic menu effect, by selecting deeper into the menu and applying hover effects to show/hide sub-menu items using the same principles.

The third menu takes a completely different approach, and does not change size when hovered but instead goes transparent, and applies effects to child elements that cause them to be rendered in a circle around the menu. This cool effect is achieved by sizing the menu items to the same size as the parent, using position: fixed to stack them vertically on top of each other, rotating each item by a factor of 90 degrees to encircle the menu, and applying transform: translateX(var(--nav-size)) to the child span element that will shift the span over by one “nav size unit”. The emoji icons are subsequently rotated as necessary, to re-orient them in the right direction (as the previous rotation places some of them sideways, upside-down, etc).

This example illustrates just a few cool menus that can be designed and built purely in CSS. These menus can be modified or extended in any number of ways to produce interactions that feel right for the application at hand. Some of these concepts can be transferred to responsive mobile designs, replacing hover interactions with implementations of the CSS checkbox hack.

When it comes to HTML and CSS, the front-end developer is only limited by imagination (a healthy dose of patience also goes a long way). Thanks for reading and good luck with your next project!

--

--