- The entire hamburger element is a link with a span, where the span has a before and after pseudo-element.
- The center bar is the actual span, whereas the top and bottom are the before and after pseudo-elements respectively.
- The top and bottom bars are positioned to the center and rotated to create the X.
- For some reason, the top bar rotates seamlessly while the bottom one is a bit jittery, even after specifying a bottom attribute.
- The bars need to be rotated from the center due to the default transform-origin. The positioning may be removed if we specify a different origin at the expense of lower browser support at the time of writing.
- The bottom bar rotation can be accomplished by adding a translateY(-10px) and top: 10px to force the transition to kick in and have it visually rotate from the bottom.
- See this CodePen for an example of it in action.
- The middle bar could be rotated with the bottom bar faded away, but the top bar rotation would need to be recalculated since the pseudo-elements are contained within the element and would be subsequently rotated as well.
- Each bar could also be redone as individual spans for greater flexibility, but at the cost of being more explicit in DOM.
UPDATE: I played around with another implementation that was a bit snappier. Here are some notes on what I discovered.
- Elijah's version is simple and uses CSS transitions which allows us to piggy back off existing CSS selectors and avoid having to add our own.
- Strunk's version uses animations which gives us keyframes, allowing for more flexibility in what the animation does. However, this comes at the cost of needing an explicit activation class for each animation if the animation should be gated behind some action/event such as a click. You can see this in Strunk's implementation because there is a flicker when the page is loaded.
- This post demonstrates how to do it without the animation flicker by using extra classes and toggling between them as necessary.
- The extra example below is a modified version of Strunk's implementation to use transforms instead of positioning. I felt that would degrade more gracefully in case a given browser didn't support animations. Also, it keeps it consistent with the transition implementation.