css 100daysofcode

Zoom up effect navigation menu

Feb 29, 2020

For one of the days of 100DaysOfCode challenge, I was messing around ideas around creating interesting hamburger menus. One interesting concept was to present the menu at the top of the page and minimise the page content.

For one of the days of 100DaysOfCode challenge, I was messing around ideas around creating interesting hamburger menus. One interesting concept was to present the menu at the top of the page and minimise the page content.

The result is as follows:

👉 Show me the code

The resulting code did not turn out to be as compact as I would of hoped. If you want to view the complete code, please see my GitHub here

👉 How it works

The below steps will describe how I got the basic hamburger navigation going. If you want to see the rest of the details - go through the above GitHub page.

The basic concept on how it hangs together:

  • The navigation will be placed in the center of the page (behind everything else). It will be moved up (and visible) when you click the hamburger menu
  • There are six div elements that represents a page
  • The page’s height will scale 75% when hamburger menu is clicked

Some CSS concepts I have used includes:

  • transitions
  • flex layout
  • animations

▶ Step 1 - HTML structure

The HTML consists of a nav element and a collection of div elements that represent the pages. The hamburger menu will be the last element, but its position is absolute and on top of other elements.

The nav will be positioned at the center of the screen and transition up when the hamburger icon is clicked.

    ...
	<nav class="pages-nav">
		<div class="pages-nav__item"><a class="link link--page" href="#page-home">Home</a></div>
		<div class="pages-nav__item"><a class="link link--page" href="#page-about">About Me</a></div>
		<div class="pages-nav__item"><a class="link link--page" href="#page-blog">Blog</a></div>
		<div class="pages-nav__item"><a class="link link--page" href="#page-contact">Contact</a></div>
		<div class="pages-nav__item"><a class="link link--page" href="#page-projects">Projects</a>
		</div>
		<div class="pages-nav__item"><a class="link link--page" href="#page-resume">Resume</a></div>

	</nav>
	<!-- /navigation-->
	<!-- pages stack -->
	<div class="pages-stack">
		<!-- page -->
		<div class="page" id="page-home">
			<header class="header cf">
				<h1 class="header__title">Howdy, #100DaysOfCode</h1>
				<p class="header__desc">Thanks for checking this out</p>
				<img class="poster animate" src="images/1.png" alt="img01" />

			</header>
		</div>
		<!-- /page -->
		<div class="page" id="page-docu">
			<header class="header cf">
				<h1 class="header__title">About me</h1>
				<p class="info">
					Lorem ipsum, dolor sit amet consectetur adipisicing elit. Similique ullam fugit tenetur nesciunt
					iusto quam expedita laborum fuga repudiandae molestias beatae aperiam porro, laudantium aliquid ad
					debitis est repellendus magnam!
				</p>
			</header>
			<img class="poster" src="images/2.png" alt="img06" />
		</div>
                ...
                ...
                ...
    </div>


	<button class="menu-button"><span>Menu</span></button>

    ...

▶ Step 2 - Basic page styling 🌟

When starting with CSS, the first thing I would do is to set basic styles. This includes CSS resets, fonts, body background colors, etc. This is in the resets.css.

You might want to use different styles to suit your needs.

    ...


/* Resets */

*,
*:after,
*:before {
	box-sizing: border-box;
}

body {
	font-family: 'Roboto', 'Lato', 'Segoe UI', Helvetica, Arial, sans-serif;
	margin: 0;
	color: #fff;
	background:#6e5773;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

a {
	text-decoration: none;
	color: #5c5edc;
	outline: none;
}

a:hover {
	color: #fff;
}


    ...

▶ Step 3 - CSS for the navigation

Now we will need to style the navigation to appear as a grid of 3 columns. This is done using with flex layouts and flex-wrap. To get the 3 column layout, each menu item is 33% width.

It is not required to use flex, you could use some other approach to layout your menu grid (eg CSS grid) - flex just seems quickest in this case.

The navigation menu initially will be positioned at the center of the page. When the user clicks on our hamburger menu, we will add the class pages-nav--open. This will animate it to the top of the page.

The styles are in the navigationstyles.css file.

    ...

.pages-nav {
	display: -webkit-flex;
	display: flex;
	-webkit-flex-wrap: wrap;
	flex-wrap: wrap;
	-webkit-justify-content: center;
	justify-content: center;
	-webkit-align-items: center;
	align-items: center;
	padding: 20px;
	text-align: center;
	background: #0e0f0f;
	position: absolute;
	top: 0;
	left: 0;
	color:white;
	width: 100%;
	height: 30vh;
	padding: 30px;
	pointer-events: none;
	opacity: 0;
	background: transparent;
	-webkit-transition: -webkit-transform 1.2s, opacity 1.2s;
	transition: transform 1.2s, opacity 1.2s;
	-webkit-transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1);
	transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1);
	-webkit-transform: translate3d(0, 150px, 0);
	transform: translate3d(0, 150px, 0);
}

