龙喵专栏 /前端 /内容

《精通CSS》第4章 网页排版

版权声明:龙喵网!!!网站网址:http://ailongmiao.com

或许大家会觉得排版都是设计师的工作,前端开发按照已经排版好的设计稿复原就行。当然,这样理解也没有太大问题,但是过于依赖于设计师往往会限制我们的脚步。作为前端开发,对于排版我们要有自己的认知,而且更好地理解 CSS 中关于网页排版的技术,我们也能更得心应手地还原设计稿。

本章原书用了近 40 页的篇幅来介绍排版,歪马会尽量精简地将其中的核心内容传达给大家。

同原书,借助维基百科中一篇关于月亮的文档来给大家介绍排版。分别包括以下几部分内容:

  1. 基础排版:包括文本颜色、字体相关、间距、对齐、折行连字符等
  2. 文本特效
  3. 多栏布局
  4. 更丰富的字体:Web 字体
  5. 高级的排版特性:OpenType

其中比较推荐大家关注的点有对于行盒子构造的理解、连字符的使用、Web 字体的使用以及 OpenType 新排版特性

示例代码托管在CodeSandbox

4.1 基础排版

如下图所示,我们没有应用任何样式时,网页也并没有很糟糕,还是可读的,主要是因为浏览器应用了一些默认的样式。

初始文档-未应用样式

下面我们开始逐步美化这一文档,在这个过程中,歪马不会挨个贴出效果图,这样太浪费篇幅了,有兴趣的同学可以自己动手跟着试一试。下面先看一下完成版的效果图。

完成效果图

4.1.1. 文本/背景颜色

首先我们可以微调一下文本的颜色。默认情况下,浏览器会将文字渲染成黑色(链接为蓝色),背景为白色,白底黑字有时候太过与显眼。我们可以调整下字体颜色/背景颜色,使其看起来更柔和。

如下:

