开始之前
最近自己懒癌又犯了,本来计划一周出两篇日记,结果上个周写到 Javascript 原型与继承时突然不知道怎么写了周末就打了一天的游戏。这两天忙公司项目的事情,今天正好处理了算是渲染电子签章的东西,觉得挺有意思,正好也写一篇 CSS 的文章过渡一下。
代码开撸
政府红头文件的下发需要盖章,审批单的审批需要盖章,开发票需要盖章,结婚证需要盖章,毕业证书需要盖章,资格证书需要盖章,几乎所有的批示行文件或者证书都需要盖章。现在政府也好,企业也好都在提倡无纸化办公,一些审批性工作可能没有纸质文件了,都会在网上完成审批。为了保证还是熟悉味道,盖章这个动作也要搬到网上了。领导点击一个同意,网页上渲染出一个盖章,不用去费劲真拿章,盖章。当然关于电子签章是有很多权限认证和安全认证的,这篇日记只说渲染,其他的都不负责。
项目需求
最近这个项目里面有一个流程审批的页面,用户发起一条审批流程,等流程各个节点的审批人完成审批后,审批的结果的签章就会显示在用户的申请单上。效果如下:
上面那个审批通过的盖章就是需要我实现的电子签章。
做阴影做时间长了,这个你可能一看就是一个多重边框的效果。在上一篇CSS的文章,我曾经提到过做一个边框阴影的办法就是使用 box-shadow,然后直接在第三个参数上设定一个距离,再添加一个颜色。其实这个属性第四个参数叫“扩张半径”,通过指定正值或负值,可以让投影面积加大或者减小。前面三个参数如果设置为 0,得到的投影就像一道实线的边框。
background:red;
box-shadow: 0 0 0 10px #655
当然了这个并没有什么了不起的,因为你完全可以用 border
属性开生成一个完全一样的边框效果。不过 box-shadow
的好处在于,它支持逗号分隔的语法,我们可以创建任意数量的投影。因此,我们可以非常轻松的实现上面我们项目要求的效果。
这里唯一需要注意的是,box-shadow
是层层叠加的,第一层的 投影位于最顶层,一次类推。因此,你就需要按此规律调整扩张半径。比如说,再前面代码中,我们像在外圈再加一道 5px 的外框,那就需要指定扩张半径的值为 15px (10px + 5px)。如果你愿意,甚至还可以在这些 “边框”的底下再加一层常规的投影。
background: red;
box-shadow: 0 0 0 10px #655,
0 0 0 15px deepink;
0 2px 5px 15px rgba(0,0,0,.6);
代码实现
我们项目里面除了多重边框外,可以看到位置是有一个倾斜的,所以要再上面的基础上加一个倾斜,使用的属性是transform
。好了,现在我把代码全部贴在下面。
<!DOCTYPE html>
<html>
<head>
<title>Circle</title>
<style type="text/css">
/* box-shadow 电子签章 */
.circle{
margin: 50px auto;
width:46px;
height: 46px;
line-height: 25px;
padding: 25px;
color:#fff;
font-weight: bold;
text-align: center;
word-break: break-all;
border-radius: 50%;
background-color: #5acc9b;
box-shadow: 0 0 0 2px #ffffff, 0 0 0 8px #5acc9b, 0 0 0 25px #fff, 0 0 0 27px #8fddbb, 0 0 0 32px #fff,0 0 0 34px #dbf4ea;
font-size: 23px;
transform: rotate(-45deg);
}
</style>
</head>
<body>
<div class="circle">审批通过</div>
</body>
</html>
多重投影解决方案可以再绝大数场合都可以很好地工作,但是有一些需要注意的地方:
- 投影的行为跟边框不完全一致,因为它不会影响布局,而且也不会收到
box-size
的影响。不过你还是可以通过内边距或外边距(这取决于投影是内嵌还是外扩)来额外模拟出边框所需要占据的空间。 - 上述方法创建出的假“边框”出现在元素的外圈。它们并不会响应鼠标事件,比如悬停或者点击。如果这一点非常重要,你可以给
box-shadow
属性加上inset
关键字,来使投影绘制在元素的内圈。请注意,此时你需要增加额外的内边距来腾出足够的空隙。
项目拓展
项目里的章还是略显随意,我们需要设计一个更加正规的机关专用章,就像下面这个:
使用纯CSS实现起来还是很有难度的。如果完全真的使用 CSS,对于上面这个环形文字,那可能我们需要对每个字进行旋转了。在实现这个的时候我想起来我师父曾经跟我讲过他使用 SVG,来绘制流程图,于是这个的实现我就使用了svg, 内联的svg原生支持以任意路径排队的文字,而圆形至不过是一种特定的路径而已。
在 SVG 中,让文本按照路径排列的基本方法就是用一个<textPath>
元素来包裹住这段文本,再把它们装进一个<text>
元素中。这个<textPath>
元素还需要再它的 ID 属性中引用一个 <path>
元素,然后就可以用这个 <path>
元素来定义我们想要的路径。在内联 SVG 内部的文本同样可以继承绝大多数字体样式,因此我们可以完全不需要担心字体的问题,就像处理外部的 SVG 图像时一样。
上面我们想把 “伟哥出品 必属精品”这句话定义为环形文字。首先我们需要在HTML元素中添加一个 SVG,并用一个路径来定义我们想要的图形。
<div class="circle-seal">
<svg viewBox="0 0 100 100">
<path d="M 0,50 a 50,50 0 1,1 0,1 z" id="circle-seal" />
</svg>
</div>
请注意我们使用的是 viewBox 来定义它的单位,不是用width height属性,这个属性允许我们不需要指定一个固定的尺寸就可以设置坐标系统和图形系统的宽高比。这个写法不仅更加紧凑,还可以节省几行CSS代码,因为我们不需要对这个 <svg> 应用 100% 的宽度和高度了: 它自适应外层容器的尺寸。
对于 SVG 的路径一般人是没法看懂的,这个放个链接,需要的时候看一下吧
到目前为止,我们看到的路径是一个黑色的圆。我们通过<text> 和 <textPath> 元素来添加文本,并通过 xlink:href 属性来把它链接到这个圆上:
<div class="circle-seal">
<svg viewBox="0 0 100 100">
<path d='M 0,50 a 50,50 0 1,1 0,1 z' id="circle-seal" />
<text>
<textPath xlink:href="#circle-seal">
伟哥出品 必属精品
</textPath>
</text>
</svg>
</div>
目前为止环形效果是出来了,但是还有一块黑色的填充需要从路径中去掉。在任何情况下我们都不希望这个圆形被人看到;我们只是希望它发挥一个基线的作用,来引导这段文本,我们可以使用 CSS 给它设置一个 fill:none 样式来消除它
.circle-seal path{
fill: none
}
现在这个圆就会不见了,但是接下来的问题是文本都跑到 SVG 元素外面去了,而且遭到了裁切。为了修正这个问题,我们需要让这个容器元素变小,然后再给 SVG 元素应用 overflow: visible 样式,这样他就不会把内容的益处部分裁掉了。
.circle-seal{
margin: 100px auto;
height: 100px;
width: 100px;
}
.circle-seal path{
fill:none;
}
.circle-seal svg{
display: block;
overflow: visible;
}
OK 这样一个环形的文字就可以实现了。
对于实现一个上面的红色签章,五角星和权威鉴定部分我是用了绝对定位来实现的,边框是使用的box-shadow,就是上一个例子说的。还有一个事情 fill 这个属性是填充,可以设置颜色值,环形文字变红就是用了这个属性。其他的就是常规操作,需要咱们一点一点调试来达到想要的效果。好了,下面就把全部代码贴在下面。
<!DOCTYPE html>
<html>
<head>
<title>Circle</title>
<style type="text/css">
.circle-seal{
width: 100px;
height: 100px;
margin: 100px auto 0;
font-size: 22px;
font-weight: bold;
color: red;
position: relative;
border-radius: 50%;
border:1px solid #ffffff;
box-shadow: 0 0 0 22px #ffffff, 0 0 0 24px red;
}
.circle-seal path{
fill: none;
}
.circle-seal svg{
display: block;
overflow: visible;
transform: rotate(-26deg);
}
.circle-seal svg text{
letter-spacing: 2px;
fill:red
}
.circle-seal .star{
position: relative;
left: 24px;
top: -90px;
font-size: 54px;
border-radius: 50%;
}
.circle-seal .text{
color: red;
font-size: 18px;
position:absolute;
top:83px;
left:14px;
}
</style>
</head>
<body>
<div class="circle-seal">
<svg viewBox="0 0 100 100">
<path d='M 0,50 a 50,50 0 1,1 0,1 z' id="circle-seal" />
<text>
<textPath xlink:href="#circle-seal">
伟哥出品 必属精品
</textPath>
</text>
</svg>
<div class="star"></div>
<div class="text">权威鉴定</div>
</div>
</body>
</html>
写在最后
CSS真的是非常深奥,使用它可以构造出千奇百怪的内容,更能使页面呈现的方式更加美观、优雅。本期使用CSS实现电子签章到此就结束了。最后我要给信上盖个印章,当是把我的相思印在你的心上!
彩蛋时刻
快速复制系统源码
背景介绍
有些场景下需要将系统的所有源码拷贝在一起,比如:申请软件著作权时需要提供源码,一个一个文件copy就太慢了。
解决方案
在Linux 或者 Mac 上执行以下脚本:
find . -name '.java' -o -name '.ftl' | xargs cat |head -n 4000 > software_copyright_src.java
将文件software_copyright_src.java 下载到本地,Copy到Word文档中
简单说明:
find . -name '.java' -o -name '.ftl' //查找当前目录以及子目录中以java或者ftl结尾的文件
find . -name '.java' -o -name '.ftl' | xargs cat //将代码文件合并在一起
find . -name '.java' -o -name '.ftl' | xargs cat |head -n 4000 > software_copyright_src.java //截取前4000行代码写入文件中
注意事项
一定要在项目的根目录执行,否则有可能包含其他项目代码
快速统计文件的代码行数
Linux 有一个统计文件行数的命令 wc。使用 wc 可以打印出每个文件和总文件的行数、字数和字节数,如果没有指定文件,则会读取标准输入 (一般是终端) 做统计。格式如下:
Usage: wc [OPTION]... [FILE]...
-c, --bytes, --chars print the byte counts
-l, --lines print the newline counts
-L, --max-line-length print the length of the longest line
-w, --words print the word counts
--help display this help and exit
--version output version information and exit
下面举几个例子:
统计当前目录下,py 文件数量:
find . -name "*.py" |wc -l
统计当前目录下,所有 py 文件行数:
find . -name "*.py" |xargs cat|wc -l
统计当前目录下,所有 py 文件行数,并过滤空行:
find . -name "*.py" |xargs cat|grep -v ^$|wc -l