A tutorial on how to create a off-canvas icon navigation with an animated border effect. The menu effect is inspired by CreativeDash's bounce menu for mobile apps.
The other day I saw a really nice concept of a menu on the UI8 site. CreativeDash implemented that gorgeous concept and I instantly had some ideas for more effects involving border transitions but also with the desktop in mind. So today I want to show you how to create something like that and provide some more inspirational examples.
In this tutorial we will be going through demo 2 where the menu icon is in the top left corner and the border is thickest on the left side.
Please note that we’ll be using transitions and animation on pseudo-elements which won’t work in some browsers (e.g. Safari and Mobile Safari).
So, let’s get started!
The Markup
The HTML structure for our menu will consist of anav
element that will contain a trigger anchor and an unordered list with the menu items which will consist of icons:
1
2
3
4
5
6
7
8
9
10
| < nav id = "bt-menu" class = "bt-menu" > < a href = "#" class = "bt-menu-trigger" >< span >Menu</ span ></ a > < ul > < li >< a href = "#" class = "bt-icon icon-zoom" >Zoom</ a ></ li > < li >< a href = "#" class = "bt-icon icon-refresh" >Refresh</ a ></ li > < li >< a href = "#" class = "bt-icon icon-lock" >Lock</ a ></ li > < li >< a href = "#" class = "bt-icon icon-speaker" >Sound</ a ></ li > < li >< a href = "#" class = "bt-icon icon-star" >Favorite</ a ></ li > </ ul > </ nav > |
The CSS
Note that the CSS will not contain any vendor prefixes, but you will find them in the files.Let’s use the border-box box-sizing:
1
2
3
4
5
| *, *:after, *::before { box-sizing : border-box; } |
1
2
3
4
5
6
7
| body { background : #04a466 ; } .container { padding : 80px ; } |
The main menu element will have position fixed so that, no matter where we are in the page, the border is always around the viewport. We set an initial border style which we will transition to a bigger border. Setting the initial height to 0 will make sure that the menu does not cover anything initially. The “backward” or closing height transition will have a delay of 0.3s:
1
2
3
4
5
6
7
8
9
10
11
12
| .bt-menu { position : fixed ; top : 0 ; left : 0 ; width : 100% ; height : 0 ; border-width : 0px ; border-style : solid ; border-color : #333 ; background-color : rgba( 0 , 0 , 0 , 0 ); transition : border-width 0.3 s, background-color 0.3 s, height 0 s 0.3 s; } |
1
2
3
4
5
6
| .bt-menu.bt-menu-open { height : 100% ; border-width : 30px 30px 30px 90px ; background-color : rgba( 0 , 0 , 0 , 0.3 ); transition : border-width 0.3 s, background-color 0.3 s; } |
1
2
3
4
| .bt-overlay { position : absolute ; width : 100% ; } |
1
2
3
| .bt-menu-open .bt-overlay { height : 100% ; } |
1
2
3
4
5
6
7
8
9
| .bt-menu-trigger { position : fixed ; top : 15px ; left : 20px ; display : block ; width : 50px ; height : 50px ; cursor : pointer ; } |
1
2
3
4
5
6
7
8
9
10
11
12
13
| .bt-menu-trigger span { position : absolute ; top : 50% ; left : 0 ; display : block ; width : 100% ; height : 4px ; margin-top : -2px ; background-color : #fff ; font-size : 0px ; user-select : none ; transition : background-color 0.3 s; } |
1
2
3
| .bt-menu-open .bt-menu-trigger span { background-color : transparent ; } |
1
2
3
4
5
6
7
8
9
10
| .bt-menu-trigger span:before, .bt-menu-trigger span:after { position : absolute ; left : 0 ; width : 100% ; height : 100% ; background : #fff ; content : '' ; transition : transform 0.3 s; } |
For positioning them correctly, we’ll use translateY:
1
2
3
4
5
6
7
| .bt-menu-trigger span:before { transform : translateY ( -250% ); } .bt-menu-trigger span:after { transform : translateY ( 250% ); } |
1
2
3
4
5
6
7
| .bt-menu-open .bt-menu-trigger span:before { transform : translateY ( 0 ) rotate ( 45 deg); } .bt-menu-open .bt-menu-trigger span:after { transform : translateY ( 0 ) rotate ( -45 deg); } |
1
2
3
4
5
6
7
8
9
10
| .bt-menu ul { position : fixed ; top : 75px ; left : 0 ; margin : 0 ; padding : 0 ; width : 90px ; list-style : none ; backface-visibility : hidden ; } |
display: block
and give them full width:
1
2
3
4
5
6
| .bt-menu ul li, .bt-menu ul li a { display : block ; width : 100% ; text-align : center ; } |
1
2
3
4
5
6
| .bt-menu ul li { padding : 16px 0 ; opacity : 0 ; visibility : hidden ; transition : transform 0.3 s, opacity 0.2 s, visibility 0 s 0.3 s; } |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| .bt-menu ul li:first-child { transform : translate 3 d( -100% , 200% , 0 ); } .bt-menu ul li:nth-child( 2 ) { transform : translate 3 d( -100% , 100% , 0 ); } .bt-menu ul li:nth-child( 3 ) { transform : translate 3 d( -100% , 0 , 0 ); } .bt-menu ul li:nth-child( 4 ) { transform : translate 3 d( -100% , -100% , 0 ); } .bt-menu ul li:nth-child( 5 ) { transform : translate 3 d( -100% , -200% , 0 ); } |
1
2
3
4
5
6
| .bt-menu.bt-menu-open ul li { visibility : visible ; opacity : 1 ; transition : transform 0.3 s, opacity 0.3 s; transform : translate 3 d( 0 , 0 , 0 ); } |
By setting the font size of the anchor to 0 and make it transparent, we’ll hide the text:
1
2
3
4
5
6
7
| .bt-menu ul li a { display : block ; outline : none ; color : transparent ; text-decoration : none ; font-size : 0px ; } |
1
2
3
4
5
| .bt-menu ul li a:before { color : #04a466 ; font-size : 48px ; transition : color 0.2 s; } |
1
2
3
4
| .bt-menu ul li a:hover:before, .bt-menu ul li a:focus:before { color : #fff ; } |
1
2
3
4
5
| @media screen and ( max-height : 31.125em ) { .bt-menu ul li a:before { font-size : 32px ; } } |
The JavaScript
Our script is pretty straightforward; when we click on the trigger anchor, we toggle the class bt-menu-open and bt-menu-close on thenav
element. (Adding
the closing class is only needed if you are using animation for the
trigger icon effect, just like we do in demo 1. This will allow us to
only play the backward animation, when we close the menu).When we click on the overlay, we will close the menu. We’ll also add some touch support:
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
| ( function () { // http://stackoverflow.com/a/11381730/989439 function mobilecheck() { var check = false ; ( function (a){ if (/(android|ipad|playbook|silk|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge
|maemo|midp|mmp|netfront|opera m(ob| in )i|palm(
os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows
(ce|phone)|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a
wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r
|s
)|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob| do (c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1
u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp(
i|ip)|hs\-c|ht(c(\-|
|_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac(
|\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt(
|\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg(
g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de| do |t(\-|
|o|v)|zz)|mt(50|p1|v
)|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v
)|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-|
)|webc|whit|wi(g
|nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check
= true })(navigator.userAgent||navigator.vendor||window.opera); return check; } function init() { var menu = document.getElementById( 'bt-menu' ), trigger = menu.querySelector( 'a.bt-menu-trigger' ), // event type (if mobile, use touch events) eventtype = mobilecheck() ? 'touchstart' : 'click' , resetMenu = function () { classie.remove( menu, 'bt-menu-open' ); classie.add( menu, 'bt-menu-close' ); }, closeClickFn = function ( ev ) { resetMenu(); overlay.removeEventListener( eventtype, closeClickFn ); }; var overlay = document.createElement( 'div' ); overlay.className = 'bt-overlay' ; menu.appendChild( wrapper ); trigger.addEventListener( eventtype, function ( ev ) { ev.stopPropagation(); ev.preventDefault(); if ( classie.has( menu, 'bt-menu-open' ) ) { resetMenu(); } else { classie.remove( menu, 'bt-menu-close' ); classie.add( menu, 'bt-menu-open' ); overlay.addEventListener( eventtype, closeClickFn ); } }); } init(); })(); |
Make sure to check out the other demos. The last one is a concept for a fullscreen video player.
by Mary Lou (Manoela Ilic)
souurce: http://tympanus.net/codrops/2013/09/30/animated-border-menus/?utm_source=feedburner&utm_medium=feed&utm_campaign=Feed%3A+tympanus+%28Codrops%29
Find this project on Github
0 komentar:
Post a Comment