你不知道的Markdown基础知识
目前很多Markdown语法说明只介绍了Markdown具体语法的使用,而本文主会介绍一些普通教程里提及不多的知识。所以,在阅读之前,你应该掌握最基础的Markdown语法。
Markdown的组成与结构
组成Markdown正文的元素可以分成区块元素和行内元素。
简单说,区块元素主要用来定义内容、提供框架,如标题、列表、段落等。而行内元素主要提供实质内容,如图片、文字等。
就好比一个表格(区块元素),我们需要用文字、图片(行内元素)来填充它。
我们可以将一份Markdown文档看成一系列连续的区块元素(包括段落、区块引用、列表、标题、分割线、区块代码等)的纵向排列,部分区块(如引用和列表)可以包含其他区块,而其他的区块(如标题和段落)则包含行内元素,如文本、链接、图片、行内代码等等。
——翻译自 commonmark.org
段落、文本行、换行
段落与行的概念在Markdown中虽然很基础,但是很重要。可惜很多Markdown的教程(特别是国内教程)都将其忽略。
一个文本行指连续两个换行之间的内容,并非指最终显示所看到的行。简单说,手动换行才叫一行,自动换行形成的不叫一行。
段落由一个或多个连续文本行组成,两个段落间由空行分开。
当一个段落需要包含该多个文本行时,需要先在行末敲入两个或以上空格再回车。不过目前很多编辑器可以直接敲回车换行。
知道这些有什么用?可以用来调整文档的疏密。段落间的间距比较宽,如果希望文档密一点,多使用强制换行;如果希望文档优雅整齐一点,可以多用段落。
区块元素的相接
前面说过,一份Markdown文档看成一系列连续的区块元素的纵向排列。所以一份Markdown文档的结构基本是由区块元素决定的。而区块元素之间的关系有两种——首尾相接与嵌套。
原生的Markdown只规定了段落间需要空行,没有规定其他的区块如何相接。我们往往会想当然的认为其他区块直接换行相接就可以了。但是真的是这样吗?
其实,不同区块间有不同的规则,不同的编辑器也有不同的相接规则。这是几乎所有编辑器共有的现象。所以,区块相接存在着严重的方言问题。
但是,它们也有一些规则是通用的:
有明确开始标识和明确结束标识的区块可不用空行。当我们回头看原生Markdown语法设计的时候,会发现虽然Markdown也是一种轻量级的标记语言,可是基本所有区块元素只有开始标识(比如引用使用>开始,无序列表使用*、+或-开始),却没有结束标识,这种区块的结束就取决于下一个区块或空行,不同的编辑器或产生不同的结果。但是后来加入的部分语法开始使用包裹式的标识,比如区块公式使用$$包裹,这些区块就有着明确的结束标识。当像这样有着明确开始标识和结束标识的区块相接时,一般编辑器都不会出现差异,所以可以不用空行,直接换行相接。分割线与标题后接区块可以不空行。分割线与标题占用的行数比较固定,只有一行或两行,其后可以直接换行接任何区块元素。区块引用和列表后接其他区块必须空行。区块引用和列表与其他区块不同,它们可以嵌套区块,而且有lazy输入(懒人输入,回车直接沿用上方样式),所以必须用空行区分。使用减号-画分割线时,前面必须预留一空行。因为连续三个减号—这个语法与Setex式标题(底线式标题)语法重合了,不留空行容易造成识别错误。如果不想使用预留空行,也可以在减号内加空格,如- - -,以避免与Setex标题语法重合。空白HTML标签的使用。这个标签其实很少会用到,一般只在带lazy输入的区块连续出现的时候用于分割区块。目前允许lazy输入的区块有:区块引用、缩进式代码、列表。空白HTML标签不会再最后的输出中显示,所以用来写备注也是可以的。 区块元素的嵌套
区块元素中引用和列表可以实现区块的嵌套,我们将其称为可嵌套区块。
当我们说嵌套的时候,并非只指自身的嵌套,而是说可以嵌套基本所有类型的区块。
1. 引用的嵌套
引用的嵌套相对简单,只要所有的嵌套内容每行行首加上>,跟写简单的文字引用一样,只不过每一行都加>而已,多级嵌套就多加几个>。
示例:
> 段落1行1
> 段落2行2
>
> ---
> 段落2
>
> > 二级引用
效果:
段落1行1
段落2行2
段落2
二级引用
引用的嵌套,在实际写作中不太实用,一般只会用到简单的文段引用,嵌套最多用到段落。而且,目前很多编辑器的引用嵌套都有个不起眼的小bug,嵌套中的标题会被纳入到目录大纲。
2. 列表的嵌套
列表的嵌套相对复杂,目前一般有两种方式来实现,一是Tab方式,二是对齐方式。
Tab方式是原生Markdown提出的嵌套方式,使用4个空格或1个Tab缩进实现多级嵌套(这里的Tab指4个空格,有的编辑器Tab键值不一样,或者会根据上一行变化)。
对齐方式是CommonMark提倡的方式,不固定每次嵌套所需的空格数量,使用空格缩进至嵌套内容与列表项目首行对齐为止。
两种方式各有优势,Tab方式更易写,每次缩进按一个Tab就可以;对齐方式更易读,写出来的文档与最后显示的结果更接近。
3. 范围元素的嵌套
在原生Markdown中将所有的行内元素叫做范围元素。但是这里的范围元素指行内元素中采用标识包裹的语法元素,包括强调、重强调、删除线和行内代码。
如删除线内嵌套强调:123**56**789
注意:
转义
Markdown之所以易写易读,很大程度的功劳在于它使用了大量的常见符号来构建语法,但是如果需要写入被占用的这些特殊符号,就会面临特殊符号被误识别为Markdown语法的可能性。
这时候就需要对特殊符号进行转义,转义方式为在符号前添加一个反斜线\。
比如想输入:
2017. 金鸡报喜!
就需要在Markdown中这么写,否则会被识别为有序列表:
2017\. 金鸡报喜!
下面是John Gruber提供的符号列表,这些符号常常需要被转义(当然不限于这些符号):
符号中文名英文名
反斜线
backslash
反引号
backtick
星号
asterisk
下划线
underscore
{ }
大括号/花括号
curly braces
[ ]
中括号/方括号
square brackets
( )
小括号/括弧
parentheses
井号
hash mark
加号
plus sign
减号/连字符
minus sign/hyphen
英文句号/小数点
dot
感叹号
exclamation mark
输入Markdown代码
如果我们想用区块代码记录Markdown围栏式区块代码怎么办?想在行内代码中添加反引号`怎么办?
我们知道无论围栏式区块代码还是行内代码,输入的内容都会原样输出,直到结束的反引号出现,如果代码内包含反引号,就可能被错误识别,提前结束代码。代码内部也不支持转移,上一节中提到的转移技巧无法使用。
这时,可以用更大的围栏包围代码来解决,如用4个反引号`:
````
```
围栏式代码
```
````
那么,行内代码内怎么添加反引号呢?行内代码也不能使用反斜线转义,无论```或` ` `都不能得到想要的结果。
同样,这时可以使用类似上面的方法。如果行内代码内添加一个反引号,就用两个反引号包裹,如果要添加连续的反引号,就用三个反引号包裹,以此类推。
这是一个反引号的写法:`` ` ``。
这是两个连续反引号的写法:``` `` ```。
如果代码存在多个反引号,但不连续,用两个反引号包裹:`` 行内代码用`反引号`包裹 ``。
兼容HTML
非程序员可能不知道,Markdown兼容HTML标签语法。这就能解释为什么有的人用尖括号< >包裹内容得时候会发现内容消失了,因为它被当做HTML标签识别了。这时候对尖括号转义即可。
虽然Markdown兼容HTML,但是在Markdown文档中使用HTML标签显然不符合Markdown设计的本意,而且懂HTML的人也不多,所以在书写Markdown文档时,HTML标签是不推荐使用的。
13 个让你值得一试的 CSS 技巧
CSS在近些年的web发展中表现出了无以伦比的力量。今天我们要分享的这些CSS技巧可帮助大家更深层次地探索CSS。
一起来看看吧。
1. 利用border属性绘制三角形
在需要简单三角形的情况下,例如添加箭头指针到工具提示时,加载图像有点儿太过大费周章。
因为只使用CSS的border属性,我们就可以创建三角形。
这是一个惯用伎俩。理想情况下,我们可以在宽度和高度为0的元素上设置边框。所有边框颜色都是透明的,除了将形成箭头的颜色部分。例如,要创建指向上方的箭头,则底部边框是彩色的,而左边框和右边框是透明的。无需包含顶部边框。边框宽度决定了箭头的大小:
.upwards-arrow {
width: 0;
height: 0;
border-left: 20px solid transparent;
border-right: 20px solid transparent;
border-bottom: 20px solid crimson;
}
上面的代码将创建向上的箭头,如下所示:
2. 元素的背景交替
z-index属性可以让元素叠加到其他元素之上。有时,我们可能会将子元素上的z-index属性设置得太小,从而导致元素最终隐藏在其父元素的背景后面。若要防止这种情况,可以在父元素上创建新的堆叠上下文。创建堆叠上下文的一种方法是使用isolation: isolatecss样式声明。
我们可以通过堆叠上下文的手段来创建按钮交替背景的悬停效果。例如:
button.join-now {
cursor: pointer;
border: none;
outline: none;
padding: 10px 15px;
position: relative;
background-color: #5dbea3;
isolation: isolate; /* If ommitted, child pseudo element will be stacked behind */
}
button.join-now::before {
content: "";
position: absolute;
background-color: #33b249;
top: 0;
left: 100%;
right: 0;
bottom: 0;
transition: left 500ms ease-out;
z-index: -1;
}
button.join-now:hover::before {
left: 0;
}
上面的代码在悬停时将交换button的背景。背景会在不干扰前景文本的情况下发生变化,如下图所示:
3. 居中元素
使用display: flex;以及display: grid;居中元素比较常见。还有一种在x轴居中元素的方法是使用text-align CSS属性。此属性开箱即用。若要在DOM中居中其他元素,子元素的display需要为inline,可以是inline-block或任何其他内联...
div.parent {
text-align: center;
}
div.child {
display: inline-block;
}
4. 药丸形状的按钮
我们可以通过设置按钮的边框半径值来制作药丸形按钮。其中,边框半径应大于按钮的高度。
button.btn {
border-radius: 80px; /* value higher than height of the button */
padding: 20px 30px;
background-color: #fdd835;
border: none;
color: black;
font-size: 20px;
}
结果如下:
按钮的高度可以随着设计更改而改变。因此,用大的值设置border-radius会很方便,这样即使按钮变大,css依然能继续工作。
5. 轻松添加漂亮的加载动画
为网站创建漂亮的加载动画通常是一项无聊的任务。我们希望能够将有限的精力花费到真正重要的部分。
那么有什么办法呢?推荐一个打包到库的加载指示器集合,不但即插即用,而且用法简单,源代码也在Github上。
地址:
6. 简单的dark或light模式
只需几行CSS,我们即可在网站上启用dark/light模式。如下所示:
html {
color-scheme: light dark;
}
注意:color-scheme属性可以在html以外的任何DOM元素上设置。
然后设置变量来控制网站的背景颜色和文本颜色,并检查浏览器支持:
html {
--bg-color: #ffffff;
--txt-color: #000000;
}
@supports (background-color: Canvas) and (color: CanvasText) {
:root {
--bg-color: Canvas;
--txt-color: CanvasText;
}
}
注意:如果未在元素上设置background-color,则将继承浏览器定义的所匹配的dark/light主题系统颜色。这些系统颜色在不同的浏览器之间可能有所不同。
显式设置background-color在与prefers-color-scheme结合使用时会非常有用,可提供与浏览器设置的默认值不同的颜色阴影。
下面是运行中的dark/light模式,模拟了用户在dark模式和light模式之间切换的效果。
7. 用省略号(...)截断溢出的文本
这个技巧可用于裁剪长文本使得更美观。
只需使用以下CSS即可:
p.intro {
width: 300px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
规则如下:
结果如下所示:
8. 将长文本截断为多行
这一条与上面的技巧略有不同。虽然文本也被剪裁,但将内容限制在多行。
p.intro {
width: 300px;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3; /* Truncate when no. of lines exceed 3 */
overflow: hidden;
}
输出如下所示:
9.没必要总写top、right、bottom、left
使用定位元素时,很多时候我们会这样编写代码:
.some-element {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
但这可以使用inset属性简化:
.some-element {
position: absolute;
inset: 0;
}
此外,如果top、right、bottom、left有不同的值,可以按顺序分别设置:inset: -10px 0px -10px 0px。这种简写方式与边距相同。
10.提供优化后的图像
在网速慢的时候访问高清图片网站的痛苦大家一定深有体会。
这里我们提供一种使用image-set的CSS补救技巧。
那就是为浏览器提供选项,让它来决定最适合用户设备的图像。例如:
.banner {
background-image: url("elephant.png"),
background-image: -webkit-image-set(
url("elephant.webp") type("image/webp") 1x,
url("elephantHD.webp") type("image/webp") 2x,
url("elephant.png") type("image/png") 1x,
url("elephantHD.png") type("image/png") 2x
);
}
上面的代码用于设置元素的背景图像。
如果支持-webkit-image-set,则背景图像将是优化的图像,即支持的MIME类型的图像,更适合用户设备的分辨率。
例如:由于更高质量的图像与尺寸成正比,因此拥有高分辨率设备但网络较差的用户将提示浏览器决定是否提供分辨率较低的图像。此时用户不等待加载高清图像是合乎逻辑的。
注意:浏览器认为最适合的图像是已下载的图像。
11. 计数器
我们不必纠结于浏览器如何呈现编号列表,直接使用counters()实现设计即可。方法如下:
ul {
margin: 0;
font-family: sans-serif;
/* Define & Initialize Counter */
counter-reset: list 0;
}
ul li {
list-style: none;
}
ul li:before {
padding: 5px;
margin: 0 8px 5px 0px;
display: inline-block;
background: skyblue;
border-radius: 50%;
font-weight: 100;
font-size: 0.75rem;
/* Increment counter by 1 */
counter-increment: list 1;
/* Show incremented count padded with `.` */
content: counter(list) ".";
}
输出如下所示:
适用于任何除和之外的其他DOM元素。
12. 表单验证可视化提示
我们可以只使用CSS来向用户显示有关表单输入有效性的帮助可视化提示。在表单元素上使用:valid和:invalid CSS伪类,可在内容验证成功与否时应用合适的样式。
假设有以下HTML页面结构:
<input
type="text"
pattern="([a-zA-Z0-9]\s?)+"
placeholder="Enter full name"
required
/>
<span>span>
将用于显示验证结果。
下面的CSS用于设置有关验证结果的输入样式:
input + span {
position: relative;
}
input + span::before {
position: absolute;
right: -20px;
bottom: 0;
}
input:not(:placeholder-shown):invalid {
border: 2px solid red;
}
input:not(:placeholder-shown):invalid + span::before {
content: "✖";
color: red;
}
input:not(:placeholder-shown):valid + span::before {
content: "✓";
color: green;
}
因此,我们在不涉及任何javascript的情况下实现了交互性。
13. 一键选择文本
此技巧侧重于改善网站用户的复制和粘贴体验。使用user-select: all即可一键启用文本选择。
此外,我们也可以使用user-select: none;禁用文本选择。禁用文本选择的另一种方法是将文本放在::before或::after CSS伪元素的content: '';属性中。