<canvas> 是HTML中的一个元素,它可被用来通过 JavaScript(Canvas API 或 WebGL API)绘制图形及图形动画。
Canvas API 提供了一个通过 JavaScript 和 HTML 的 <canvas> 元素来绘制图形的方式。它可以用于动画、游戏画面、数据可视化、图片编辑以及实时视频处理等方面。
<canvas>标签本身没有绘图能力,它仅仅是图形的容器。在HTML,一般通过Javascript语言来完成实际的操作。
本文通过Javascript操作Canvas制作一个简单的显示当前时间的动画时钟,了解和学习简单的canvas用法,仅以抛砖引玉。
首先创建一个HTML文件,为了方便管理,使用一个div标签包裹两个canvas标签,并加上一些简单的css样式。
<!doctype html>
<html lang="zh-cn">
<head><title>Canvas绘制动画时钟</title>
<style>
html,body{margin:0;padding:0}
#clockWrap {
position: relative;
}
canvas {
position: absolute;
}
#clock-ui {
z-index: 2;
}
#clock-plate {
z-index: 1;
}
</style>
</head>
<body>
<div id="clockWrap">
<canvas id="clock-plate"></canvas>
<canvas id="clock-ui"></canvas>
</div>
<script></script>
</body></html>
本示例中使用了两个canvas标签(为什么使用两个,一个不是更简单吗?),一个用于绘制钟面,一个根据当前时间实时显示和更新时针、分针和秒针的动态指向。好了,话不多说,开干。
一个简单的时钟,可以分为钟面上的刻度和指针。其中刻度和12个数字是固定的,我们可以将它们绘制在当作背景的canvas上(示例中id为clock-plate的canvas)。
(1)要使用canvas,首先必须通过容器获取渲染上下文:
var $=function(id){return document.querySelector(id);}//这个函数只是为了方便获取dom元素
const canvasbg=$("#clock-plate"),
canvas=$("#clock-ui"),
ctx = canvasbg.getContext("2d"),//背景容器上下文
ctxUI = canvas.getContext("2d");//指针容器上下文,后面代码要用
//定义画布宽度和高度,时钟圆直径,并设置画布大小
const oW=1000,oH=800,cW=400,r=cW/2,oX=oW/2,oY=oH/2;
canvas.width=oW;
canvas.height=oH;
canvasbg.width=oW;
canvasbg.height=oH;
(2)画钟的边框,为了好看,这里画两个圈:
//画出时钟外圆框
ctx.lineWidth = 12;
ctx.beginPath();
ctx.arc(oX, oY, r+14, 0, 2 * Math.PI);
ctx.stroke();
ctx.closePath();
ctx.lineWidth = 8;
//画出时钟内圆框(刻度圈)
ctx.beginPath();
ctx.arc(oX, oY, r, 0, 2 * Math.PI);
ctx.stroke();
ctx.closePath();
ctx.beginPath();
边框效果图
(3)绘制刻度线和数字,可以利用三角函数计算出每个刻度的坐标:
利用三角函数计算刻度线的坐标位置
钟面上有12个大格,从正上方12开始,它们的度数分别是270,300,330,0,30,60,90,120,150,180,210,240。然后利用JS的Math.sin和Math.cos分别计算出各大格的坐标。注意:js中Math.sin()和Math.cos()的参数不是角度数是弧度。可以使用Math.PI/180*角度来转化,比如将30度转换成弧度=Math.PI/180*30
//绘制钟表中心点
ctx.beginPath();
ctx.arc(oX, oY, 8, 0, 2 * Math.PI);//圆心
ctx.fill();
ctx.closePath();
//设置刻度线粗细度
ctx.lineWidth = 3;
//设置钟面12个数字的字体、大小和对齐方式
ctx.font = "30px serif";
ctx.textAlign="center";
ctx.textBaseline="middle";
var kdx,kdy;
//绘制12个大刻度和12个数字
//为方便计算,先定义了0-11这12个刻度对应的度数,也可以直接定义对应的弧度。
const hd=Math.PI/180,degr=[270,300,330,0,30,60,90,120,150,180,210,240];
for(var i=0;i<12;i++){
kdx=oX+Math.cos(hd*degr[i])*(r-3);
kdy=oY+Math.sin(hd*degr[i])*(r-3);
ctx.beginPath();
ctx.arc(kdx, kdy, 6, 0, 2 * Math.PI);//画圆形大刻度
ctx.fill();
//绘制刻度对应的数字
ctx.strokeText(i==0? 12 : i,oX+Math.cos(hd*degr[i])*(r-24),oY+Math.sin(hd*degr[i])*(r-24));
ctx.closePath();
}
//绘制小刻度
ctx.lineWidth = 2;
for(var i=0;i<60;i++){
if(i % 5 == 0) continue;//跳过与刻度重叠的刻度
x0=Math.cos(hd*i*6);
y0=Math.sin(hd*i*6);
ctx.beginPath();
ctx.moveTo(oX+x0*(r-10), oY+y0*(r-10));
ctx.lineTo(oX+x0*r, oY+y0*r); //画短刻度线
ctx.stroke();
ctx.closePath();
}
效果如图:
钟面效果图
(4)根据当前时间绘制指针
习惯上,时针粗短,分针略粗而长,秒针细长。为加大区别,示例中秒针细长并且绘制成红色。
function drawHp(i){//绘制时针
const x0=Math.cos(hd*i*30),y0=Math.sin(hd*i*30);
drawPointer(oX,oY,oX+x0*(r-90),oY+y0*(r-90),10,"#000000");
}
function drawMp(i){//绘制分针
const x0=Math.cos(hd*i*6),y0=Math.sin(hd*i*6);
drawPointer(oX,oY,oX+x0*(r-60),oY+y0*(r-60),5,"#000000");
}
function drawSp(i){//绘制秒针
const x0=Math.cos(hd*i*6),y0=Math.sin(hd*i*6);
drawPointer(oX,oY,oX+x0*(r-20),oY+y0*(r-20),2,"#FF0000");
}
//抽取出绘制三种指针时共同的部分,注意指针绘制在渲染上下文ctxUI中
function drawPointer(ox,oy,tx,ty,width,color){
ctxUI.strokeStyle = color;
ctxUI.lineCap = "round";
ctxUI.lineWidth = width;
ctxUI.beginPath();
ctxUI.moveTo(ox, oy);
ctxUI.lineTo(tx,ty);
ctxUI.stroke();
ctxUI.closePath();
}
现在已经有了绘制三种指针的方法,参数是当前时间的时、分和秒,将根据它们的值确定指针的坐标。不过,因为使用的是默认的convas坐标体系,0值实际指向3的位置,需要小小的修正一下。
window.requestAnimationFrame(function fn(){
var d = new Date();
ctxUI.clearRect(0,0,oW,oH);
//度数从0开始,而0在3刻度(15分/秒位置),修正为全值减15,如果小于0则修正回来
var hour=d.getHours(),minute=d.getMinutes()-15,second=d.getSeconds()-15;
hour=hour>11? hour-15 : hour-3;
drawHp(hour>=0? hour : 12+hour);
drawMp(minute>=0? minute : 60+minute);
drawSp(second>=0? second : 60+second);
window.requestAnimationFrame(fn);
});
接下来,调用window.requestAnimationFrame,在其中绘制并更新指标的位置。看看效果如何:
指针绘制情况与实际时间相符
貌似效果有了,截图时电脑上的时间是10时17分,指针绘制上,时针指向10时,分针指向17。嗯,感觉有点别扭?对了,时针和分针怎么是端端正正地指向它们的整时整分刻度上呢?实际钟表上时针和分针是展示动态进度的,此时时针应该越过10时的位置才对。没关系,我们在绘制时针和分针时别点东西,让它的角度值加上分针和秒针的值试试。
//修改后的绘制三种指针的方法
function drawHp(i,f,m){//绘制时针,参数:时,分,秒
const x0=Math.cos(hd*(i+(f/60)+(m/600))*30),y0=Math.sin(hd*(i+(f/60)+(m/600))*30);
drawPointer(oX,oY,oX+x0*(r-90),oY+y0*(r-90),10,"#000000");
}
function drawMp(i,f){//绘制分针,参数,分,秒
const x0=Math.cos(hd*(i+(f/60))*6),y0=Math.sin(hd*(i+(f/60))*6);
drawPointer(oX,oY,oX+x0*(r-60),oY+y0*(r-60),5,"#000000");
}
function drawSp(i){//绘制秒针
const x0=Math.cos(hd*i*6),y0=Math.sin(hd*i*6);
drawPointer(oX,oY,oX+x0*(r-20),oY+y0*(r-20),2,"#FF0000");
}
再来看看效果,嗯,立竿见影呀:
指针指向更合理了
到此为止,canvas绘制一个简易时钟就完成了。下面继续优化一下。刚才使用requestAnimationFrame方法即时更新绘制情况。这个方法与刷新率有关,看看mdn上面怎么说的:
window.requestAnimationFrame() 方法会告诉浏览器你希望执行一个动画。它要求浏览器在下一次重绘之前,调用用户提供的回调函数。
对回调函数的调用频率通常与显示器的刷新率相匹配。虽然 75hz、120hz 和 144hz 也被广泛使用,但是最常见的刷新率还是 60hz(每秒 60 个周期/帧)。为了提高性能和电池寿命,大多数浏览器都会暂停在后台选项卡或者隐藏的 <iframe> 中运行的 requestAnimationFrame()。
本示例中,更新指针的位置并不需要很高的刷新频率,可以通过节流进行一下优化:
var fps = 5, fpsInterval = 1000 / fps,lastTime = new Date().getTime(); //记录上次执行的时间
function runStep() {
requestAnimationFrame(runStep);
var d=new Date(),now = d.getTime()
var elapsed = now - lastTime;
if (elapsed > fpsInterval) {
ctxUI.clearRect(0,0,oW,oH);
lastTime = now - (elapsed % fpsInterval);
//度数从0开始,而0在3刻度(15分/秒位置),修正为全值-15,如果小于0则用60减回
var hour=d.getHours(),minute=d.getMinutes()-15,second=d.getSeconds()-15;//console.log(d.getSeconds(),second);
hour=hour>11? hour-15 : hour-3;
drawHp(hour>=0? hour : 12+hour,minute+15,second+15);
drawMp(minute>=0? minute : 60+minute,second+15);
drawSp(second>=0? second : 60+second);
}
}
runStep();
当然,实现时钟的方法是很多,比如可以使用画布的旋转(rotate方法)来实现指针的动态转动等等。
完整HTML+JS源码:
看最终效果:
制作思路:
在timeline里每一行使用dl标签布局;每行(dl)左侧的边框使用border-left绘制。左侧圆形使用dt布局,我们可以使用border给dt加边框,使用border-radius绘制圆形效果,右侧文字使用dd排列。
html布局代码如下:
<div class="timeline">
<dl>
<dt class="on"></dt>
<dd>
<h3>管家接单中</h3>
<p>2021-04-21 14:47:56.0</p>
</dd>
</dl>
<dl>
<dt></dt>
<dd>
<h3>已派单</h3>
<p></p>
</dd>
</dl>
<dl>
<dt></dt>
<dd>
<h3>已完成</h3>
<p></p>
</dd>
</dl>
</div>
css样式代码:
.timeline{ padding: 1rem 0;}
.timeline dl{border-left:1px solid #eee; position:relative; margin:0 0 0 .5rem; height: 5rem;}
.timeline dl dt{ position: absolute; left: -.5rem; top:0rem; width:.5rem; height: .5rem; border-radius: .5rem; border:2px solid #eee; background-color: #fff;}
.timeline dl dt.on{border:2px solid #FF8800;}
.timeline dl dd{ position: absolute; left: 1rem; top:0rem;}
.timeline dl dd h3{font-size:1.1rem; font-weight:600; padding:0 0 .5rem 0; color: #333333;}
.timeline dl dd p{ color: #949494;}
.timeline dl:last-child{border-left:none; }
说明:定义dl样式的时候position一定要使用relative。因为后面我们需要给里面的dt和dd使用绝对定位。
dt标签里,position:absolute代表使用绝对定位。left位置为-.5rem代表向左负的0.5rem(这里我使用的rem单位 ,你们使用px的话,就写具体的px 值)。宽和高也同时是.5rem。然后为了绘制圆形设置border-radius也是.5rem。边框使用border属性设置宽度为2px。
dd标签里,同样设置position:absolute使用绝对定位。设置left为1rem(代表距离左边界1rem)。
然后我们看到最后一个dl左边是没有边框的,如下图箭头所示:
这个是通过:.timeline dl:last-child{border-left:none; }设定的。
如果没有这行,效果就是这边的样子了:
好了,介绍就这些,代码不多,实现了效果:)
天我们学习的内容有:过渡,动画,转换,伸缩盒子。
可以说今天学习的内容都是重量级的大佬,学好了,使用css3做出酷炫的效果 So Easy!~~
1.过渡
在css3中,有一个属性可以设置过渡效果。
它就是transition,所谓的过渡效果,指的就是以动画的形式慢慢演化样式属性变化的过程。
A.案例:通过transition设置焦点过渡效果
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Document</title><style>div{width: 200px;height: 200px;margin:200px;background: url(girl.jpg);border-radius:50%;transition:all 1s linear 0.3s;cursor: pointer;}div:hover{box-shadow: 0px 0px 20px blue;}</style></head><body><div></div></body></html>
注意页面中的代码:
第一,我们给div添加了一个hover伪类样式,当我们鼠标悬停在div上方的时候,会给div盒子添加一个蓝色的盒子阴影。
第二,我们给div盒子添加了一个transition样式,设置的值为:all 1s linear 0.3s;
这四个数据分别对应
transition-property(需要过渡的属性):如果设置为all表示所有样式属性都需要过渡。
transition-duration(过渡的时间):以秒作为单位,设置过渡的时间
transition-timing-function(过渡的方式):常用的有linear(匀速),ease(先慢后快),ease-in,ease-out,ease-in-out等
transition-delay(延迟的时间):以秒作为单位进行延迟,延迟之后开始进行过渡效果。
所以,我们通过transition这个复合属性设置的过渡效果为:
all:需要过渡所有的属性
1s:过渡的时间为1秒
linear:匀速过渡
0.3s:在延迟0.3秒之后开始过渡动画。
如果大家理解了上面的描述,那么也就不难理解咱们鼠标放到div上之后,为啥会慢慢出现蓝色的光晕了,就是因为咱们添加了过渡,所以,慢慢的就会给盒子添加阴影效果。
2.动画:
在学习完了过渡之后,发现咱们可以使用transition去以动画的形式展示样式的改变以及变化的过程,这可以帮助我们来实现一些过渡的动画。
但是,有的时候,我们的需求会更加的复杂,要求会更加的多变,那么,transition可能就无法满足我们的需要了,我们需要有更加炫酷,复杂的效果呈现。
那么,动画animation就可以满足我们的需要。
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Document</title><style>@keyframes moveAndChange{0%{left:0px;top:0px;}25%{left:200px;top:200px;background:green;border-radius: 0;}50%{left:400px;top:200px;background:blue;border-radius: 50%;}75%{left:400px;top:0px;background:#ccc;border-radius: 0;}100%{left:0px;top:0px;background:red;border-radius: 50%;}}div{margin:200px;width: 200px;height: 200px;position: absolute;background:red;border-radius:50%;animation: moveAndChange 5s linear 0.5s infinite normal;}</style></head><body><div></div></body></html>
代码效果如下:
同样,让我们来关注编写的代码:
1.在样式中,首先我们使用@keyframes 来定义了一个复杂的动画,在css3中,新增了@keyframes可以来帮助我们添加动画。代码如下:
/*动画的名字叫做moveAndChange*/
@keyframes moveAndChange{
/*动画最初的时候,将left设置为0px,top设置为0px*/
0%{
left:0px;
top:0px;
}
/*当动画进行到25%的时候,使用动画将left过渡到200px,top过渡到200px,
背景颜色过渡为绿色,圆角过渡为0(无圆角)*/
25%{
left:200px;
top:200px;
background:green;
border-radius: 0;
}
/*当动画进行到50%的时候,使用动画将left过渡到400px,top过渡到200px,
背景颜色过渡为蓝色,圆角过渡为50%(正圆)*/
50%{
left:400px;
top:200px;
background:blue;
border-radius: 50%;
}
/*当动画进行到75%的时候,使用动画将left过渡到400px,top过渡到0,
背景颜色过渡为灰色,圆角过渡为0(无圆角)*/
75%{
left:400px;
top:0px;
background:#ccc;
border-radius: 0;
}
/*当动画结束的时候,使用动画将left过渡到0x,top过渡到0px,
背景颜色过渡为红色,圆角过渡为50%(正圆)*/
100%{
left:0px;
top:0px;
background:red;
border-radius: 50%;
}
}
这是一个比较复杂的动画效果,可以发现,它通过百分比的形式将一个完整的动画拆分成了5个部分,每个部分都有不同的样式效果,而当我们采用该动画的元素就会按照设置的顺序和样式效果进行动画的过渡和展示。
2.上面我们只是通过@keyframes创建了一个动画,我们还需要通过特定的语法来使用这个动画。
就是下面这句代码了:
animation: moveAndChange 5s linear 0.5s infinite normal;
它是一个复合属性,设置了6个值,分别对应:
animation-name(设置动画的名称):用来设置动画的名字,我们这里写的是moveAndChange ,也就是说我们就是要使用我们刚刚创建的动画。
animation-duration(设置整个动画的时间):以秒作为单位,我们这里写的是5s,表示整个动画的时间为5秒
animation-timing-function(设置播放动画的方式):播放动画的方式,常用的有linear(匀速),ease(先慢后快),ease-in,ease-out,ease-in-out等,我们使用的是linear匀速播放动画。
animation-delay(设置动画的延迟):以秒作为单位,我们写的是0.5s,表示延迟0.5秒之后开始播放动画。
animation-iteration-count(设置动画播放的次数):播放动画的次数,我们这里写的是infinite ,表示动画将会被播放无限次,如果写数字,那么就会播放数字对应的次数。
animation-direction(设置是否反向播放动画):我们写的是normal,表示正常播放动画,如果写的是
alternate则表示要反向播放动画,大家也可以自己试一试这个效果。
最终,我们通过@keyframes创建动画,通过animation设置动画,成功完成了这个复杂的动画效果。
3.转换
在css3中,我们通过transform属性可以设置元素的转换效果,具体的效果如下:
A.平移
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Document</title><style>body{background:pink;}div{width: 200px;height: 200px;position: absolute;background: green;left:0px;top:0px;transform: translate(300px,300px);}</style></head><body><div></div></body></html>
代码效果如下:
如上图所示,本来div盒子的位置是left:0,top:0;
但是我们通过transform: translate(300px,300px);将盒子进行了偏移,所以,盒子的位置发生了改变。
B.旋转
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Document</title><style>body {background: pink;}div {width: 200px;height: 200px;margin: 200px;position: absolute;background: green;left: 0px;top: 0px;transform: rotate(45deg);}</style></head><body><div></div></body></html>
代码效果如下:
如上图所示,本来div盒子应该是四四方方的。
但是,经过我们的代码transform: rotate(45deg); //deg为单位,表示度数。
进行了45度的旋转之后,呈现出来的就是一个菱形的盒子了,旋转的正方向为顺时针,负方向为逆时针。
C.缩放
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Document</title><style>body {background: pink;}div {width: 200px;height: 200px;margin: 200px;position: absolute;background: green;left: 0px;top: 0px;transform: scale(0.5,0.25);}</style></head><body><div></div></body></html>
代码效果如下:
如上图所示,本来盒子的宽高为200*200,而我们通过transform: scale(0.5,0.25);进行的缩放
scale的第一个参数为0.5,表示横向缩小为0.5倍
scale的第二个参数为0.25,表示纵向缩小为0.25倍。
scale的参数如果为1,则表示不进行任何缩放,小于1就是做缩小,而大于1表示做放大。
小结:transform转换中其实还包含了skew(倾斜),matrix(矩阵转换),相对来说用到的不是特别多,所以在本文中我们便不再做介绍。
4.flex布局
Flex布局,可以简便、完整、响应式地实现各种页面布局。
Flex是Flexible Box的缩写,翻译成中文就是“弹性盒子”,用来为盒装模型提供最大的灵活性。任何一个容器都可以指定为Flex布局。
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Document</title><style>div{box-sizing: border-box;}.parent {width: 600px;height: 200px;margin: 100px;position: absolute;background: green;left: 0px;top: 0px;display: flex;justify-content: flex-start}.parent div{width: 20%;border:1px solid #ccc;background:pink;}</style></head><body><div><div>1</div><div>2</div><div>3</div><div>4</div></div></body></html>
代码效果如下:
如图所示,咱们通过display:flex将.parent元素设置为了flex盒子,那么子元素将会按照justify-content设置的方式进行元素的排列,目前看来,和我们没有设置flex盒子的效果是一致的。
接下来我们更改一下,将justify-content设置为flex-end,效果如下图所示:
所以我们就应该发现,flex-start是让所有的子元素从父元素的左侧开始排列
而flex-end是让所有的子元素从元素的右侧开始排列。
我们再来更改一下,将justify-content设置为center,效果如下图所示:
更厉害了,子元素在父盒子的中央位置排列显示了。
然后,我们再将justify-content设置为space-around,效果如下图所示:
它是平均分配的形式为每一个子元素设置了间距,但是看起来有点变扭。
所以我们推荐将justify-content设置为space-between,效果如下图:
我们还可以通过flex-wrap来设置子元素是否换行显示,以及flex-direction设置子元素排列的顺序。
这两个属性可以设置的值如下:
flex-wrap: nowrap;//不换行,会自动收缩
flex-wrap: warp;//换行,会自动收缩
flex-wrap: warp-reverse;//反转,从默认的从上到下排列反转为从下到上。
flex-direction:row; //从左至右一行一行进行子元素的排列
flex-direction:column; //从上到下一列一列进行子元素的排列
flex-direction:row-reverse; //从右至左一行一行进行子元素的排列
flex-direction:column-reverse; //从下到上一列一列进行子元素的排列
案例代码如下:
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Document</title><style>div{box-sizing: border-box;}.parent {width: 600px;height: 200px;margin: 100px;position: absolute;background: green;left: 0px;top: 0px;display: flex;justify-content: space-between;flex-wrap: nowrap;flex-direction: row-reverse;}.parent div{width: 20%;border:1px solid #ccc;background:pink;}</style></head><body><div><div>1</div><div>2</div><div>3</div><div>4</div><div>5</div><div>6</div></div></body></html>
我们设置了flex-wrap: nowrap;(不换行,压缩所有的子元素在一行中显示),以及flex-direction: row-reverse;(反向排列)
代码效果如下:
如果设置为flex-wrap: warp(换行显示无法在一行显示的子元素),则效果如下:
如果将flex-direction: column;,则会纵向排列元素,效果如下图:
除了上面的这些给伸缩盒子父元素设置的样式之外,我们还可以可以伸缩盒子的子元素设置flex属性,用来设置平均分配整个父盒子的空间。
代码如下:
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Document</title><style>div{box-sizing: border-box;}.parent {width: 600px;height: 200px;margin: 100px;position: absolute;background: green;left: 0px;top: 0px;display: flex;justify-content: space-between;}.parent div{flex:1;width: 20%;border:1px solid #ccc;background:pink;}</style></head><body><div><div>1</div><div>2</div><div>3</div><div>4</div></div></body></html>
效果如下:
如上图所示,每个盒子平均分配了父盒子的空间,原本宽度为20%,现在被拉伸了。
除此之外,咱们还可以使用flex属性进行进一步的设置,代码如下:
<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Document</title><style>div{box-sizing: border-box;}.parent {width: 600px;height: 200px;margin: 100px;position: absolute;background: green;left: 0px;top: 0px;display: flex;justify-content: space-between;}.parent div:nth-of-type(1){flex:1;border:1px solid #ccc;background:red;}.parent div:nth-of-type(2){flex:2;border:1px solid #ccc;background:green;}.parent div:nth-of-type(3){flex:2;border:1px solid #ccc;background:blue;}.parent div:nth-of-type(4){flex:1;border:1px solid #ccc;background:pink;}</style></head><body><div><div>1</div><div>2</div><div>3</div><div>4</div></div></body></html>
效果如下图:
我们分别给四个子盒子设置了flex:1 , flex:2, flex:2 ,flex:1.
这是什么意思呢?
四个flex加起来一共是6.那么第一个盒子就占据整个父盒子的1/6宽度。
同理,另外三个盒子分别占据2/6,2/6,1/6的宽度,所以就形成了我们现在看到的效果。
原文来源于:黑马程序员社区
学习资源:
想学习css,可以关注:黑马程序员头条号,后台回复:css
*请认真填写需求信息,我们会在24小时内与您取得联系。