你们好,有一段时间没有发表《前端每日实战》做品了,今天,2020年的第一天,终于又从新启程,我将继续实践 PBL(Project-based Learning)的学习方法,并把学习笔记分享出来,和你们交流探讨、共同进步。css
这段没有发表做品的日子里,我在人民邮电出版社的支持和帮助下,写出了一本书,命名为《CSS3 艺术》,它脱胎于《前端每日实战》的一百多个做品,把伪元素、边框、背景、阴影、剪切、滤镜、色彩混合、变量、计数器、变换、缓动、动画这些概念进行了梳理和总结,但愿能为你们学习 CSS 提供一些帮助。此书已于近日上市,京东、天猫、当当都可购买。html
接下来进入正题,今天的项目是用纯 CSS 制做一个 2020 造型图案,并为它增长一点动画效果。前端
按下右侧的“点击预览”按钮能够在当前页面预览,点击连接能够全屏预览。app
https://codepen.io/comehope/pen/jOEGzZxdom
dom 结构的最外层用 <figure>
元素,表示这是一个图片:函数
<figure></figure>
页面用深红色背景,并采用 grid 布局:布局
body { margin: 0; height: 100vh; display: flex; align-items: center; justify-content: center; background-color: darkred; } figure { display: grid; grid-template-columns: repeat(8, 1em); grid-template-rows: repeat(3, 1em); font-size: 60px; color: whitesmoke; }
grid 布局比定位布局的语义化更好,一样的布局效果,grid 布局的代码量比定位布局的代码量明显减小。此项目建立了一个 3 行 8 列的网格,为了能明显看出网格线,咱们增长一些辅助线,这些辅助线会在做品完成后被删除掉:学习
figure { background-image: linear-gradient(to bottom, transparent 0%, transparent 99%, pink 100%), linear-gradient(to right, transparent 0%, transparent 99%, pink 100%), linear-gradient(to top, transparent 0%, transparent 99%, pink 100%), linear-gradient(to left, transparent 0%, transparent 99%, pink 100%); background-size: 1em 1em; background-repeat: repeat, repeat, repeat-x, repeat-y; }
效果以下图:字体
在 dom 中增长有关数字 2 的元素,数字 2 被分红了 4 部分:flex
<figure> <span class="two part1"></span> <span class="two part2"></span> <span class="two part3"></span> <span class="two part4"></span> </figure>
把这 4 部分分别放置在网格的相应位置上,grid-area
的属性 x/y 分别表示顶部网格线编号和左侧网格线编号,网格线是从 1 开始编号的,以 .part4
为例,它的顶部网格线是从上数的第3条,左侧网格是从左数的第2条,因此它的属性值是 3/2
:
.two { background-color: currentColor; } .two.part1 {grid-area: 1/1;} .two.part2 {grid-area: 2/2;} .two.part3 {grid-area: 3/1;} .two.part4 {grid-area: 3/2;}
效果以下图:
接下来把各部分的形状都改成扇形,border-radius
属性有 4 个值,分别表明左上、右上、右下、左下的圆角值,以 .part4
为例,它是左下角为圆角的扇形,因此它的属性值是 0 0 0 100%
:
.two.part1 {grid-area: 1/1; border-radius: 100% 0 0 0;} .two.part2 {grid-area: 2/2; border-radius: 0 0 100% 0;} .two.part3 {grid-area: 3/1; border-radius: 100% 0 0 0;} .two.part4 {grid-area: 3/2; border-radius: 0 0 0 100%;}
效果以下图:
这时一个数字 2 已经绘制出来了,另外一个数字 2 不须要增长 dom 元素,只要把第 1 个元素复制一下就能够了,这里使用的是 drop-shadow()
函数,它的 2 个参数分别表明复制后的偏移量,此处的参数值为 4em 0
,即水平方向向右平移 4em,垂直方向不变:
.two { filter: drop-shadow(4em 0); }
效果以下图:
至此,2个数字 2 就都画出来了。
在 dom 中增长有关数字 0 的元素,和数字 2 不一样,每个数字 0 只须要 1 个 dom 元素,因此 2 个数字 0 须要 2 个 dom 元素:
<figure> <span class="two part1"></span> <span class="two part2"></span> <span class="two part3"></span> <span class="two part4"></span> <span class="zero copy-1"></span> <span class="zero copy-2"></span> </figure>
在网格中分别定位 2 个数字 0,仍使用 grid-area
参数,但它们的属性值为 4 个数字,后 2 个数字分别表明底部网格线编号和右侧网格线编号,可知每一个 0 占据 2 * 2 的网格区域:
.zero.copy-1 {grid-area: 2/3/4/5;} .zero.copy-2 {grid-area: 2/7/4/9;}
画出数字 0 的大体轮廓,这里是利用边框属性绘制的,元素自己宽高为 0,可是有 1em 的边框,其中上、下边框是白色,左、右边框是透明色,注意,在 CSS 中边框并不必定以线条的形式存在,在此处每条边框都是三角形:
.zero { width: 0; height: 0; border: 1em solid; border-color: currentColor transparent; }
效果以下图:
增长圆角效果:
.zero { border-radius: 50%; }
效果以下图:
再倾斜 45 度:
.zero { transform: rotate(-45deg); }
效果以下图:
至此,2 个数字 0 也都画出来了。
在 dom 中增长有关文本的元素,一共 3 个单词,分别用 3 个元素表示:
<figure> <span class="two part1"></span> <span class="two part2"></span> <span class="two part3"></span> <span class="two part4"></span> <span class="zero copy-1"></span> <span class="zero copy-2"></span> <span class="text happy">happy</span> <span class="text new">new</span> <span class="text year">year</span> </figure>
效果以下图,能够看到这 3 个单词都重叠在第1行的第2个网格中,这是由于在 grid 布局下会自动把未指定 grid-area
属性的元素排放在未被占用的网格中:
接下来为 3 个文本元素设置它们的网格位置:
.text.happy {grid-area: 1/2;} .text.new {grid-area: 2/4;} .text.year {grid-area: 1/6;}
效果以下图:
接下来设置文字的样式,把文字都改成大写字母,加粗,字体用花式字体,为避免与左侧的图案靠得太紧,再把文字左侧增长一点内边距:
.text { text-transform: uppercase; font-size: 0.66em; line-height: 1.5em; font-weight: bold; font-family: cursive; padding-left: 0.25em; }
效果以下图:
至此,文字绘制完成。
由于数字 0 造型太抽象,因此咱们让数字 0 转动起来,动画很简单,就是以 4 秒每圈的速度不断地转啊转,由于数字 0 此前设置了旋转 45 度,因此动画的 to
关键帧要加上 45 度,另外旋转的度数是负值,表示逆时针旋转:
.zero { animation: round 4s linear infinite; } @keyframes round { to { transform: rotate(calc(-45deg + -1turn)); } }
效果以下图:
不过咱们看到左侧的数字 0 在转动时遮挡住了文字“new”,为了不遮挡,咱们用色彩混合模式来解决,这样当数字 0 和文字“new”重叠时,重叠的部分会变为黑色:
.text { mix-blend-mode: difference; }
效果以下图:
至此,整个做品所有完成了,最后把辅助线删除掉:
figure { /*background-image: linear-gradient(to bottom, transparent 0%, transparent 99%, pink 100%), linear-gradient(to right, transparent 0%, transparent 99%, pink 100%), linear-gradient(to top, transparent 0%, transparent 99%, pink 100%), linear-gradient(to left, transparent 0%, transparent 99%, pink 100%); background-size: 1em 1em; background-repeat: repeat, repeat, repeat-x, repeat-y;*/ }
效果以下图:
完整的 CSS 代码以下:
body { margin: 0; height: 100vh; display: flex; align-items: center; justify-content: center; background-color: darkred; } figure { display: grid; grid-template-columns: repeat(8, 1em); grid-template-rows: repeat(3, 1em); font-size: 60px; color: whitesmoke; } .two { background-color: currentColor; filter: drop-shadow(4em 0); } .two.part1 {grid-area: 1/1; border-radius: 100% 0 0 0;} .two.part2 {grid-area: 2/2; border-radius: 0 0 100% 0;} .two.part3 {grid-area: 3/1; border-radius: 100% 0 0 0;} .two.part4 {grid-area: 3/2; border-radius: 0 0 0 100%;} .zero.copy-1 {grid-area: 2/3/4/5;} .zero.copy-2 {grid-area: 2/7/4/9;} .zero { width: 0; height: 0; border: 1em solid; border-color: currentColor transparent; border-radius: 50%; transform: rotate(-45deg); animation: round 4s linear infinite; } @keyframes round { to { transform: rotate(calc(-45deg + -1turn)); } } .text.happy {grid-area: 1/2;} .text.new {grid-area: 2/4;} .text.year {grid-area: 1/6;} .text { text-transform: uppercase; font-size: 0.66em; line-height: 1.5em; font-weight: bold; font-family: cursive; padding-left: 0.25em; mix-blend-mode: difference; }