解析:用 CSS3 和 JavaScript 制作径向动画菜单
原作者的解析(英文):http://creative-punch.net/2014/02/making-animated-radial-menu-css3-javascript/
本文非转载,为个人原创解析,转载请先联系博主,谢谢~
首先,看看html的结构:
<!DOCTYPE html> <head> <meta charset="UTF-8"> <title>kissy | TaoBaoUED</title> <link rel="stylesheet" href="style.css" type="text/css" media="all"> <script src="jquery-1.3.2.js"></script> <script src="ext.js"></script> </head> <!-- Demo by http://creative-punch.net --> <!-- Modified by xzh - 20140701 --> <nav class="circular-menu"> <div class="circle"> <a href="">●</a> <a href="">■</a> <a href="">◆</a> <a href="">♦</a> <a href="">★</a> <a href="">卍</a> <a href="">卐</a> <a href="">♥</a> </div> <a href="#" class="menu-button fa fa-bars fa-2x">A</a> </nav> <h1 class="author">Demo by <a href="" target="">Creative Punch</h1></span></span>
——Css完整代码请参见文章最后。
——Js完整代码请参见文章最后。
然后,看下页面:
图1-1
一开始,只有两个是“可见”的元素,一个的类是.menu-button,另一个的类是.circular-menu,因为按钮的position属性要设置在absolute,所以它的父元素外框.menu-button设置position为relative,现在分析.menu-button的属性:
1、 top和left的值为calc(50% - 30px),50%很好理解,30px是怎么来的呢?注意到,height和left都为40px,而绝对位置的top和left属性分别表示元素左上角相对上方和左方的距离,如图1-2,为了让元素的中心点居中,距离应该减去元素的长宽的一半,但是它的长宽都是20px,为什么是减30px呢?原因在于它的padding属性为10px,相当于给它的长宽分别增加了20px。
得(30px = 40px/2 +10px)
图1-2
2、 line-height和height都为40px,使得文字能够垂直居中。
3、 border-radius:50%,圆形。
4、 display:block,删掉好像没什么影响。
再看被“隐藏”了的.circle,它里面装了几个<a>标签,它的透明度为0,还设置了CSS3的动画——transform和transition。其中,transition: all 0.4s ease-out为一打开网页时看到几个白点突然藏到大按钮背后的效果就是它干的,解释一下意思,所有属性在0.4s内渐渐消失,其实完整的它是有4个参数的。单击按钮后,为div切换一个类.open,
.open.circle { opacity: 1; -webkit-transform: scale(1); -moz-transform: scale(1); transform: scale(1); }渐显/渐隐,从0倍放大到1倍,变成图1-3的样子。
图1-3
现在,让我们去看看js代码,document加载之后为各个小<a>添加了top和left属性,为了更加容易被看懂,我稍微修改了一下原demo代码,如下:
items[i].style.left = (50 - 35*Math.cos(2*Math.PI*i/len)).toFixed(4) + "%"; items[i].style.top = (50 + 35*Math.sin(2*Math.PI*i/len)).toFixed(4) + "%";35后面的一块意思是,从一个点开始,经历2π,期间2π平分成多少个点取决于<a>的个数,例如我们例子,<a>有8个,从x=0开始,正向取2π,将2π平分成8段,依次取8个点,他们的y值如图1-4所示,我们可以看到,8个点上的y值变化不正符合我们的圆圈位置变化规律么?35的意思是,让top和left最多取85%,最小取15%。
图1-4
举一反三:
1、 上面说了,2π被分成几段取决于<a>的个数,试着增删几个<a>看看吧。
2、 上面的代码是从0开始正向取2π的,试着改一下吧,注意始终不变的东西是2π*i/len,你可以作加减一些东西,或者为它添加负号之类的改动,特别地,加减一些东西的时候,如加上π/5,因为影响的是第一个点的取值,间接影响其他点的值,你会发现,所有<a>组成的圆圈好像被人顺/逆时针轻轻拧了一下,具体效果是怎样的,你可以尝试弄出来看一下。
现在回过来看样式,.circle a中需要注意的的是margin-left和margin-top,还记得我们刚刚说的.menu-button中的left和top属性吗?对,两者都是差不多的意思,让我们回过来看图1-3,图中虚线框位置为我们没有设置margin-left和margin-top时的位置,同样地,我们取margin-left和margin-top为<a>元素的长宽的一半,记得负号。
触类旁通:
都说了跟前面的.menu-button差不多,那我们就不设置margin-top和margin-left了,那怎么改?
答:(字体颜色为白色,全选文字可见-->在js里,items[i].style.left和items[i].style.top都减20px即可<--)
忘了说,注意如果还有border的时候,同样需要减去border的值。
最后,谢谢你认真看完了,不足之处,欢迎指出!
完整js和css代码如下:
$(document).ready(function(){ // Demo by http://creative-punch.net // Modified by xzh - 20140701 var items = document.querySelectorAll('.circle a'); for(var i = 0, len = items.length; i < len; i++) { items[i].style.left = (50 - 35*Math.cos(2*Math.PI*i/len)).toFixed(4) + "%"; items[i].style.top = (50 + 35*Math.sin(2*Math.PI*i/len)).toFixed(4) + "%"; console.log(items[i].style.left+" "+items[i].style.top); } document.querySelector('.menu-button').onclick = function(e) { e.preventDefault(); document.querySelector('.circle').classList.toggle('open'); } });
/* Demo by http://creative-punch.net */ /* Modified by xzh - 20140701 */ body { background: #39D; } .circular-menu { width: 250px; height: 250px; margin: 0 auto; position: relative; } .circle { width: 250px; height: 250px; opacity: 0; -webkit-transform: scale(0); -moz-transform: scale(0); transform: scale(0); -webkit-transition: all 0.4s ease-out; -moz-transition: all 0.4s ease-out; transition: all 0.4s ease-out; } .open.circle { opacity: 1; -webkit-transform: scale(1); -moz-transform: scale(1); transform: scale(1); } .circle a { text-decoration: none; color: white; display: block; height: 40px; width: 40px; line-height: 40px; margin-left: -20px; margin-top: -20px; position: absolute; text-align: center; } .circle a:hover { color: #eef; } .menu-button { position: absolute; top: calc(50% - 30px); left: calc(50% - 30px); text-decoration: none; text-align: center; color: #444; border-radius: 50%; display: block; height: 40px; width: 40px; line-height: 40px; padding: 10px; background: #dde; } .menu-button:hover { background-color: #eef; } /* Author stuff */ h1.author { text-align:center; color: white; font-family: Helvetica, Arial, sans-serif; font-weight: 300; } h1.author a { color: #348; text-decoration:none; } h1.author a:hover { color: #ddd; }