body { background: #f6fafc; }
p { color: #3b4348; }
a { color: #235ea7; }

4.1.2. 字体族

第二步可以给文档应用我们喜欢的字体。可以借助font-family字体族属性,该属性的值是一个备选字体的列表,按优先级从左到右排列。如下:

body {
  font-family: 'Georgia Pro', Georgia, Times, 'Times New Roman', serif;
}
h1, h2, h3, h4, h5, h6 {
  font-family: Avenir Next, Avenir, SegoeUI, arial, sans-serif;
}

由于font-family是一个可继承属性,所以body及其后代元素在使用字体时,浏览器会依次从左向右判断字体是否存在,存在则使用,一直到都不匹配时,随机选择一种衬线字体(serif)。

这种按照顺序查找字体的后备机制是font-family的重要特性,因为不同的操作系统和移动设备中包含的字体并不一样。关于什么操作系统中默认安装了哪些字体,可以通过这个网址查询:www.cssfontstack.com

上面代码中的最后一种备选字体(衬线字体)是通用字体族的一种。通用字体族共有以下几种:

  • serif 衬线字体:字形笔画末梢带有装饰性的线条,很多经典的英文字体都有。
  • sans-serif 非衬线字体:与衬线字体对应,字形笔画末梢没有装饰性的线条。
  • monospace 等宽字体: 每个字符的宽度一样,不同行之间的字符可以完美对齐,常用于显示代码。
  • fantasy 花式字体:顾名思义,就是比较花花绕的字体。
  • cursive 手写字体:手写字体。

歪马将 Orbit 轨道部分的两个段落分别应用的fantasy花式字体和cursive手写字体,大家可以感受下。Safari 下效果比较显著,所以该图是 Safari 下的截图。如图:

花式字体与手写字体

最后,如果字体族的名称包含空格,引号并非非加不可,但最好加上。规范中只要求与通用字体族重名的字体族需要加引号,但同时也建议给包含非标准符号的名称加引号,从而防止浏览器误判。

4.1.3. 字体大小与标题行外边距

几乎所有浏览器中,font-size的默认大小都是16px,除非主动修改。

在这里,我们不修改默认的font-size,在设置指定元素的font-size时,推荐使用em,如下:

h3 {
  font-size: 1.314em; /* 21px */
}

使用em比较灵活,em单位是基于继承的字体大小进行缩放的。所以当我们修改默认的font-size大小时,相应的元素大小也会随之调整。

不过这样做会有一个问题,元素的位置会意外改变其字体大小。试想如下代码:

p {
  font-size: 1.314em;
}
article {
  font-size: 1.314em;
}

particle元素默认情况下字体大小是21px,但article下的p元素的字体大小会变成1.314em × 1.314em,约等于1.73em(28px)

对于font-size属性,可以用百分比代替em。如131.4%1.314em没有区别,可以任意选择。

em用于计算盒模型大小时,不是基于继承的font-size,而是基于元素自身计算后的font-size

如上em的计算规则会因为应用属性的不同而不同。我们还可以rem,它也是一个缩放因子,它是相对于根元素的字体大小进行缩放的。

rem较新,但所有现代浏览器均已支持,只有 ie8 及更早的浏览器不支持。为了兼容,我们可以如下为标题元素声明统一的上外边距:

h1, h2, h3, h4, h5, h6 {
  margin-top: 24px; /* 针对老旧浏览器不能缩放的后备 */
  margin-top: 1.5rem;
}

书中推荐使用em/rem这两个缩放单位,其他的长度单位,如mm/cm/in/pt这些绝对物理长度,这些是给打印样式准备的,网页样式不应该使用这些单位

4.1.4. 行高与垂直对齐

要像彻底了解行高与垂直对齐。我们需要先了解下行盒子的构造。构造如下图(书中图 4-5),大家可以仔细看看各部分的含义。

行内格式化模型的构造及相关概念

对应代码是:

<p>The <strong>Moon</strong>...</p>

关于行内格式化上下文,我们知道每行文本都会生成一个行盒子,这段代码中,行盒子内包含行内盒子(strong元素)以及前后的匿名行内盒子。

内容区用于显示文本,用font-size决定高度。行高是行盒子的总高度,内容区上下的空白部分叫做半铅空(因为传统印刷时用铅块隔开的)。

其中,每个字符在摆放的时候,底边都是对齐于靠近底部的一条水平线,这条线叫做基线。内容区并不会完全限制字符的显示,比如某些字体中g就会超出内容区。

最后,如果行盒子内有多个行高不等的行内盒子,则行盒子最后的高度至少等于最高的。至于为啥是至少,还和垂直对齐的方式有关,下面说垂直对齐的时候就知道了。

1. 设置行高

一般来说,行高的取值范围是1.2~1.5。行与行之间不能太密也不能太疏。

如下,我们可以给body设置line-height: 1.5;

body {
  line-height: 1.5;
}

没有单位的行高,表示是当前字体大小的 1.5 倍。当然我们也可以给line-height设置像素、百分比或em值。但要注意的是,在元素继承的时候,继承的是计算后的值。这就会导致如果我们在body上设置1.5em,其他元素继承的并不是1.5em,而是24px。这显然不是我们想要的。

好在line-height设置为没有单位的值时并不会出现这一现象,子元素继承的永远都会是这个数值。

2. 垂直对齐

垂直对齐vertical-align的默认值是基线对齐baseline,即子元素的基线与父元素的基线对齐。它还有很多很有意思的值如:suptopbottomtext-toptext-bottommiddle,还可以设置像素值、em以及百分比。

如下图所示,红框中的文字分别应用了不同的 vertical-align 值,字面文字即为属性值。

vertical-align不同值对应效果

其中text-toptext-bottom会让当前元素的内容区和父元素的内容区顶部或底部对齐,但只有在行内盒子的 font-size 或 line-height 与父元素不同时才有影响。

从图中,我们还能看出,当使用 vetical-align 调整元素位置时,会扩展行盒子的高度。这也是我们前面为什么说:“当行盒子内有多个行高不等的行内盒子时,行盒子最后的高度至少等于最高的”。

最后,需要提一下,与行内文本相比,行内块和图片的垂直对齐行为稍有不同,因为图片不一定有自己的唯一基线。第 6 章的时候会介绍。

4.1.5 文本粗细(字重)

下面,我们可以使用font-weight给不同的标题指定不同的文本粗细,也称字重。font-weight支持关键字normalboldbolderlighter,也可以指定数字值,都是 100 的倍数,100~900.

默认值为normal,对应数字 400,bold对应 700。关键字bolderlighter是在继承值的基础上把文本变得更粗或更细。

如下,我们给标题设置字重 500,h1 和 h2 分别是 800 和 600:

h1, h2, h3, h4, h5, h6 {
  font-weight: 500;
}
h1 {
  font-weight: 800;
}
h2 {
  font-weight: 600;
}

如果指定的粗细不存在,浏览器尽量模拟,但是效果不会很好。

4.1.6 字体样式

font-style除了normal外还有两种样式,分别是italicobliqueitalic会选择字体的斜体变体来显示,如果不存在,浏览器会通过倾斜字体来模拟,但是效果不太理想。oblique也是倾斜文本的一种变体,但是没有几款字体支持,所以很少使用。

4.1.7 文字变换

CSS 中有两种文字变换,分别是text-transformfont-variantfont-variant更准确的说是字体的一种变体,需要字体支持。

text-transform可以控制英文字母大小写。uppercase可以将所有字母显示为大写,lowercase可以将所有字母变成小写,capitalize可以将每个单词的首字母大写,none显示源码中的默认大小写。

如下,我们可以将h1元素中的字母全部大写。

h1 {
  text-transform: uppercase;
}

font-variant是字体的特殊变体,需要字体支持。如small-caps可以把英文文本转换成所谓的“小型大写字母”。我们可以将文档中 NASA 缩写进行这一变化。不过文中 NASA 已经是大写了,所以我们还加了text-transform: lowercase;将其转换为小写字母;此外由于 small-caps 会导致某些浏览器把内容盒子向下移动一点,所以缩小了一下行高。

abbr {
  font-variant: small-caps;
  text-transform: lowercase;
  line-height: 1.25;
}

效果图如下:
small-caps效果

CSS2.1 中,只规定了small-caps这一个有效值。CSS Font Modules Level 3 扩展了很多,后面高级排版技术我们再介绍。

4.1.8 字间距和词间距

word-spacing可以调整单词与单词之间的距离。letter-spacing可以调整字母与字母之间的距离。

通常情况下,我们无需做字间距和词间距的调整。如果设计师有特殊需求时,我们可以进行相应的调整。

4.1.9 行长

我们都知道,每一行文字的多少(也就是行长),对于阅读体验有着重要的影响。过长或过短的文本行会打断人的眼球移动,导致读者无法连续阅读,甚至读不下去。

书中建议主体内容的文本行长通常是 45-75 个字符,平均 66 个字符。对于小屏幕也要有至少 40 个字符。

所以,我们可以直接给article元素设置如下属性。这里推荐使用max-width,好处是当时候屏幕比这个更窄时可以自动调整。

article {
  max-width: 33em;
}

4.1.10 缩进与对齐

接下来,我们可以调整一下缩进与对齐。对于段落,我们可以设置一定的缩进,方便用户定位新段落的起始,这个在中文排版中比较常见。

p {
  text-indent: 1.25em;
}

另外,我们会发现段落的右边参差不齐,这种样式叫做“毛边”。这是因为文本默认是左对齐的。

text-align有以下几个值:left|right|center|justifyleft|right|center三个值都会存在毛边。其中比较适合给短标题应用center(我们给h1应用一个)。justify可以再单词间平均分布间距,实现左右两端对齐,消除毛边。但是当某些行空白太多,会出现空白“串流”的现象,并且行长越短越明显。如下图所示。

justify空白串流

这主要是因为浏览器处理文本两端对齐时使用的算法较为粗糙,虽然我们可以通过text-justify来修改算法,但浏览器的支持度较差,效果也不太好。

此外,text-align新增了start|end两个新的值,这两个值与文本书写方向对应。如果dir="ltr"文字书写方向是从左到右,则start为左,end为右;反之同理。

4.1.11 连字符

如果又想解决毛边问题,又不想出现串流问题。我们可以在 HTML 中手动插入连字符的实体符号&shy;只有当浏览器需要断词换行是才会显示这个连字符

但是这个方式想想就不可能是吧。谁会没事手动插入连字符,行长变了咋办?

好在我们可以使用hyphens属性来让浏览器帮我们插入连字符。该属性有两个值auto自动和manual手动。

但是这个属性较新,很多浏览器都不支持,部分需要加前缀,大家可以自行在Can I Use上查询一下。支持度不好没事,别忘了我们前面提到的渐进增强,这是一个可以提高体验的优化方案,所以我们可以照用不误。

不过想要使用自动连字符功能,一定要在 HTML 中设置语言代码<html lang="en">

连字符的效果如下图所示:
连字符效果

4.2 文本特效

“标题党”总是能够更抓人眼球,赚取更多的点击。见惯了标题党小伎俩的我们可能早就不吃这一套了。不过,今天我们也要给大家说一说标题党。但是此标题党非彼标题党,我们是要让你的标题看起来更炫更酷。

我们可以借助text-shadow文本阴影来实现很好看的标题特效。给大篇幅的正文文本应用阴影不仅不会更炫,反而会降低可读性。阴影更适合标题或短文本,我们可以用其模拟凸版印刷或喷涂效果。

text-shadow的语法格式为<offset-x> <offset-y> <blur-radius> <color>,如1px 1px 5px 0,其中颜色值放在最前或者最后都行。offset-x/offset-y是 x/y 轴的偏移量(可正可负);blur-radius为模糊半径,0 表示完全不模糊;color为颜色,如果不传颜色,默认为黑色。

此外,我们还可以用逗号分隔来应用多组阴影,多组阴影会按照先后顺序堆叠,先定义的在上,后定义的在下

如下,我们可以给h1标题应用如下样式:

h1 {
  text-shadow: -2px 2px 0 goldenrod,
                  0px -2px 0 goldenrod,
                  0px 3px 0 goldenrod,
                  3px 0px 0 goldenrod,
                  -3px 0px 0 goldenrod,
                  2px 2px 0 goldenrod,
                  2px -2px 0 goldenrod,
                  -2px -2px 0 goldenrod,
                  -3px 3px 0 #233956,
                  -4px 3px 0 #3568A8,
                  -4px 5px 0 #233956,
                  -5px 4px 0 #3568A8,
                  /* ...省略部分 */
                  -13px 12px 0 #3568A8,
                  -13px 14px 0 #233956,
                  -14px 13px 0 #3568A8,
                  -14px 15px 0 #233956,
                  -15px 14px 0 #3568A8,
                  -15px 16px 0 #233956,
                  -16px 15px 0 #3568A8;
}

效果如下:
h1标题文字特效

文本阴影是一门很深的学问,需要对齐不断尝试,充分发挥才能创造出更多有意思的效果。Typekit Practice 的Using shades for eye-catching emphasis一文有更多的类似技术,大家感兴趣可以看一下。

4.3 多栏布局

第一部分我们把整篇文章的行长设置为了33em,但是如果在较大的屏幕下,仅仅只有33em的行长可能会浪费很多空间。有时候为了有效利用宽屏,我们可以使用多栏布局。

多栏布局主要包括以下几个属性:

  • column-gap: 栏间距,值为长度值
  • column-count: 栏数,值为数字
  • column-width: 栏宽,值为长度值
  • column-span: 是否跨栏,all开启跨栏,none关闭跨栏。
  • column: column-countcolumn-width的简写形式。

如果只设置column-count,浏览器会严格生成指定数量的栏,不管宽度如何。如果同时设置了column-countcolumn-width,则前者会作为最大栏数,后者会作为最小栏宽,也就是说优先保证栏宽,如果不够栏数减少也没关系。

如下,我们可以这样进行多栏布局。

/* 一级标题和来源跨行 */
h1,
.source {
  column-span: all;
}
/* article指定最大宽度,栏数自动生成 */
article {
  max-width: 70em;
  columns: 20em;
  column-gap: 1.5em;
}

效果如下图所示:
多栏布局

最后对于不支持多栏布局的浏览器,我们要实现优雅降级,可以给段落元素应用max-width属性,限制行长的最大宽度。这样,旧版浏览器只会显示一栏,但仍然可读。

article > p {
  max-width: 33em;
}

不知道你有没有注意到,上面的效果图中,三栏中的文本基线已经没有对齐的(对着上图你看,你细细地看)。这主要是因为标题高度导致的问题。这一问题会一定程度地影响阅读。我们可以通过修改标题的高度,让其等于段落文本的整数倍,从而使得各栏文本的基线均对齐,这种方法叫做垂直律动

如下,对标题做如下调整。让两个标题的上下边距加行高等于正文行高的整数倍。如此,所有栏的文本基线就都能对齐了。

h2 {
  font-size: 1.75em; /* 28px */
  line-height: 1.25; /* 28*1.25 = 35px; */
  margin-top: 1.036em; /* 29px */
  margin-bottom: 0.2859em; /* 8px */
}
h3 {
  font-size: 1.314em; /* 21px */
  line-height: 1.29; /* 21*1.29 = 27px; */
  margin-top: 0.619em; /* 13px */
  margin-bottom: 0.38em; /* 8px */
}

最后,h1 的高度是 72px,h2 的高度是 48px,刚好是正文行高的整数倍,如下图所示,所有栏的正文都对齐了。

多栏文本应用垂直律动

4.4 更丰富的字体:Web 字体

前面介绍的内容中,多数都是使用系统自带的字体。其实我们也可以使用自定义的字体。

相信大家对于 Web 字体一定不会陌生,大家一定都用过一些 Icon Font 相关的字体,如阿里的iconfont.cn,这类字体也是 Web 自定义字体的一种。

我们可以通过@font-face规则来声明自定义的字体。它可以指定浏览器下载字体的地址以及如何在样式表中引用字体。

@font-face {
  font-family: Vollkorn;
  src: url('fonts/vollkorn/Vollkorn-Bold.woff') format('woff');
  font-weight: 800;
}

目前现代浏览器基本都支持 Web 字体,但对于文件格式的支持却并不统一。字体格式的问题很复杂,涉及微软、苹果以及 Adobe 等公司的发展史,此处我们不做详述。为了保证各个浏览器可用,我们通常需要补足各种字体文件的格式,如WOFFWOFF2SVGEOTTTF

如下:

@font-face {
  font-family: Vollkorn;
  src: url('fonts/vollkorn/Vollkorn-Bold.eot#?ie') format('embeded-opentype'),
         url('fonts/vollkorn/Vollkorn-Bold.woff2') format('woff2'),
         url('fonts/vollkorn/Vollkorn-Bold.woff') format('woff'),
         url('fonts/vollkorn/Vollkorn-Bold.ttf') format('truetype'),
         url('fonts/vollkorn/Vollkorn-Bold.svg') format('svg');
  font-weight: 800;
}

如果你只有其中一种字体格式,可以通过Font Squirrel进行转换。

4.4.2 字体描述符

@font-face规则中接受以下几个声明,又称字体描述符:

  • font-family: 必需,使用该字体时字体族的名称。
  • src: 必需,URL 或 URL 列表(逗号隔开),用于下载字体。
  • font-weight: 可选,字体粗细,默认为normal
  • font-style: 可选,字体样式,默认为normal

浏览器在匹配字体时优先匹配font-family,如果存在font-family对应的字体则应用。如果对应字体声明了多次,如font-weight不同,分别为boldnormal,那么就会在字重不同的时候应用不同的字体。如果只声明了一次,则不管什么字重都应用该字体。font-style同理。

4.4.3 性能

Web 字体让网页有了更多的可能性,但也带来了一些问题。

首先,浏览器需要下载额外的字体文件,这会延长用户等待的时间。所以我们一方面要注意不要加载过多字体,另一方面要对字体文件做缓存,从而避免不必要的网络开销。

此外,对于非文档类的网站,如果字数有限,可以通过字体截取的功能来减小字体文件的大小。这一点对于中文字体来说尤为重要,因为中文字体动辄就是几十兆,通过截取的方式可以大大减小字体文件的大小。大家可以通过字蛛来进行字体截取,也有一些根据网页内容动态截取的解决方案,大家有需要的话可以找一找。

其次,除了额外的加载,浏览器在下载字体的时候,有两种方式处理相应的内容。第一种方式是在下载完成前,暂缓显示文本,这就会导致在下载完成之前,用户什么都看不到,这种现象叫做FOIT(flash of invisible text)。Safari、Chrome 和 IE 默认采用这种方式,如果网速很慢的话,用户体验会很差。

第二种方式,是在字体下载完成前,浏览器先用一种后备字体作为替代显示。可以避免网速慢导致的页面空白问题,但是也会带来新的问题——字体切换时的闪烁,这种现象叫做FOUT(flash of unstyled text)。这种闪烁会影响用户阅读,如果内容差距较大还会导致失去焦点,所以我们尽量选择较为相似的字体作为后备字体。

4.4.4 JavaScript 加载字体

CSS Font Loading规范定义了一个用于加载字体的实验性 JavaScript API,但是尚未得到浏览器的广泛支持。不过 Typekit 维护了一个开源库可以让我们有类似的能力来操作字体,叫Web Font Loader

这里我们简单介绍一下这个库的原理。Web Font Loader 主要暴露了以下三个事件:

  • loading: 开始加载字体
  • active: 字体加载完成
  • inactive: 字体加载失败

我们可以做的事情就是如果字体成功加载了,可以给根元素添加一个特殊的类名,这样就可以给自定义字体和后备字体定义不同的样式了。通过细微的调节,可以让两种字体切换时的闪烁感降到最低,如将行高调整一致,对于 x 高度不一致的字体调整字体大小等。

4.5 高级的排版特性:OpenType

前面我们知道了如何使用更丰富的字体。那么我们可能会应用一些具有丰富特性的字体。在有些 OpenType 字体格式中支持在字体文件中包含字体的额外设定和特性,包括连字(ligature,由字符组合而成的特殊字形,如“fi”或“ffl” ),字距(kerning,调整特定字母组合的间距),分数形式,数字风格等。使用这些特性可以使我们的网站更有用、更易读、更优美。

那么一款 OpenType 的字体到底有哪些特性呢?我们可能是一脸懵逼的,我也不是字体的设计者,我怎么知道某款字体有没有某种特性呢?好在已经有前人为我们解决了这一麻烦。我们可以通过wakamaifondue.com这一网站来查看字体功能、特性的相关内容。

如下,我们将书中的示例字体Vollkorn Semibold传入上述网站,可以看到解析结果中如图中蓝框所示的特性。

Vollkorn Semibold字体特性

CSS 里定义了很多与这些特性相关的属性如连字的font-variant-ligatures、字距font-kerning、数字风格font-variant-numeric等。但这些属性支持度并不好,不过我们可以使用底层属性font-feature-settings来控制。建议大家两种同事使用。

如下,我们可以像这样设置字体特性(示例中是开启了常用连字和任意连字):

h1, h2, h3 {
  font-variant-ligatures: discretionary-ligatures;
  -webkit-font-feature-settings: "liga", "dlig";
  -moz-font-feature-settings: "liga", "dlig";
  -moz-font-feature-settings: "liga=1, dlig=1";
  font-feature-settings: "liga", "dlig";
}

连字的效果大概像下面这个样子,大家应该都能理解。

连字的效果

稍微解释一下font-feature-setting的语法,其语法格式为font-feature-setting: <feature-code>;。主要有以下几点细节:

  • 可以通过加引号的 4 个字符的特性代码开启相应的字体特性,代码后可接关键字on/off,分别表示开启或关闭,也可以接一个数字。如果不指定则默认是on
  • 如果只为数字,0 一般表示关闭特性。如果特性只有开关两个状态,则 1 为开启;如果有多个状态,则根据字体来选择对应的数字。
  • 多个特性之间用逗号隔开。
  • 不同浏览器的浏览器可能需要加前缀(这个不用手动加,建议使用 CSS 预处理器)。其中 Mozilla 浏览器的旧语法有一些不同,多个特性是写在一个引号内的,如上代码中所示。

下面我们看下数字的效果。文本段落中的“老式”数字风格和小写字母搭配更合适;“表格数字”在表格里的费用清单里排列得更整齐;而“线性”数字单独使用或与大写单词搭配使用显得更为统一。分别如下面两图所示。

Vollkorn字体中的线性数字(上)与老式数字(下)

Alegreya Sans的表列线性数字,右侧的价格宽度不同,但是垂直对齐

OpenType 相关的特性有很多,而且受到字体的影响,本文就不再做详细的介绍了,大家对于这一概念有一个整体的了解就好。后续歪马有空会整理一篇完整的 OpenType 特性相关的文章。

另外,因为中文的特殊性,中文字体往往也不具备这些特性,所以不感兴趣的同学可以先行略过。当然数字相关的我们还是会用到的。

4.6 总结

好了到这里,本章的陪读分享就结束了。

本章主要是逐步带大家对于关于月亮的文档进行了排版,包括基础的排版、文本特效以及满足宽屏的多栏布局。然后介绍了如何使用 Web 字体以及 OpenType 字体的特性应。

版权声明:龙喵网!!!网站网址:http://ailongmiao.com

作者:歪马

来源:掘金:https://juejin.im/post/5e34e6d451882536c964f45b

1.部分文章来自网络,如有侵犯权益,请联络博主,资源失效与内容勘误留言说明.

2.如若转载,请注明出处:https://ailongmiao.com/read/913.html

[ web前端导航 ]:https://ailongmiao.com/web/

评论

继续阅读

  选择打赏方式

打赏

打赏