CSS3制作旋转导航
慕课网学习CSS3时,遇到个习题,觉得有必要总结学习下:CSS3制作旋转导航
慕课网习题地址:http://www.imooc.com/code/1883
示例及源码地址:http://codepen.io/airen/pen/icFba
老师的源代码内容太多,太复杂,也没有逻辑讲解,所以我就从头捡重点,一边写,一边分析,并且去掉了兼容性,这样看起来简单,所以下面的代码都是在谷歌浏览器才可以适用的,尤其是CSS3部分!先看目标效果图:
总结下要点:
1、特殊的字体样式
2、在鼠标移入时,
1)改变了背景色
2)出现了3D旋转
3)出现了下边框
3、这个情况
我觉得这里的核心应该是3D旋转,所以我的思路是:
1、在鼠标滑过时
1)实现单个 li 的3D旋转
2)实现单个 li 下边框
3)实现单个 li 背景颜色改变
2、考虑全局布局
3、考虑 Blog 下的特殊情况
那么好,思路有了,咱么来考虑这个单个 li 的3D旋转,不过在这之前先把静态页面写好(自己写哦,可以参考老师的嘛),,做个小的 li ,代码如下:
body:
<body> <ul class="nav-menu"> <li class="three-d-box"> <a href="#" class="cont">Home</a> <a href="#" class="front">Home</a> <a href="#" class="back">Home</a> </li> <li class="three-d-box"> <a href="#" class="cont">Html</a> <a href="#" class="front">Html</a> <a href="#" class="back">Html</a> </li> </ul> </body>
css:
* { padding: 0; margin: 0; } body { padding: 20px; } .nav-menu { background-color: #74adaa; width: 950px; height: 50px; margin: 0 auto; } .three-d-box { display: inline-block; position: relative; padding: 0 20px; list-style-type: none; } .three-d-box a { display: inline-block; width: 100%; height: 100%; text-align: center; line-height: 50px; font-size: 25px; color: white; text-decoration: none; background-color: #74adaa; } .three-d-box .cont { color: #74adaa; } .three-d-box .front, .three-d-box .back { position: absolute; left: 0; top: 0; border-right: 1px solid #94c0be; }
这个大家问题应该不大,看看老师源码应该能明白,这只是静态页面!
这里可能需要解释下,为什么要用3个 a 标签,
<a href="#" class="cont">Home</a> <a href="#" class="front">Home</a> <a href="#" class="back">Home</a>
因为,这里至少要有两个 a ,用来翻转实现 3D 旋转,一前一后(front , back),这个大家应该明白,所以有了两个 a 标签,但是静态页面上,我们只看到一个,结合旋转效果可以发现,这里的多个 a 标签肯定是在同一个位置的,而且是重合的,所以这里在静态页面上实现,就要给 a 标签 absolute 一下,然后 left & top 肯定为 0;但是这样的话,会出错,因为 li 的内容不一定,导航条可长可短,所以每个 li 的长度应该是自适应内容的,所以宽度不能设置,而 li 里面的 a 又是 absolute ,所以这里 li 与 li 之间就会有各种问题,我不知道你是什么问题,我是这样的,当然一开始也有其他样式的,十分奇怪,
所以最后就想了办法,再加一个内容一模一样的 a 标签,className 为 cont ,解决了上述问题,所以你也看到 front 和 back 都做了 absolute 定位和 cont 重合,但是 cont 没有 absolute ,为的是根据导航 li 的长度自适应宽度,好,静态页面完成,看旋转!
1、在鼠标滑过时
1)实现单个 li 的3D旋转
首先要搞明白,这个3D旋转是怎么实现的 ,把老师的源码旋转速度降到 3秒 之后,我看了好些遍,终于明白了,原理是这样:上图!
一开始是这样,也就是静态页面,.front & .back 通过定位实现重合:
放到坐标系就是这样,你看到的就是XY对应浏览器宽高这一面;
然后,要实现旋转效果需要把静态页面做成这样,当鼠标滑过时, 让 .front 和 .back 这个整体(也就是包裹他两的父元素)顺时针翻转90度(transform: rotateX(90deg)),这样,眼睛会看到 front 从正前方翻过去,. back 从下方翻上来 ; 滑出时,回到原位(即逆时针翻转90度) ;这样就实现了3d 旋转动画!!!听不懂?看图!
静态页面要做成这样:(请忽略此处O)
鼠标滑过,包裹他俩的父元素,顺时针翻转90度 ,翻到这样:(请忽略此处O)
能明白么?不明白好好想想~~~;或者看看下图:
3D 旋转的时候,其实是在旋转 .front 和 .back 的父元素 ( 即 li ):这个时候,li 的中心点应该 在L处,所以上述的变化,就是把这半个长方体,以 L 为原点,立体 顺时针 旋转 90 度。再想想~~
从这样:(请忽略此处O)
翻成这样:
所以,我们的主要任务就是要把静态页面做好,然后把 li transform:rotateX(90deg) 就好了,难点在静态页面!当然还有这个思路!
放在坐标轴里,我们要把静态页面改成这样就可以了:(请忽略此处O)
然而我们之前做的页面把 .front 和 .back 是放在这里的,如下图:
两张图一看,大家有思路了嘛?
说之前,先确定这里元素的原点:
注意,原点是居于元素X轴和Y轴的50%处,即O点,CSS变形进行的旋转、位移、缩放,扭曲等操作都是在原点O的基础上进行的;所以我们要在此基础上,完成上面两张图的转换,对,这是在 3d 动态
旋转 变换之前就要做好的;这里的O点既是 .front 和 .back的原点,也是 他们的父元素 li 的原点。
然后我们的思路就是:
先把 .back 绕X轴 逆时针旋转90度:transform: rotateX(-90deg)
然后.back 沿着自身的Z轴(因为之前已经翻转过一次了,所以现在 .back 的Z轴 在图中就是Y轴(我猜的!!!))下移25px , transform: rotateX(-90deg) translateZ(25px);就是这样:
最后再把 .front 向用户正对面移动 25px 就可以了,即 transform: rotateX(0deg) translateZ(25px);
此时看看 .front 和 .back 的父元素(li)的 原点 L,还在原位置 ,但是 .front 和 .back都移到位了,而 L 正好在这个半长方体中间,所以,把 li 沿着X轴顺时针翻转90度,就是我们要的 3D 旋转!
上述代码放一起就这些:
.three-d-box .front { height: 49px; } .three-d-box .front { -webkit-transform: rotateX(0deg) translateZ(25px); border-bottom: 1px solid #94c0be; } .three-d-box .back { -webkit-transform: rotateX(-90deg) translateZ(25px) ; /* 面对浏览器,translateX(5px)往右5px,translateY(5px)往下5px,translateZ(5px)正对用户5px */ } /* 准备翻转three-d-box 鼠标滑过时 */ .three-d-box:hover { -webkit-transform: rotateX(90deg); } /* 规定动画效果是3D和动画时间 */ .three-d-box { -webkit-transform-style: preserve-3d; -webkit-transition: all 4s ease; }
好了,核心3D旋转就说完了~~~接着看思路:
1、在鼠标滑过时
1)实现单个 li 的3D旋转(已实现)
2)实现单个 li 下边框(已实现)
3)实现单个 li 背景颜色改变(未实现)
那么好,我们来改变 li 的背景颜色,感觉这个很简单,摆代码之前发现这个小问题,我们的 li 中间有个外边距,效果图没有,那么好,我们把 父层 li 的margin 改下;
就加个margin-right: -7px; 其他的没动,这下就好了;
.three-d-box { display: inline-block; position: relative; padding: 0 20px; list-style-type: none; margin-right: -7px; }
改鼠标移入时背景颜色:
.three-d-box:hover .front, .three-d-box:hover .back { background-color: #51938f; background-image: -webkit-linear-gradient(45deg, #478480 25%, transparent 25%, transparent 75%, #478480 75%, #478480), linear-gradient(45deg, #478480 25%, transparent 25%, transparent 75%, #478480 75%, #478480); -webkit-background-size: 5px 5px; }
这个地方看不懂呢,可以三条样式一个个放,先放第一个,再放第二个,再放第三个,就很清楚了,其实就是,先加背景色,然后加背景图片,因为背景图片太大了,把背景图片尺寸变小;
至于默认的 HOME 的样式,就给 HOME li 加个className 就好了,比方加个 active , 样式里也加下,就变成这样:
.three-d-box:hover .front, .three-d-box:hover .back, .active .front, .active .back { background-color: #51938f; background-image: -webkit-linear-gradient(45deg, #478480 25%, transparent 25%, transparent 75%, #478480 75%, #478480), linear-gradient(45deg, #478480 25%, transparent 25%, transparent 75%, #478480 75%, #478480); -webkit-background-size: 5px 5px; }
className 也要加哦:
<li class="three-d-box active"> <a href="#" class="cont">Home</a> <a href="#" class="front">Home</a> <a href="#" class="back">Home</a> </li>
好了,这下进行第二步:
1、在鼠标滑过时(已实现)
1)实现单个 li 的3D旋转(已实现)
2)实现单个 li 下边框(已实现)
3)实现单个 li 背景颜色改变(已实现)
2、考虑全局布局(未实现)
把第一个做好的 li 复制几个就好了,注意去掉 active ,复制好了,可能会这样:
那么就把字体调小点就可以了,我是改成了 24px ,当然你也可以把 ul 改长点;
那么好,现在就进行第三步了:
1、在鼠标滑过时(已实现)
1)实现单个 li 的3D旋转(已实现)
2)实现单个 li 下边框(已实现)
3)实现单个 li 背景颜色改变(已实现)
2、考虑全局布局(已实现)
3、考虑 Blog 下的特殊情况(未实现)
当我们在 Blog 下放上 明细的代码时,其实也就是这样,
<li class="three-d-box"> <a href="#" class="cont">Blog</a> <a href="#" class="front">Blog</a> <a href="#" class="back">Blog</a> <ul class="dropMenu"> <li class="three-d-box"> <a href="#" class="cont">Html5</a> <a href="#" class="front">Html5</a> <a href="#" class="back">Html5</a> </li> <li class="three-d-box"> <a href="#" class="cont">Css3</a> <a href="#" class="front">Css3</a> <a href="#" class="back">Css3</a> </li> <li class="three-d-box"> <a href="#" class="cont">Javascript</a> <a href="#" class="front">Javascript</a> <a href="#" class="back">Javascript</a> </li> </ul> </li>然后调整下格式:
.dropMenu { position: absolute; left: 0; } .dropMenu .three-d-box { width: 100%; }
结果就发现这样了:
我们看效果图:下拉菜单 和 Blog 应该在两个元素内部,所以 Blog 的父元素 3D 翻转时,下拉菜单的父元素并没有翻转,而是 变长显示了出来,所以这个时候,应该是 横向导航里 li 里面有两个元
素,一个包裹了 Blog ,包括里面的三个 a, 一个包裹了下拉菜单 ul 及其内容。
原来的结构:
<li class="three-d-box"> <a href="#" class="cont">Blog</a> <a href="#" class="front">Blog</a> <a href="#" class="back">Blog</a> <ul class="dropMenu"> <li class="three-d-box"> <a href="#" class="cont">Html5</a> <a href="#" class="front">Html5</a> <a href="#" class="back">Html5</a> </li> <li class="three-d-box"> <a href="#" class="cont">Css3</a> <a href="#" class="front">Css3</a> <a href="#" class="back">Css3</a> </li> <li class="three-d-box"> <a href="#" class="cont">Javascript</a> <a href="#" class="front">Javascript</a> <a href="#" class="back">Javascript</a> </li> </ul> </li>
为了方便起见,现在我们给这个 li 改下结构,把 Blog 和 下拉菜单分别包裹在不同的元素内:
<li> <a href="#" class="three-d-box"> <span href="#" class="cont">Blog</span> <span href="#" class="front">Blog</span> <span href="#" class="back">Blog</span> </a> <ul class="dropMenu"> <li> <a href="#" class="three-d-box"> <span href="#" class="cont">Html5</span> <span href="#" class="front">Html5</span> <span href="#" class="back">Html5</span> </a> </li> <li> <a href="#" class="three-d-box"> <span href="#" class="cont">Css3</span> <span href="#" class="front">Css3</span> <span href="#" class="back">Css3</span> </a> </li> <li> <a href="#" class="three-d-box"> <span href="#" class="cont">Javascript</span> <span href="#" class="front">Javascript</span> <span href="#" class="back">Javascript</span> </a> </li> </ul> </li>
能明白么?现在咱们把所有代码和样式都改下:
<style> /* 基本样式 */ * { padding: 0; margin: 0; } body { padding: 20px; } .navMenu { background-color: #74adaa; width: 950px; height: 50px; margin: 0 auto; } .navMenu>li { display: inline-block; list-style-type: none; margin-right: -7px; } .navMenu li a { width: 100%; height: 100%; display: block; line-height: 50px; font-size: 20px; color: white; text-decoration: none; text-align: center; } .three-d-box { position: relative; } .three-d-box .cont { display: block; color: #74adaa; padding: 0 30px; height: 50px; } .three-d-box .front, .three-d-box .back { display: block; width: 100%; height: 100%; position: absolute; left: 0; top: 0; border-right: 1px solid #94c0be; background-color: #74adaa; } /* 3d旋转准备样式 */ .three-d-box .front { height: 49px; } .three-d-box .front { -webkit-transform: rotateX(0deg) translateZ(25px); border-bottom: 1px solid #94c0be; } .three-d-box .back { -webkit-transform: rotateX(-90deg) translateZ(25px) ; /* 面对浏览器,translateX(5px)往右5px,translateY(5px)往下5px,translateZ(5px)正对用户5px */ } /* 准备翻转three-d-box 鼠标滑过时 */ .three-d-box:hover, .three-d-box:focus { -webkit-transform: rotateX(90deg); } .three-d-box:hover .front, .three-d-box:hover .back, .active .front, .active .back { background-color: #51938f; background-image: -webkit-linear-gradient(45deg, #478480 25%, transparent 25%, transparent 75%, #478480 75%, #478480), linear-gradient(45deg, #478480 25%, transparent 25%, transparent 75%, #478480 75%, #478480); -webkit-background-size: 5px 5px; } /* 鼠标移出时 */ .three-d-box { -webkit-transform-style: preserve-3d; -webkit-transition: all 1s ease; } .dropMenu { position: absolute; top: 70px; background-color: #74adaa; } .dropMenu li a { width: 100%; } .dropMenu li { list-style-type: none; height: 0; -webkit-transform: rotateX(90deg); -webkit-transition: all 4s ease; } .navMenu>li:hover .dropMenu li { -webkit-transform: rotateX(0deg); height: 50px; } </style>
body:
<body> <ul class="navMenu"> <li> <a href="#" class="three-d-box active"> <span href="#" class="cont">Home</span> <span href="#" class="front">Home</span> <span href="#" class="back">Home</span> </a> </li> <li> <a href="#" class="three-d-box"> <span href="#" class="cont">Service</span> <span href="#" class="front">Service</span> <span href="#" class="back">Service</span> </a> </li> <li> <a href="#" class="three-d-box"> <span href="#" class="cont">Products</span> <span href="#" class="front">Products</span> <span href="#" class="back">Products</span> </a> </li> <li> <a href="#" class="three-d-box"> <span href="#" class="cont">About</span> <span href="#" class="front">About</span> <span href="#" class="back">About</span> </a> </li> <li> <a href="#" class="three-d-box"> <span href="#" class="cont">Contact</span> <span href="#" class="front">Contact</span> <span href="#" class="back">Contact</span> </a> </li> <li> <a href="#" class="three-d-box"> <span href="#" class="cont">Blog</span> <span href="#" class="front">Blog</span> <span href="#" class="back">Blog</span> </a> <ul class="dropMenu"> <li> <a href="#" class="three-d-box"> <span href="#" class="cont">Html5</span> <span href="#" class="front">Html5</span> <span href="#" class="back">Html5</span> </a> </li> <li> <a href="#" class="three-d-box"> <span href="#" class="cont">Css3</span> <span href="#" class="front">Css3</span> <span href="#" class="back">Css3</span> </a> </li> <li> <a href="#" class="three-d-box"> <span href="#" class="cont">Javascript</span> <span href="#" class="front">Javascript</span> <span href="#" class="back">Javascript</span> </a> </li> <li> <a href="#" class="three-d-box"> <span href="#" class="cont">Videogames</span> <span href="#" class="front">Videogamess</span> <span href="#" class="back">Videogamess</span> </a> </li> </ul> </li> <li> <a href="#" class="three-d-box"> <span href="#" class="cont">Shop On-Line</span> <span href="#" class="front">Shop On-Line</span> <span href="#" class="back">Shop On-Line</span> </a> </li> </ul> </body>
样式里最后几行就是处理 Blog 下的特殊情况的,太累了,不写了,自己看代码,不懂再问我,,,
原理就是:一开始,将 .dropMenu 下的 li 高度设为0且 顺时针旋转90度,这样用户就看不到了呀,鼠标滑过时,再将高度设为 50px , 不旋转,就回来了呀,,,
欢迎拍砖留言。。。
行文仓促,如有错误,欢迎批评指正~~~
转载请注明来源,文中所提文档可以在我的 Github 上下载~~~新博客现已迁移至 Github issues