过渡
transition:提供了一种在更改CSS属性时控制动画速度的方法,其可以让属性变化成为一个持续一段时间的过程,而不是立即生效的,它是一个简写属性
-
API介绍
transition-property 指定要产生过渡效果的属性,有些属性不能产生过渡效果,比如display
transition-duration 指定过渡持续的时间,必须带单位
transition-timing-function 指定过渡运动的形式
transition-delay 指定过渡效果开始之前的延迟时间 -
注意点
2.1 当属性值对应不一致的时候:
transition-property: width height color;
transition-duration: 1s 2s;
transition-timing-function: ease linear;
transition-delay: 1s 2s;
时间列表会重复,并将多余的截去,而运动形式则采用默认值ease,(1s 2s)重复成(1s 2s 1s 2s)将1s给color,将多余的2s截去,color的运动形式直接采用默认值ease
2.2 0也一定要带单位
transition-duration: 0 和 transition-duration: 0s 区别很大 -
过渡事件
当过渡效果完成时触发一个事件,在符合标准的浏览器下,这个事件是transitionend,在webkit内核下是webkitTransitionEnd
每一个拥有过渡的属性在其完成过渡时都会触发一次transitionend事件
在transitionend完成前设置display:none,事件不会触发 -
过渡的天坑
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
*{
margin: 0;
padding: 0;
}
html{
height: 100%;
}
body{
height: 60%;
width: 60%;
margin: 100px auto 0;
border: 1px solid;
}
#test{
width: 200px;
height: 200px;
border-radius: 50%;
background: pink;
text-align: center;
font: 30px/200px "微软雅黑";
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
transition-property: width;
transition-duration: 2s;
transition-timing-function: linear;
}
body:hover #test{
transition-property: height;
width: 100px;
height: 100px;
}
/* 这样写鼠标悬浮是高度先变,鼠标移出宽度在变 */
/* 要注意的是:此时,当鼠标移入框内时,变化的并不是width,而是height;
当鼠标移出框内时,width进行变化。解释:这跟浏览器的渲染机制有关系,
浏览器真正在页面上渲染动画过程中是需要去画布局的,
这个过程比解析代码来得慢,导致有一个时间差。
浏览器第一次解析时的确是移入框内width进行变化。
但是,CSS代码解析的速度极快,当鼠标移入框内时,
触发body:hover #test中的代码,发现有transition-property: height;
因此就立即把内存中需要变化的width改为height;在这一过程中,
浏览器根本来不及进行渲染工作,因此,当渲染发生时,
浏览器去内存中寻找到底是哪个属性要进行过渡,此时,
width已经被改为height,所以渲染的时候,就直接将更改后的height进行过渡。
然后,当鼠标移出框外的一瞬间,浏览器发现有transition-property: width;
然后就立即把height改为width,这段时间内浏览器仍然由于时间太短而无法进行渲染工作,
因此移出时是width进行过渡
*/
</style>
</head>
<body>
<div id="test">
123
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
html {
height: 100%;
}
body {
width: 60%;
height: 60%;
border: 1px solid;
margin: 100px auto 0;
}
#test {
width: 100px;
height: 100px;
background: pink;
text-align: center;
position: absolute;
left: 0;
right: 0;
bottom: 0;
top: 0;
margin: auto;
/*------------以上代码用于居中、边框等--------------*/
transition-property: width;
transition-duration: 2s;
transition-timing-function: linear;
}
</style>
</head>
<body>
<div id="test">
</div>
</body>
<script type="text/javascript">
//transition在元素首次渲染还没有结束的情况下是不会触发的
window.onload = function() {
var test = document.querySelector("#test");
// 这样也没有渲染效果,因为又变成了100px,100px到100px没有过渡效果
test.style.width = "300px";
test.style.width = "100px";
//
/*
这样也属于首次渲染,不会触发过渡效果
var test = document.createElement("div");
test.id = "test";
document.documentElement.appendChhild(test);
//这里加个2s定时器就可以
test.style.width = "300px"
*/
}
</script>
</html>
- 过渡的简写属性
CSS过渡由简写属性定义是最好的方式,可以避免属性值列表长度不一,节省调试时间,但要注意,在transition属性中,各个值的书写顺序是很重要的,第一个解析成时间赋给transition-duration,第二个解析成时间的值会赋值给transition-delay延迟
2D变换
transform属性允许你修改CSS视觉格式模型的坐标空间
transform属性,只对block级元素生效
-
旋转
transform: rotate(角度) -
平移
transform: translate(x轴偏移,Y轴偏移) 一个参数时也是X轴偏移
translateX(偏移量) translateY(偏移量) -
倾斜
skew(角度) 单值仅对X有效 -
缩放
scale(数字) 大于1放大 小于1缩小 单值X,Y均有效
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
html {
height: 100%;
overflow: hidden;
}
body {
height: 60%;
width: 60%;
margin: 100px auto 0;
border: 1px solid;
overflow: hidden;
}
#test {
width: 200px;
height: 200px;
border-radius: 50%;
background: pink;
text-align: center;
font: 30px/200px "微软雅黑";
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
transition: transform 1s linear;
/* 基点变换 基于左上角的位置变换 */
/* 可以写像素,也可以写百分比 */
/* 对平移不会造成影响 */
/* transform-origin: left top; */
}
body:hover #test {
transform: rotate(360deg);
/* transform: translateX(100px); */
/* transform: skew(45deg); */
/* transform: scale(1.5); */
}
</style>
</head>
<body>
<div id="test">
123
</div>
</body>
</html>
-
基点的变换
transform-origin: left top; //基于左上角进行变换
10px 10px; //基于(10px 10px)的位置进行变换
10% 10%; //基于自身(10% 10%)的位置进行变换 -
2D变换组合
变换的本质是矩阵的计算,对应的变换就是乘以对应变换的矩阵
transform: rotate(45deg) translateX(100px)
transform: translateX(100px) rotate(45deg)
变换组合的计算方式是从右往左进行计算,第一个是先乘以X轴平移的矩阵,再乘以旋转的矩阵,第二个是先乘以旋转的矩阵,再乘以X轴平移的矩阵
二者的效果不同,因为矩阵乘法不满足交换律
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
html {
height: 100%;
overflow: hidden;
}
body {
height: 60%;
width: 60%;
margin: 100px auto 0;
border: 1px solid;
overflow: hidden;
}
#test {
width: 200px;
height: 200px;
border-radius: 50%;
background: pink;
text-align: center;
font: 30px/200px "微软雅黑";
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
transition: 1s;
}
body:hover #test {
/* 变换组合都是从右往左进行计算的 */
/* 变换的本质是矩阵的计算,对应的变换就是乘以对应变换矩阵 */
transform: translateX(200px) rotate(360deg);
/* 两者变换效果,大不同,因为矩阵乘法不满足交换律 */
/* transform: rotate(360deg) translateX(200px); */
}
</style>
</head>
<body>
<div id="test">
123
</div>
</body>
</html>
综合应用
时钟
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
#wrap {
/* 钟盘居中,没什么好说的 */
position: absolute;
left: 50%;
top: 50%;
margin-top: -100px;
margin-left: -100px;
width: 200px;
height: 200px;
border: 1px solid black;
border-radius: 50%;
}
#wrap>ul {
list-style: none;
}
#wrap>ul>li {
/* 移动到12点的位置 */
position: absolute;
top: 0;
left: 99px;
width: 2px;
height: 10px;
background: #000000;
/* 旋转的基点调整为钟盘的圆心 */
transform-origin: center 100px;
}
#wrap>ul>li:nth-child(5n+1) {
/* 长针怼出来 */
height: 15px;
}
#wrap>.hour {
/* left:100-width/2 */
/* top:100-height */
position: absolute;
left: 97px;
top: 70px;
width: 6px;
height: 30px;
background: black;
/* 基点为自己的`尾巴` */
transform-origin: center bottom;
}
#wrap>.minute {
position: absolute;
left: 98px;
top: 50px;
width: 4px;
height: 50px;
background: gray;
transform-origin: center bottom;
}
#wrap>.second {
position: absolute;
left: 99px;
top: 30px;
width: 2px;
height: 70px;
background: red;
transform-origin: center bottom;
}
#wrap>.icon {
/* left:100-width/2 */
/* top:100-height/2 */
position: absolute;
left: 90px;
top: 90px;
width: 20px;
height: 20px;
background: pink;
border-radius: 50%;
}
</style>
</head>
<body>
<div id="wrap">
<ul>
</ul>
<div class="hour">
</div>
<div class="minute">
</div>
<div class="second">
</div>
<div class="icon">
</div>
</div>
</body>
<script type="text/javascript">
// 获取相关操作节点
var hourNode = document.querySelector("#wrap>.hour");
var minuteNode = document.querySelector("#wrap>.minute");
var secondNode = document.querySelector("#wrap>.second");
var ulNode = document.querySelector("#wrap>ul");
//创建一个style节点
var styleNode = document.createElement("style");
var liHTML = "";
var styleHTML = "";
//往ul里面塞60个li,并添加旋转,每次增加旋转6度,转出一个表的刻度
for (let i = 0; i < 60; i++) {
liHTML += "<li></li>";
styleHTML += `#wrap>ul>li:nth-child(${i+1}){transform: rotate(${6*i}deg)}`;
}
ulNode.innerHTML = liHTML;
styleNode.innerHTML = styleHTML;
document.head.appendChild(styleNode);
move();
//1s执行一次,模拟时钟一s走一下嘛
setInterval(move, 1000);
//走表函数
function move() {
//获取当前时间
var date = new Date();
var s = date.getSeconds();
//加上秒数的尾巴,每次分数都不一样,模拟分针每次都走嘛
var m = date.getMinutes() + s / 60;
//类似
var h = date.getHours() + m / 60;
//时针一个小时走360/12=30°
hourNode.style.transform = `rotate(${h*30}deg)`;
//分针一分钟6°
minuteNode.style.transform = `rotate(${m*6}deg)`;
//秒针一秒6°
secondNode.style.transform = `rotate(${s*6}deg)`;
}
</script>
</html>
扇形导航
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
#wrap {
height: 50px;
width: 50px;
position: fixed;
right: 0;
bottom: 0;
border-radius: 50%;
}
#wrap>.inner {
height: 100%;
}
#wrap>.inner>img {
position: absolute;
left: 0;
top: 0;
margin: 4px;
border-radius: 50%;
}
#wrap>#home {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
z-index: 1;
transition: 1.5s;
}
#home>img {
border-radius: 50%;
}
</style>
</head>
<body>
<div id="wrap">
<div class="inner">
<img src="img/clos.png">
<img src="img/full.png">
<img src="img/open.png">
<img src="img/prev.png">
<img src="img/refresh.png">
</div>
<div id="home">
<img src="img/home.png">
</div>
</div>
</body>
<script type="text/javascript">
window.onload = function() {
var homeElem = document.querySelector("#home");
var imgs = document.querySelectorAll("#wrap>.inner>img");
var c = 140;
var flag = true;
//第二部分(点击放大并缩回去)
for (let i = 0; i < imgs.length; i++) {
imgs[i].onclick = function() {
//存在闭包,里面不要用i,用this
//注意点1:记得重置一下,因为下面也操作了img,并增加了延迟
//这里应该取消掉延迟
this.style.transition = "0.5s";
//为了防止样式切换时对应不一致,导致效果失效
//transform覆盖的时候应该带上上次的状态
//这是最笨的办法,我们可以自己封装一个函数处理,抱歉,我不会
this.style.transform = "rotate(-720deg) scale(2)";
this.style.opacity = 0.1;
//过渡结束就会触发的事件,必须放在这个函数里面
//不然外面的过渡效果结束,也会来触发这个事件
this.addEventListener("transitionend", fn);
}
}
function fn() {
this.style.transition = "0.3s";
this.style.transform = "rotate(-720deg) scale(1)";
this.style.opacity = 1;
//因为事件一旦绑定就不会消失,这样其他的过渡效果也会触发这个事件
//所以应该解绑
this.removeEventListener("transitionend", fn);
}
//第一部分(导航出现和消失)
homeElem.onclick = function() {
if (flag) {
this.style.transform = "rotate(-720deg)";
for (let i = 0; i < imgs.length; i++) {
imgs[i].style.transition = `1s ${i*0.1}s`;
imgs[i].style.transform = "rotate(-720deg) scale(1)";
imgs[i].style.top = -getPosition(c, 90 * i / (imgs.length - 1)).top + "px";
imgs[i].style.left = -getPosition(c, 90 * i / (imgs.length - 1)).left + "px";
}
} else {
this.style.transform = "rotate(0deg) scale(1)";
for (let i = 0; i < imgs.length; i++) {
imgs[i].style.transition = `1s ${(imgs.length-1-i)*0.1}s`;
imgs[i].style.transform = "rotate(0deg)";
imgs[i].style.top = 0;
imgs[i].style.left = 0;
}
}
flag = !flag;
}
function getPosition(c, deg) {
var x = Math.round(c * Math.sin(deg * Math.PI / 180));
var y = Math.round(c * Math.cos(deg * Math.PI / 180));
return {
left: x,
top: y
};
}
}
</script>
</html>
好了,我的分享就到这里了,谢谢大家