.pages-nav--open {
	pointer-events: auto;
	opacity: 1;
	-webkit-transform: translate3d(0, 0, 0);
	transform: translate3d(0, 0, 0);
}

.pages-nav__item {
	width: 33%;
}

.pages-nav  {
	width: 100%;
	opacity: 0;
	-webkit-transition: -webkit-transform 1.2s, opacity 1.2s;
	transition: transform 1.2s, opacity 1.2s;
	-webkit-transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1);
	transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1);
	-webkit-transform: translate3d(0, 20px, 0);
	transform: translate3d(0, 20px, 0);
}

.pages-nav--open {
	opacity: 1;
	-webkit-transition-delay: 0.35s;
	transition-delay: 0.35s;
	-webkit-transform: translate3d(0, 0, 0);
	transform: translate3d(0, 0, 0);
}

    ...

▶ Step 4 - Styling the hamburger menu ⛄

The second last step is to style the hamburger menu - menu-button class. In our HTML, the button looks like this:

<button class="menu-button"><span>Menu</span></button>

To get the above HTML to have 3 solid horizontal lines, we have to use the ::before and ::after pseudo elements. These elements allow you to insert content before the button and after the button without need of extra HTML. Each element (::before, ::after, and span) will have width of 100% and height of 2px.

The ::before element will be at the top, so we need to use translate3d to move it vertically -10px.

As for the ::after element, we will set it vertically 10px

.menu-button {
	position: absolute;
	z-index: 1000;
	top: 30px;
	left: 30px;
	width: 30px;
	height: 24px;
	padding: 0;
	cursor: pointer;
	border: none;
	outline: none;
	background: transparent;
}

.menu-button::before,
.menu-button::after,
.menu-button span {
	background: white;
}

.menu-button::before,
.menu-button::after {
	content: '';
	position: absolute;
	top: 50%;
	left: 0;
	width: 100%;
	height: 2px;
	pointer-events: none;
	-webkit-transition: -webkit-transform 0.25s;
	transition: transform 0.25s;
	-webkit-transform-origin: 50% 50%;
	transform-origin: 50% 50%;
}

.menu-button span {
	position: absolute;
	left: 0;
	overflow: hidden;
	width: 100%;
	height: 2px;
	text-indent: 200%;
	-webkit-transition: opacity 0.25s;
	transition: opacity 0.25s;
}

.menu-button::before {
	-webkit-transform: translate3d(0, -10px, 0) scale3d(0.8, 1, 1);
	transform: translate3d(0, -10px, 0) scale3d(0.8, 1, 1);
}

.menu-button::after {
	-webkit-transform: translate3d(0, 10px, 0) scale3d(0.8, 1, 1);
	transform: translate3d(0, 10px, 0) scale3d(0.8, 1, 1);
}

.menu-button--open span {
	opacity: 0;
}

.menu-button--open::before {
	-webkit-transform: rotate3d(0, 0, 1, 45deg);
	transform: rotate3d(0, 0, 1, 45deg);
}

.menu-button--open::after {
	-webkit-transform: rotate3d(0, 0, 1, -45deg);
	transform: rotate3d(0, 0, 1, -45deg);
}

▶ Step 5 - Adding JavaScript to show the navigation 🔥

Now the last step to trigger the navigation when the hamburger button is clicked.

The main function that does this is the openMenu function. At the core of it, it will take the page div and transforms it using translate3d(0, 75%, {z-position}). The z-position depends on where the page sits on the stack.

For example, if its on the top, the position will be -200px, the next one on the stack will be 250px, etc

Additionally, the function will add menu-button--open class to the button to change it to a cross.

// opens the menu
function openMenu() {
	// toggle the menu button
	addClass(menuCtrl, 'menu-button--open')
	// stack gets the class "pages-stack--open" to add the transitions
	addClass(stack, 'pages-stack--open');
	// reveal the menu
	addClass(nav, 'pages-nav--open');
	// now set the page transforms
	var stackPagesIdxs = getStackPagesIdxs();
	for(var i = 0, len = stackPagesIdxs.length; i < len; ++i) {
		var page = pages[stackPagesIdxs[i]];
		page.style.transform = 'translate3d(0, 75%, ' + parseInt(-1 * 200 - 50*i) + 'px)';
	}
}

Hope this helps!

See Also

Creating a wave effect with CSS and SVG

Read more

Chrome DevTools tip - disabling the cache

Read more

Simple CSS reset code

Read more

Using CSS to highlight images not containing the 'alt' attribute

Read more