慕课网学习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 , 不旋转,就回来了呀,,,
欢迎拍砖留言。。。