How to Build a CSS3 Sliding Menu
There are various solutions throughout the web, but I struggled to find one matching my requirements:
- It must use clean semantic HTML5 with no superfluous tags.
- It must not rely on JavaScript.
- It must not require additional graphics.
- It must work on mobile and tablet touch devices.
- It must degrade gracefully in older browsers (IE7+) or when specific CSS3 properties are not supported.
- It must look great!
Open your favorite editor and let’s get coding…
The HTML
No surprises here — we have an HTML5 document, the IE shim, a link to our stylesheet, a nav
element for the menu, and an article
for our body text:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>Revealing CSS3 Menu</title> <!--[if lt IE 9]> <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link rel="stylesheet" media="all" href="styles.css" /> </head> <body> <!-- menu --> <nav> <ul> <li><a href="http://www.sitepoint.com/">SitePoint.com</a></li> <li><a href="http://www.sitepoint.com/css3-sliding-menu/">Revealing CSS3 Menu</a></li> </ul> </nav> <!-- main article --> <article> <h1>Revealing CSS3 Menu</h1> <p>body text</p> </article> </body> </html> |
CSS: Article Styles
The article is a little unusual because we want to apply a 3D effect when the menu slides into place. It’s given a fixed position so it matches the dimensions of the body:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
article { position: fixed; width: 70%; left: 0; top: 0; right: 0; bottom: 0; padding: 30px 15%; background-color: #fff; overflow: auto; z-index: 0; -webkit-transform-origin: 0 50%; -moz-transform-origin: 0 50%; -ms-transform-origin: 0 50%; -o-transform-origin: 0 50%; transform-origin: 0 50%; } |
We’ve also defined the transform-origin to the middle of the left-hand edge. Even though the transform doesn’t occur until hover, Chrome becomes upset if we attempt to set the origin in the :hover styles.
We also require a shadow overlay when the page rotates — the right-hand edge will be darker, so we can do that with a gradient applied to a pseudo element attached to the article:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
article:after { position: absolute; content: ' '; left: 100%; top: 0; right: 0; bottom: 0; background-image: -webkit-linear-gradient(right, rgba(0,0,0,0.2) 0%, transparent 100%); background-image: -moz-linear-gradient(right, rgba(0,0,0,0.2) 0%, transparent 100%); background-image: -ms-linear-gradient(right, rgba(0,0,0,0.2) 0%, transparent 100%); background-image: -o-linear-gradient(right, rgba(0,0,0,0.2) 0%, transparent 100%); background-image: linear-gradient(right, rgba(0,0,0,0.2) 0%, transparent 100%); pointer-events: none; } |
The element is fixed as a zero-width block on the right-hand edge of the screen which is resized when the menu slides out. Note the pointer-events
property
CSS: Navigation Styles
The main navigation block is fixed to the left of the screen. The content has a width of 16em, so we move it off to the left with -16em. However, the 50px right border will be shown. We can also apply a pseudo element to create a CSS triangle:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
nav { position: fixed; left: -16em; top: 0; bottom: 0; background-color: #654; border-right: 50px solid #765; box-shadow: 4px 0 5px rgba(0,0,0,0.2); z-index: 1; cursor: pointer; } nav:after { position: absolute; content: ' '; width: 0; height: 0; right: -70px; top: 50%; border-width: 15px 10px; border-style: solid; border-color: transparent transparent transparent #765; } |
The menu styling is nothing unusual. The outer ul
is given a width of 14em and padding of 1em which determines the 16em total:
1
2
3
4
5
6
7
|
nav ul { width: 14em; list-style-type: none; margin: 0; padding: 1em; } |
CSS: The Animation
This is where it gets interesting. First, let’s apply transitions to the article
, nav
and menu items:
1
2
3
4
5
6
7
8
|
article, article:after, nav, nav * { -webkit-transition: all 600ms ease; -moz-transition: all 600ms ease; -ms-transition: all 600ms ease; -o-transition: all 600ms ease; transition: all 600ms ease; } |
Moving the menu into place is simple — we move it from -16em to 0 when the user hovers over the element:
1
2
3
4
|
nav:hover { left: 0; } |
The page effect is applied to any article sibling following the hovered nav
. The translateX moves it by 16em to the right to make room for the menu. The perspective and rotateY apply a 3D transformation:
1
2
3
4
5
6
7
8
|
nav:hover ~ article { -webkit-transform: translateX(16em) perspective(600px) rotateY(10deg); -moz-transform: translateX(16em) perspective(600px) rotateY(10deg); -ms-transform: translateX(16em) perspective(600px) rotateY(10deg); -o-transform: translateX(16em) perspective(600px) rotateY(10deg); transform: translateX(16em) perspective(600px) rotateY(10deg); } |
Finally, the shadow gradient applied to the article’s pseudo element has the left hand edge moved from 100% to 60%. In other words, it grows to 40% of the page width:
1
2
3
4
|
nav:hover ~ article:after { left: 60%; } |
An that’s it. Even with vendor prefixes, the return on coding investment is far higher than you’d expect.
The page works in most browsers. Firefox is perfect, although:
- The page shadow appears instantly rather than expanding over time in Chrome and Safari (webkit does not support pseudo element animation).
- Opera does not support the 3D page transforms — the menu slides out over the page.
- IE does not support transform so the menu covers the page. Few of the effects are shown in IE7 and 8, but the menu can be used.
- Mobile browsers such as Android, Dolphin and Firefox Mobile work well although performance might be an issue on slower devices.
Source Link: http://www.sitepoint.com/css3-sliding-menu/