Skip to content

Instantly share code, notes, and snippets.

@tillsanders
Last active March 21, 2016 12:42
Show Gist options
  • Save tillsanders/10237546 to your computer and use it in GitHub Desktop.
Save tillsanders/10237546 to your computer and use it in GitHub Desktop.
Animation for a mobile menu toggle. Three horizontal lines transform into a cross and back again.

Animate the transformation of a mobile menu toggle into a cross

Animation Transition for a mobile menu toggle. Three horizontal lines transform into a cross and back again. The top and bottom lines fall into the center, transforming into one line. The line(s) rotate clockwise, spawning a line at 45deg and stop at 135 deg, forming a cross. Demo: http://jsfiddle.net/SYYr5/84/

Annotations:

  • the animation uses four additional elements inside the a tag. This is not semantic, but we can at least use elements without a semantic meaning, like div and span
  • using a div as a second container, we are able to apply a padding to our a tag
  • We may need to use vendor prefixes :/

The HTML-Snippet:

<a id="toggle-menu">
	<div>
		<span class="top"></span>
		<span class="middle"></span>
		<span class="bottom"></span>
	</div>
</a>

The SCSS-Snippet:

#toggle-menu {
	display: block;
	width: 15px;
	height: 15px;
	padding: 20px;
	cursor: pointer;
	div {
		width: 15px;
		height: 15px;
		position: relative;
	}
	span {
		display: block;
		width: 15px;
		height: 3px;
		background: black;
		position: absolute;
		transition: transform 0.5s ease-in-out, top 0.25s ease-in-out 0.5s, opacity 0.25s ease-in-out 0.5s;
		transform-origin: center;
		&.top {
			top: 0px;
		}
		&.middle {
			top: 6px;
		}
		&.bottom {
			top: 12px;
		}
	}
	&.menu-is-active {
		span {
			transition: transform 0.5s ease-in-out 0.3s, top 0.25s ease-in-out, opacity 0.25s ease-in-out;
			&.top {
				top: 6px;
				transform: rotate(135deg);
			}
			&.middle {
				opacity: 0;
				transform: rotate(135deg);
			}
			&.bottom {
				top: 6px;
				transform: rotate(225deg);
			}
		}
	}
}

When using my jQuery-Plugin adjust-at, the following javascript will provide interactivity:

$(document).ready(function() {
	var nav = $('header nav');
	$('#toggle-menu').adjustAt({
		below850: function(element) {
			nav.hide();
			element.click(function() {
				element.toggleClass('menu-is-active');
				nav.slideToggle(800);
			});
		},
		above850: function(element) {
			nav.show();
			element.off('click');
		}
	});
});
@zeusdeux
Copy link

Why use animations when you can just use transforms?
Example

@tillsanders
Copy link
Author

Because I needed more than two states for my desired animation: http://jsfiddle.net/SYYr5/3/

For example: it wouldn't look that smooth, if I skipped the 50%-step, here:

@keyframes inTop {
    0% {
        top: 0;
    }
    50% {
        top: 6px;
        -webkit-transform: rotate(0deg);
    }
    100% {
        top: 6px;
        -webkit-transform: rotate(135deg);
    }
}

@pjldesign
Copy link

how do we prevent from firing each time browser refreshes? relies on .hidden class in markup...

@tillsanders
Copy link
Author

@pjldesign: Not quite sure, what you mean... But I've written a jQuery-Plugin to fire javascript functions only once for certain breakpoints. Maybe this is of help. Otherwise, please send me a mail, to discuss this, as Gists don't have notifications.

@tillsanders
Copy link
Author

@zeusdeux: Turned out you were right, after all. This is possible with css transitions. Missing the 50% step, your solution is incomplete, but it is easily enhanced with transition-delay to include the 50% step. I updated the gist to use transitions now – looks good.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment