test csdn markdown

在 html 中用加色法混合颜色

概要

本文通过解决一个假想的问题介绍了 css screen 混合模式,并介绍了如何用 svg 滤镜、canvas 2d、canvas webgl 实现相同的效果。

问题

下面的图片演示三种颜色光叠加的效果,请在 html 中实现这种效果。

test csdn markdown_第1张图片

约定

词语 指代
混合 blend
加色 additive color - 名词
特性 attribute,比如 ,说 id 是元素 a 的特性
透明度 α、alpha
伪输入图像 pseudo input image
着色器 shader
着色器程序 shader program
xml 应用程序 XML application
chrome google chrome 41
firefox firefox developer edition 40
ie internet explorer 11
3 个浏览器 上面 3 个版本的浏览器


opera 已经基于 webkit 了,所以未测试 opera,若在 chrome 中可用那我就认为在 opera 中也可用。

分析

当然可以用 photoshop 制作图片,html 用 引用该图片,本文不讨论这种方法。

观察重叠部分发现该部分的颜色不仅受自己的影响、还受它下面背景颜色的影响,重叠部分的颜色是自己的颜色和背景颜色混合的结果。换句话说,一个像素绘制出来的颜色等于像素颜色和背景像素颜色的混合,即

C=B(Cb,Cs) ,其中,
C 是绘制的颜色
B 是混合函数
Cb 是背景颜色
Cs 是前景颜色,即像素的颜色

这里面 C 的 r、g、b 颜色分量都是 [0, 1] 的小数而不是 [0, 255] 的整数。显然,对同一个像素来说不同的 B 得到不同的 C 。红绿蓝分别是 rgb(1, 0, 0)rgb(0, 1, 0)rgb(0, 0, 1) B 如果满足 B(Cb,Cs)=min(Cs+Cb,1) 就能合成白色。

重点:不同的 B 得到不同的 C

不可行的方法

html 中经常用到下面 3 个方法,

  • css opacity 属性
  • css rgba()/hsla() 颜色
  • 引用带 alpha 通道的图像

它们使用相同的混合函数,叫做 α 混合简单 α 复合

C=B(Cb,Cs)=Cs×αs+Cb×αb×(1αs)=Cs×αs+Cb×(1αs)

αs 是前景透明度, αb 是背景透明度,上面的式子计算混合后的 r、g、b 颜色,混合后的透明度 αo 由公式 αo=αs+αb×(1αs) 给出。很多时候背景不透明,即 αb 是 1,上面把 1 代入了 αb

简单 α 复合 - http://dev.w3.org/fxtf/compositing/#simplealphacompositing
opacity - http://stackoverflow.com/questions/8743482/calculating-opacity-value-mathematically

下面给上面的式子代入几组实际值。设 Cs 是不透明红 rgba(1, 0, 0, 1) Cb 是不透明蓝 rgb(0, 0, 1),它俩混合的结果不用计算都知道仍然是不透明红,计算过程如下,
r = 1 x 1 + 0 x (1 - 1) = 1
g = 0 x 1 + 0 x (1 - 1) = 0
b = 0 x 1 + 1 x (1 - 1) = 0

红蓝得红,混合失败。另外一组, Cs = rgba(1, 0, 0, 0.5) Cb = rgb(0, 0, 1),有,
r = 1 x 0.5 + 0 x (1 - 0.5) = 0.5
g = 0 x 0.5 + 0 x (1 - 0.5) = 0
b = 0 x 0.5 + 1 x (1 - 0.5) = 0.5

要想让得到的 rgb(0.5, 0, 0.5)rgb(0, 1, 0) 的绿色混合以得到 rgb(1, 1, 1) 的白色,α 需要满足下面的方程组,

{0.5α+0α+0(1α)=1(1α)=1={0.5α=11α=1={α=2α=0

上面的方程组无解,即无论如何设置 α 都无法通过 B 混合 rgb(0.5, 0, 0.5)rgb(0, 1, 0) 得到 rgb(1, 1, 1)

回过头来观察式子 Cs×αs+Cb×(1αs) ,可以看出结果介于 Cs Cb 之间。红绿蓝混合时,白色的红色分量只能通过红色得到,这要求红色的 α 是 1,但 α = 1 造成背景颜色蓝或者绿被忽略,而忽略任何一个分量都无法得到白色。因此这个混合函数不合适。

可行的方法

如果可以自己逐一计算像素的颜色,得出要求的效果自然不在话下。除了自己计算外,如果存在正好能够实现要求效果的固定函数,则调用该函数也可以。

在 html 中处理颜色有 3 种工具,css、svg、canvas。

css

css 有个模块叫复合与混合,这个模块定义了若干固定函数,其中一个叫 screen,它的 B

C=B(Cb,Cs)=1[(1Cb)×(1Cs)]=Cs+CbCs×Cb

css 复合与混合 - http://dev.w3.org/fxtf/compositing/

假设 add 是 min(Cs+Cb,1) ,screen 虽然不是 add 但是也可以把红绿蓝合成白色,实现要求的效果。至于 add、screen 或其它混合函数哪个能更精确地反映光线的混合,我也搞不清楚。

通过指定 html 元素的 css 属性 mix-blend-mode: screen 来让元素和其背后的元素以 screen 方式混合。css 目前没办法逐像素计算目标区域的颜色。

html 中的 svg

本文把 svg 写在 html 内 。svg 是 xml 应用程序,遵循 xml 语法,但是放在 html 中又可以采用部分 html 语法。如果大家按照 xml svg 的知识去看本文的代码可能会有疑问,所以在写 svg 之前先说一下 html 中的 svg。

  • html 不支持名字空间,忽略 里面由特性定义的名字空间,所以本文的 svg 没有 xmlns="http://www.w3.org/2000/svg" 或者 xmlns:xlink="http://www.w3.org/1999/xlink"xlink:href 在 html 中是个普通的特性名,冒号和名字空间无关

  • 没有歧义时可以省略特性值周围的引号

  • xml 中没有内容的元素比如 也可以写做 ,叫做自闭合;html 不存在自闭合,但内嵌的 svg 元素可以使用自闭合

html 中的 svg 元素可以自闭合 - http://www.w3.org/TR/html-markup/syntax.html#svg-mathml

所有没有内容的 xml 元素都叫 empty 元素,可以自闭合;html 不存在 empty 元素,但是定义了一些 void 元素,void 元素不能有内容,只有开始标记没有结束标记。

所有 void 元素是,area, base, br, col, command, embed, hr, img, input, keygen, link, meta, param, source, track, wbr
http://www.w3.org/TR/html-markup/syntax.html#syntax-elements

所有 html 元素开始标记的 > 前面可以写一个 /,和不写 / 一样。
解释为
而不是


是 void 元素,所以没问题;

解释为
不是 void 元素,所以可能会出问题,


    red = html, green = xhtml

有些元素可以省略结束标记,但不是 void 元素,比如

  • ;有些元素有时候没有内容,但既不是 void 元素也不能省略结束标记,比如

    上面是 gl.drawArrays,它从用 gl.bindBuffer(gl.ARRAY_BUFFER, arr) 绑定的 arr 中依次读取每个顶点。gl.drawElements 需要用 gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ids) 额外绑定一个数组作为 gl.ARRAY_BUFFER 的索引,这样一来它使用两个数组,arr 保存顶点,ids 保存遍历 arr 的顺序。设

    //     vertex 0, vertex 1, vertex 2, vertex 3, ...
    arr = [  x0, y0,   x1, y1,   x2, y2,   x3, y3, ...]
    ids = [0, 3, 1, 2]
    

    并且

    • 已经调用了两次 gl.bindBuffergl.ARRAY_BUFFERgl.ELEMENT_ARRAY_BUFFER 分别对应
      arrids
    • gl.vertexAttribPointer 指出每个顶点是 2 个 type
    • 索引数组 ids 的元素类型是 Uint16 或者说 gl.UNSIGNED_SHORT

    • gl.drawArrays(gl.TRIANGLE_FAN, 0, 4) 绘制 4 次顶点,依次是 0 - 1 - 2 - 3
    • gl.drawElements(gl.TRIANGLE_FAN, 4, gl.UNSIGNED_SHORT, 0) 绘制 4 次顶点,它依次读取 ids 的每个元素,以元素的值作为 arr 的索引去获取顶点,依次绘制 arr0 - 3 - 1 - 2

    我假设读者通过前面的阅读和练习已经理解了 gl.drawArraysgl.drawElements,下面简要介绍设置颜色。

    前面在片段着色器里硬编码了个颜色,不透明黑,要画 3 个颜色的方块就需要 3 个片段着色器。如果能让片段着色器接受一个 javascript 传入的变量,有点像顶点着色器里面的特性 attribute,从 javascript 指定颜色,那就可以只写一个片段着色器。出于两个原因,不使用 attribute

    • 只有顶点着色器可以定义 attribute,片段着色器不可以
    • 方块是单色的,不需要像 attribute 那样每个顶点都传一个值

    着色器程序总共可以定义 3 种变量:attributeuniformvarying

    这里使用 uniformvarying 用来从顶点着色器往片段着色器传值,当然也可以实现效果。

    uniform 的意思是,每次调用 gl.drawArrays 绘制一系列的顶点之前,先设置一个在绘制过程中保持不变的值,绘制这些点的过程中,着色器程序可以读取但不能修改该定值。对比 attributeattributegl.drawArrays 绘制的每 1 个顶点都赋值 1 次;uniform 只在 gl.drawArrays 开始前赋值一次。

    因为 uniform 在 1 次绘制中只赋值 1 次,所以它不从数组里面取值,gl.uniformXxx 用于设置 uniform 的值。

    所以下面的示例中,顶点着色器定义 1 个 attribute 以接受顶点,片段着色器定义 1 个 uniform 以接受颜色,调用 3 次 gl.drawArrays 以绘制 3 个方块。

    混合颜色

    这里需要把 C=B(Cb,Cs) 换个形式以反映 webgl 的混合方法,换成 C=e(f(Cs),g(Cb)) 。看上去更复杂了,但马上就会发现,它很简单。

    e 对应 gl.blendEquation(mode)mode 是 3 个枚举值之一

    mode e
    gl.FUNC_ADD - 默认值 e(x,y)=clamp(x+y)
    gl.FUNC_SUBTRACT e(x,y)=clamp(xy)
    gl.FUNC_REVERSE_SUBTRACT e(x,y)=clamp(yx)


    这里的 clamp(x) 把 x 限制为 [0, 1],小于 0 的值变成 0,大于 1 的值变成 1。

    f g 分别对应 gl.blendFunc(sfactor, dfactor) 中的 sfactordfactor,均从下列枚举中取值

    factor f
    gl.ZERO - dfactor 默认值 f(x)=x×0
    gl.ONE - sfactor 默认值 f(x)=x×1
    gl.SRC_COLOR f(x)=x×Cs
    gl.ONE_MINUS_SRC_COLOR f(x)=x×(1Cs)
    gl.DST_COLOR f(x)=x×Cb
    gl.ONE_MINUS_DST_COLOR f(x)=x×(1Cb)
    gl.SRC_ALPHA f(x)=x×αs
    gl.ONE_MINUS_SRC_ALPHA f(x)=x×(1αs)
    gl.DST_ALPHA f(x)=x×αb
    gl.ONE_MINUS_DST_ALPHA f(x)=x×(1αb)
    gl.SRC_ALPHA_SATURATE f(x)=x×min(αs,αb)


    所以,当 dfactor = gl.ONEsfactor 取默认值 gl.ONEmode 取默认值 gl.FUNC_ADD 时有

    C=e(f(Cs),g(Cb))=clamp(Cs×1+Cb×1)=clamp(Cs+Cb)

    Cs Cb 都是正数时 clamp(Cs+Cb)=min(Cs+Cb,1) ,就是前面用过的 add 混合模式。相应的 js 代码是

    gl.blendFunc(gl.ONE, gl.ONE);
    gl.enable(gl.BLEND); // 必须明显的启用混合
    

    而如果让 sfactor = gl.ONE_MINUS_DST_COLORdfactor 取默认值 gl.ONEmode 取默认值 gl.FUNC_ADD,有

    C=e(f(Cs),g(Cb))=clamp(Cs×(1Cb)+Cb)=clamp(Cs+CbCs×Cb)

    Cs Cb 都是正数时 clamp(Cs+CbCs×Cb)=Cs+CbCs×Cb ,就是前面用过的 screen 混合模式。相应的 js 代码是

    gl.blendFunc(gl.ONE_MINUS_DST_COLOR, gl.ONE);
    gl.enable(gl.BLEND); // 必须明显的启用混合
    

    代码

    现在的情况是

    • 会用 gl.drawArrays(gl.TRIANGLE_FAN, 0, 4); 绘制方块
    • 知道将要用 uniform 给片段着色器传递一个代表颜色的变量
    • 知道如何设置混合

    下面看具体的代码

    <div class=sample>
        <canvas class=s4 height=180 width=200>canvas>
        <h4>webgl 混合h4>
        <script>
            !function () {
                var canvas = document.querySelector(".s4"),
                    ch = canvas.height, cw = canvas.width,
                    cc = canvas.getContext("webgl") || canvas.getContext("experimental-webgl"),
                    svs =
                        "attribute   vec2 position;" +
                        "uniform     vec2 resolution;" +
                        "void main() {" +
                        "    vec2 p = position / resolution * 2.0 - 1.0;" +
                        "    gl_Position = vec4(p * vec2(1, -1), 0, 1);" +
                        "}",
                    sfs =
                        "precision mediump float;" +
                        "uniform vec3 color;" +
                        "void main() { gl_FragColor = vec4(color, 1); }",
                    rects = [
                        50, 20, 50, 120, 150, 120, 150, 20, // red
                        30, 40, 30, 140, 130, 140, 130, 40, // lime
                        70, 60, 70, 160, 170, 160, 170, 60  // blue
                    ],
                    buffer = cc.createBuffer(),
                    attrs = { position: 0, },
                    unifs = { color: 0, resolution: 0 },
                    program = glProgram(cc, sfs, svs, attrs, unifs);
    
                cc.useProgram(program);
                cc.uniform2f(unifs.resolution, cw, ch);
                cc.bindBuffer(cc.ARRAY_BUFFER, buffer);
                cc.vertexAttribPointer(attrs.position, 2, cc.UNSIGNED_BYTE, false, 0, 0);
                cc.bufferData(cc.ARRAY_BUFFER, new Uint8Array(rects), cc.STATIC_DRAW);
    
                //cc.blendFunc(cc.ONE, cc.ONE);
                cc.blendFunc(cc.ONE_MINUS_DST_COLOR, cc.ONE);
                cc.enable(cc.BLEND);
    
                draw(cc, 0, [1, 0, 0]);
                draw(cc, 4, [0, 1, 0]);
                draw(cc, 8, [0, 0, 1]);
    
                function draw(gl, offset, color) {
                    gl.uniform3fv(unifs.color, color);
                    gl.drawArrays(gl.TRIANGLE_FAN, offset, 4);
                }
            }();
    
            function glProgram(gl, sfs, svs, attrs, unifs) {
                var prop, i,
                    program = glLink(gl,
                        glCompile(gl, sfs, gl.FRAGMENT_SHADER),
                        glCompile(gl, svs, gl.VERTEX_SHADER));
    
                for (prop in attrs) {
                    i = gl.getAttribLocation(program, prop);
                    attrs[prop] = i;
                    gl.enableVertexAttribArray(i);
                }
    
                for (prop in unifs) unifs[prop] = gl.getUniformLocation(program, prop);
                return program;
    
                function glCompile(gl, source, type) {
                    var shader = gl.createShader(type);
    
                    gl.shaderSource(shader, source);
                    gl.compileShader(shader);
                    return shader;
                }
    
                function glLink(gl, fs, vs) {
                    var program = gl.createProgram();
    
                    gl.attachShader(program, fs);
                    gl.attachShader(program, vs);
                    gl.linkProgram(program);
                    return program;
                }
            }
        script>
    div>

    要点

    • uniform 不像 attribute 那样要调用 gl.enableVertexAttribArray,使用 gl.getUniformLocation 获取 uniform 在 javascript 中的索引后就能用了

    • js 中的顶点数组使用了大于 1 的整数坐标,这个整数坐标传入顶点着色器后,顶点着色器要根据当前的画布尺寸换算出相应的小数,然后才给 gl_Position 赋值

    • 代码包含 add 和 screen 混合模式,就一句代码,add 被注释掉了

    全部代码

    
    <html>
    <head>
        <meta charset=utf-8>
        <style>
            .sample { display: inline-block; vertical-align: top; width: 200px; }
        style>
        <title>additive colortitle>
    head>
    <body>
        <div class=sample>
            <style>
                .s1 { height: 180px; isolation: isolate; position: relative; }
                .s1 > div { height: 100px; mix-blend-mode: screen; position: absolute; width: 100px; }
                .s1 > div:nth-of-type(1) { background-color: red; left: 50px; top: 20px; }
                .s1 > div:nth-of-type(2) { background-color: lime; left: 30px; top: 40px; }
                .s1 > div:nth-of-type(3) { background-color: blue; left: 70px; top: 60px; }
            style>
            <div class=s1><div>div><div>div><div>div>div>
            <h4>mix-blend-mode: screen 不是颜色分量相加h4>
        div>
    
        <div class=sample>
            <svg height=180 width=200>
                <filter id=s2-composite x=0 y=0 width=1 height=1>
                    <feComposite in2=BackgroundImage operator=arithmetic k1=-1 k2=1 k3=1>feComposite>
                filter>
                <filter id=s2-blend>
                    <feBlend in2=BackgroundImage mode=screen>feBlend>
                filter>
                <g enable-background=new>
                    <rect width=100 height=100 x=50 y=20 fill=red>rect>
                    <rect width=100 height=100 x=30 y=40 fill=lime filter=url(#s2-composite)>rect>
                    <rect width=100 height=100 x=70 y=60 fill=blue filter=url(#s2-blend)>rect>
                g>
            svg>
            <h4>svg,仅限 ie 10+h4>
        div>
    
        <div class=sample>
            <svg height=180 width=200>
                <filter id=s2-2 x=-1 y=-1 width=2 height=2>
                    <feOffset dx=-20 dy=-40>feOffset>
                    <feColorMatrix result=red type=matrix values="
                                   0 0 0 0 1
                                   0 0 0 0 0
                                   0 0 0 0 0
                                   0 0 0 1 0">feColorMatrix>
                    <feOffset in=SourceGraphic dx=-40 dy=-20>feOffset>
                    <feColorMatrix type=matrix values="
                                   0 0 0 0 0
                                   0 0 0 0 1
                                   0 0 0 0 0
                                   0 0 0 1 0">feColorMatrix>
                    <feBlend mode=screen in2=red>feBlend>
                    <feBlend mode=screen in2=SourceGraphic>feBlend>
                filter>
                <rect x=70 y=60 width=100 height=100 fill=blue filter=url(#s2-2)>rect>
            svg>
            <h4>svg feBlendh4>
        div>
    
        <div class=sample>
            <canvas class=s3-1 height=180 width=200>canvas>
            <h4>canvas 2d 全局复合h4>
            <script>
                !function () {
                    var canvas = document.querySelector(".s3-1"),
                        cc = canvas.getContext("2d");
    
                    cc.fillStyle = "red";
                    cc.fillRect(50, 20, 100, 100);
                    cc.globalCompositeOperation = "screen";
                    cc.fillStyle = "lime";
                    cc.fillRect(30, 40, 100, 100);
                    cc.fillStyle = "blue";
                    cc.fillRect(70, 60, 100, 100);
                }();
            script>
        div>
    
        <div class=sample>
            <canvas class=s3-2 height=180 width=200>canvas>
            <h4>在 canvas 中把颜色分量置 1,未使用 min(x + y, 1)h4>
            <script>
                !function () {
                    var canvas = document.querySelector(".s3-2"),
                        cc = canvas.getContext("2d"),
                        i, len, idata, arr;
    
                    cc.fillStyle = "red";
                    cc.fillRect(50, 20, 100, 100);
    
                    for (i = 0,
                        idata = cc.getImageData(30, 40, 100, 100),
                        arr = idata.data,
                        len = arr.length; i < len; i += 4)
                        arr[i + 1] = arr[i + 3] = 255;
    
                    cc.putImageData(idata, 30, 40);
    
                    for (i = 0,
                        idata = cc.getImageData(70, 60, 100, 100),
                        arr = idata.data,
                        len = arr.length; i < len; i += 4)
                        arr[i + 2] = arr[i + 3] = 255;
    
                    cc.putImageData(idata, 70, 60);
                }();
            script>
        div>
    
        <div class=sample>
            <canvas class=s4 height=180 width=200>canvas>
            <h4>webgl 混合h4>
            <script>
                !function () {
                    var canvas = document.querySelector(".s4"),
                        ch = canvas.height, cw = canvas.width,
                        cc = canvas.getContext("webgl") || canvas.getContext("experimental-webgl"),
                        svs =
                            "attribute   vec2 position;" +
                            "uniform     vec2 resolution;" +
                            "void main() {" +
                            "    vec2 p = position / resolution * 2.0 - 1.0;" +
                            "    gl_Position = vec4(p * vec2(1, -1), 0, 1);" +
                            "}",
                        sfs =
                            "precision mediump float;" +
                            "uniform vec3 color;" +
                            "void main() { gl_FragColor = vec4(color, 1); }",
                        rects = [
                            50, 20, 50, 120, 150, 120, 150, 20, // red
                            30, 40, 30, 140, 130, 140, 130, 40, // lime
                            70, 60, 70, 160, 170, 160, 170, 60  // blue
                        ],
                        buffer = cc.createBuffer(),
                        attrs = { position: 0, },
                        unifs = { color: 0, resolution: 0 },
                        program = glProgram(cc, sfs, svs, attrs, unifs);
    
                    cc.useProgram(program);
                    cc.uniform2f(unifs.resolution, cw, ch);
                    cc.bindBuffer(cc.ARRAY_BUFFER, buffer);
                    cc.vertexAttribPointer(attrs.position, 2, cc.UNSIGNED_BYTE, false, 0, 0);
                    cc.bufferData(cc.ARRAY_BUFFER, new Uint8Array(rects), cc.STATIC_DRAW);
    
                    //cc.blendFunc(cc.ONE, cc.ONE);
                    cc.blendFunc(cc.ONE_MINUS_DST_COLOR, cc.ONE);
                    cc.enable(cc.BLEND);
    
                    draw(cc, 0, [1, 0, 0]);
                    draw(cc, 4, [0, 1, 0]);
                    draw(cc, 8, [0, 0, 1]);
    
                    function draw(gl, offset, color) {
                        gl.uniform3fv(unifs.color, color);
                        gl.drawArrays(gl.TRIANGLE_FAN, offset, 4);
                    }
                }();
    
                function glProgram(gl, sfs, svs, attrs, unifs) {
                    var prop, i,
                        program = glLink(gl,
                            glCompile(gl, sfs, gl.FRAGMENT_SHADER),
                            glCompile(gl, svs, gl.VERTEX_SHADER));
    
                    for (prop in attrs) {
                        i = gl.getAttribLocation(program, prop);
                        attrs[prop] = i;
                        gl.enableVertexAttribArray(i);
                    }
    
                    for (prop in unifs) unifs[prop] = gl.getUniformLocation(program, prop);
                    return program;
    
                    function glCompile(gl, source, type) {
                        var shader = gl.createShader(type);
    
                        gl.shaderSource(shader, source);
                        gl.compileShader(shader);
                        return shader;
                    }
    
                    function glLink(gl, fs, vs) {
                        var program = gl.createProgram();
    
                        gl.attachShader(program, fs);
                        gl.attachShader(program, vs);
                        gl.linkProgram(program);
                        return program;
                    }
                }
            script>
        div>
    body>
    html>

    参考

    复合与混合级别 1
    http://www.w3.org/TR/compositing/
    http://dev.w3.org/fxtf/compositing/
    http://dev.w3.org/fxtf/compositing-1/

    svg 1.1 滤镜
    http://www.w3.org/TR/SVG11/filters.html
    http://www.w3.org/TR/SVG/filters.html

    滤镜效果模块级别 1
    http://www.w3.org/TR/filter-effects-1/
    http://dev.w3.org/fxtf/filters/

    svg 复合
    http://www.w3.org/TR/SVGCompositing/
    http://dev.w3.org/SVG/modules/compositing/master/SVGCompositingPrimer.html

    混合模式
    http://en.wikipedia.org/wiki/Blend_modes

    欢迎使用Markdown编辑器写博客

    本Markdown编辑器使用StackEdit修改而来,用它写博客,将会带来全新的体验哦:

    • Markdown和扩展Markdown简洁的语法
    • 代码块高亮
    • 图片链接和图片上传
    • LaTex数学公式
    • UML序列图和流程图
    • 离线写博客
    • 导入导出Markdown文件
    • 丰富的快捷键

    快捷键

    • 加粗 Ctrl + B
    • 斜体 Ctrl + I
    • 引用 Ctrl + Q
    • 插入链接 Ctrl + L
    • 插入代码 Ctrl + K
    • 插入图片 Ctrl + G
    • 提升标题 Ctrl + H
    • 有序列表 Ctrl + O
    • 无序列表 Ctrl + U
    • 横线 Ctrl + R
    • 撤销 Ctrl + Z
    • 重做 Ctrl + Y

    Markdown及扩展

    Markdown 是一种轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档,然后转换成格式丰富的HTML页面。 —— [ 维基百科 ]

    使用简单的符号标识不同的标题,将某些文字标记为粗体或者斜体,创建一个链接等,详细语法参考帮助?。

    本编辑器支持 Markdown Extra ,  扩展了很多好用的功能。具体请参考Github.

    表格

    Markdown Extra 表格语法:

    项目 价格
    Computer $1600
    Phone $12
    Pipe $1

    可以使用冒号来定义对齐方式:

    项目 价格 数量
    Computer 1600 元 5
    Phone 12 元 12
    Pipe 1 元 234

    定义列表

    Markdown Extra 定义列表语法:
    项目1
    项目2
    定义 A
    定义 B
    项目3
    定义 C

    定义 D

    定义D内容

    代码块

    代码块语法遵循标准markdown代码,例如:

    @requires_authorization
    def somefunc(param1='', param2=0):
        '''A docstring'''
        if param1 > param2: # interesting
            print 'Greater'
        return (param2 - param1 + 1) or None
    class SomeClass:
        pass
    >>> message = '''interpreter
    ... prompt'''

    脚注

    生成一个脚注1.

    目录

    [TOC]来生成目录:

    • 概要
    • 问题
    • 约定
    • 分析
    • 不可行的方法
    • 可行的方法
      • css
      • html 中的 svg
      • svg
      • canvas
      • 如何运行示例代码
    • 示例 - css mix-blend-mode
    • 示例 - svg feComposite 和 feBlend
      • 总结
    • 示例 - canvas 2d
    • 示例 - canvas webgl
      • 绘制方块
      • 混合颜色
      • 代码
      • 要点
    • 全部代码
    • 参考
    • 欢迎使用Markdown编辑器写博客
      • 快捷键
      • Markdown及扩展
        • 表格
        • 定义列表
        • 代码块
        • 脚注
        • 目录
        • 数学公式
        • UML 图
      • 离线写博客
      • 浏览器兼容

    数学公式

    使用MathJax渲染LaTex 数学公式,详见math.stackexchange.com.

    • 行内公式,数学公式为: Γ(n)=(n1)!nN
    • 块级公式:

    x=b±b24ac2a

    更多LaTex语法请参考 这儿.

    UML 图:

    可以渲染序列图:

    Created with Raphaël 2.1.0 张三 张三 李四 李四 嘿,小四儿, 写博客了没? 李四愣了一下,说: 忙得吐血,哪有时间写。

    或者流程图:

    Created with Raphaël 2.1.0 开始 我的操作 确认? 结束 yes no
    • 关于 序列图 语法,参考 这儿,
    • 关于 流程图 语法,参考 这儿.

    离线写博客

    即使用户在没有网络的情况下,也可以通过本编辑器离线写博客(直接在曾经使用过的浏览器中输入write.blog.csdn.net/mdeditor即可。Markdown编辑器使用浏览器离线存储将内容保存在本地。

    用户写博客的过程中,内容实时保存在浏览器缓存中,在用户关闭浏览器或者其它异常情况下,内容不会丢失。用户再次打开浏览器时,会显示上次用户正在编辑的没有发表的内容。

    博客发表后,本地缓存将被删除。 

    用户可以选择 把正在写的博客保存到服务器草稿箱,即使换浏览器或者清除缓存,内容也不会丢失。

    注意:虽然浏览器存储大部分时候都比较可靠,但为了您的数据安全,在联网后,请务必及时发表或者保存到服务器草稿箱

    浏览器兼容

    1. 目前,本编辑器对Chrome浏览器支持最为完整。建议大家使用较新版本的Chrome。
    2. IE9以下不支持
    3. IE9,10,11存在以下问题
      1. 不支持离线功能
      2. IE9不支持文件导入导出
      3. IE10不支持拖拽文件导入


    1. 这里是 脚注内容. ↩
  • 你可能感兴趣的:(test csdn markdown)