CSS & SVG 绘制写作网格线的三种方式

开发 前端
CSS 渐变混合模式的优点在于实现思路比较简单,很容易想到,纯色背景优先推荐,缺点是混合模式有一些局限性,比如在黑色背景下可能需要换一种模式了。

最近有同事问我这样一个问题:需要绘制一个自适应文本的写作网格线,设计稿是这样的。

图片

写作网格

其实就是一行行虚线,要求如下:

  1. 虚线的纵向间隔要跟随行高自适应,确保文本在每一栏虚线上。
  2. 虚线后面的背景是动态的,可以是纯色,可以是渐变,也可以是图片。

绘制这样的虚线,看似容易,其实暗藏玄机,下面一起看看有哪些实现方式吧。

一、纯色背景下的虚线

首先来看这种简单情况,大可以通过两层渐变覆盖的方式实现。

假设文本行高是2,先绘制水平方向的。

body{
background: linear-gradient(#666 1px,transparent 0) 0 -1px/100% 2em;
}

注意,这里的背景尺寸是100% 2em,高度跟随文字行高,所以高度是2em,效果如下:

图片

然后,绘制纵向的实线,盖在上面,为了区分,先用一个浅红色来代替。

body{
background: linear-gradient(to right, #ffdbdb 4px,transparent 0) 0 -4px/8px 100%, /*垂直*/
linear-gradient(#666 1px,transparent 0) 0 -1px/100% 2em; /*水平*/
}

这样就绘制了一个垂直平铺,间隔为4px的虚线,效果如下:

图片

应该比较好理解吧,就是两个方向上的渐变叠加。

然后,将这个红色改成和底色相同的颜色就行了,比如这里是白色。

body{
background: linear-gradient(to right, #fff 4px,transparent 0) 0 -4px/8px 100%, /*垂直*/
linear-gradient(#666 1px,transparent 0) 0 -1px/100% 2em; /*水平*/
}

这样就实现了纯色下的虚线网格,效果如下:

图片

二、渐变背景下的虚线

如果不是纯色,而是渐变的呢?假设有一个这样的背景。

图片

如果直接用前面的方式,可能就变成了这样。

图片

白色直接把背后的渐变背景也覆盖了。

那如何解决这个问题呢?

像这种叠加混合的情况一般都会想到混合模式,没错,这里也可以通过混合模式简单处理。要用混合模式,必须要让这两层背景处于不同的容器中,然后使用mix-blend-mode。

html{
background: linear-gradient(45deg, #f5ffc0, #fff);
}

body{
font-size: 20px;
background: linear-gradient(to right, #fff 4px,transparent 0) 0 -4px/8px 100%, linear-gradient(#666 1px,transparent 0) 0 -1px/100% 2em;
mix-blend-mode: darken;
}

这里使用了混合模式中的darken,这种模式可以去除白色部分,保留其他,效果如下:

图片

完整代码可以查看以下任意链接:

  • CSS dot line mix-blend-mode (juejin.cn)[1]
  • CSS dot line mix-blend-mode (codepen.io)[2]
  • CSS dot line mix-blend-mode (runjs.work)[3]

三、通过锥形渐变绘制

下面再介绍一个比较硬核的绘制方式:锥形渐变(conic-gradient)[4]。

为什么说比较硬核呢?因为这种方式绘制出来的图形就是完完全全的虚线,也没有混合模式的诸多限制。

首先我们从图形上分析,找到最小的重复单元,如下:

图片

找到了,就是这个,其实就是这个位于左上角的矩形,那么,如何通过锥形渐变来绘制呢?

注意:有同学可能会奇怪,这样一个矩形线性渐变不是可以很轻松的实现吗?确实可以,但是只能实现一个,无法平铺

看着好像不沾边,下面带你一步步演变。

首先是最原始的语法。

div{
background: conic-gradient(#666, transparent);
}

这是一个从透明到灰色的渐变,效果如下:

图片

这才是锥形渐变的样子!

然后,我们可以将渐变的分界线调整一下。

div{
background: conic-gradient(#666 90deg, transparent 0deg);
}

这样就变成了一个边界分明的正方形。

图片

然后改变起始角度,通过from关键词。

div{
background: conic-gradient(from 270deg, #666 90deg, transparent 0deg);
}

这样起始角度就会从270deg的地方开始,如下:

图片

接着,改变中心点的位置,默认是水平垂直居中的,我们要改到左上角,需要用到​​at​​关键词

div{
background: conic-gradient(from 270deg at 40px 10px, #666 90deg, transparent 0deg);
}

这里改成了左上角40px,10px的地方,如下:

图片

最后,改变背景的尺寸,默认是宽高100%的,我们要改成实际需要的大小。

div{
background: conic-gradient(from 270deg at 40px 10px, #666 90deg, transparent 0deg);
background-size: 80px 90px;
}

这样就会自动平铺展开,如下:

图片

原理就是这样,实际上的虚线比较小,应该是4px 1px,所以实际应用应该是这样。

div{
background: conic-gradient(from 270deg at 4px 1px, #666 90deg, transparent 0deg);
background-size: 8px 2em;
}

效果如下:

图片

完整代码可以查看以下任意链接:

  • CSS dot-line conic-gradient (juejin.cn)[5]
  • CSS dot-line conic-gradient (codepen.io)[6]
  • CSS dot-line conic-gradient (runjs.work)[7]

四、动态SVG背景绘制

最后再来介绍一个实现起来最容易的方式,就是“切图”。

但是,这种“切图”不同于一般的切图,因为这个尺寸是动态的,要跟随文字的行高变化而变化,所以需要采取一定的“手段”。

首先在绘图软件中绘制这样一个图形,例如下面是figma中绘制的。

图片

外面的宽高无所谓,随便设置。可以得到这样一段SVG。

<svg width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="10" height="10" fill="none"/>
<rect width="5" height="1" fill="#D9D9D9"/>
</svg>

然后,我们将这个svg转换成内联 CSS格式。

推荐张鑫旭老师的在线转换工具:SVG在线压缩合并工具[8]。

直接用到背景上。

body{
font-size: 20px;
background: url("data:image/svg+xml,%3Csvg width='10' height='10' viewBox='0 0 10 10' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0h10v10H0z'/%3E%3Cpath fill='%23D9D9D9' d='M0 0h5v1H0z'/%3E%3C/svg%3E") 0 0/10px 2em;
}

效果如下:

图片

为啥这里的虚线都错位了呢?

这也是 SVG不同于常规图片的一点,在外部背景尺寸超过viewbox尺寸后,SVG 画布会整体缩放,但是具体的元素并不会,具体表现是这样的。

图片

那么,有没有办法在画布缩放的时候,里面的元素仍然位于左上角呢?就像这样

图片

当然也是可以的,只需要将viewbox改为0 0 100% 100%就行了,或者干脆删除(默认就是100%),SVG的宽高也要改成100%,如下:

<svg width="100%" height="100%" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="10" height="10" fill="none"/>
<rect width="5" height="1" fill="#D9D9D9"/>
</svg>

这样一来,不管背景尺寸如何变化,内部的虚线位置都不受影响,效果如下:

图片

完整代码可以查看以下任意链接

  • svg dot-line (juejin.cn)[9]
  • svg dot-line (codepen.io)[10]
  • svg dot-line (runjs.work)[11]

除了上面这种方式,还可以换一种思路,让默认的虚线是居中的,这样在放大后也是居中的,如下

图片

这样在不改变viewbox的情况下也能实现相同的效果,有兴趣的小伙伴可以下去试一试。

五、总结一下优缺点

以上共介绍了 3 种完全不同的绘制虚线的方式,原理各不相同,也有各自的优缺点,下面总结一下。

CSS 渐变混合模式的优点在于实现思路比较简单,很容易想到,纯色背景优先推荐,缺点是混合模式有一些局限性,比如在黑色背景下可能需要换一种模式了。

CSS 锥形渐变的优点在于代码实现简单,不受结构限制,缺点是有点不好理解,还有就是兼容性稍微差一些。

SVG 自适应背景的优点在于使用简单,基本等同于“切图”,缺点是需要掌握 SVG 的特性,而且无法直接通过 CSS 改变颜色,只能换图。

综合来讲,如果兼容性没有要求,首推第2种方式,其次是 SVG 方式,最后才是混合模式。

参考资料

[1]CSS dot line mix-blend-mode (juejin.cn): ​https://code.juejin.cn/pen/7185780439276060730。​

[2]CSS dot line mix-blend-mode (codepen.io): ​https://codepen.io/xboxyan/pen/ExpNBPr。​

[3]CSS dot line mix-blend-mode (runjs.work): ​https://runjs.work/projects/a0ec6e9e89f943a2。​

[4]锥形渐变(conic-gradient): ​https://developer.mozilla.org/en-US/docs/Web/CSS/gradient/conic-gradient。​

[5]CSS dot-line conic-gradient (juejin.cn): ​https://code.juejin.cn/pen/7185788769595818042。​

[6]CSS dot-line conic-gradient (codepen.io): ​https://codepen.io/xboxyan/pen/GRBNbEN。​

[7]CSS dot-line conic-gradient (runjs.work): ​https://runjs.work/projects/dc01e87b2c62426b。​

[8]SVG在线压缩合并工具: ​https://www.zhangxinxu.com/sp/svgo/。​

[9]svg dot-line (juejin.cn): ​https://code.juejin.cn/pen/7185803705722077219。​

[10]svg dot-line (codepen.io): ​https://codepen.io/xboxyan/pen/eYjBwxa。​

[11]svg dot-line (runjs.work): ​https://runjs.work/projects/c725bbf1830743b6。​

责任编辑:姜华 来源: 前端侦探
相关推荐

2023-12-04 09:31:13

CSS卡片

2010-09-07 16:31:27

CSS

2022-03-16 14:27:49

CSS三角形前端

2012-07-17 09:16:16

SpringSSH

2021-02-28 07:42:40

可视化网格线H5-Dooring

2010-09-02 16:26:59

CSS命名

2021-06-24 08:52:19

单点登录代码前端

2019-11-20 18:52:24

物联网智能照明智能恒温器

2021-11-05 21:33:28

Redis数据高并发

2014-12-31 17:42:47

LBSAndroid地图

2020-11-01 17:10:46

异步事件开发前端

2010-03-12 17:52:35

Python输入方式

2024-07-31 20:38:18

2010-09-14 15:10:49

CSS注释

2024-07-08 09:03:31

2023-09-11 09:07:58

CSS隐藏滚动条

2010-09-13 12:19:03

2021-11-26 11:07:14

cowsay命令Linux

2010-08-24 09:43:33

2009-07-29 09:36:07

无线通信接入方式
点赞
收藏

51CTO技术栈公众号