头像
ky0haの部屋
一个没有动力的咸鱼~


qq:253157225

邮箱:mitchelltodd434@gmail.com

twitter:@ky0ha

twitch: @xysamaw

yotube: @ha kyo

bilibili: @虚叶

pixiv: @kyoha

css实现github代码样式

简介

在制作这个页面的时候,我突发奇想,如果将代码块放入html的话,要怎么做。去百度之后得到的答案是放在 code 标签内或者放在 pre 标签内,最后我选择的是 pre 标签,但是代码块虽然文本格式是代码的格式,字体大小等很多东西和正常文本是一样的,就会显得很蠢,所以我联想到了 CSDN 以及 GitHub 甚至说 steam 聊天框的 /code指令,这些都同时具有了代码的格式和代码的样式,以及一些深色的背景和缩进,甚至有的还有行号的标注,这看起来实在是太酷了。于是我决定,要在我的这个页面内也实现这种效果。


制作深色背景的代码块

我采用的是利用 pre 标签承载我的代码块,于是我给 pre 标签赋予了一个 id 并直接在 css 里面对这个 id 进行样式的制作。

html 中 pre 标签的声明:

                    <pre id="code_block">代码块内的代码文本<⁄pre>
                

对应 css 的创建部分:

                    #code_block {
                            background: #2d2d2d;
                            color: rgb(201,209,217);
                            font-family: Consolas;
                            text-align: left;
                            padding: 1em;
                            padding-left: 0.8em;
                            margin: 1em;
                            border-radius: 5px;
                            counter-reset: line;
                            white-space: pre;
                            word-spacing: normal;
                            word-break: normal;
                            word-wrap: normal;
                            line-height: 1.5;
                        }
                    

关键部分:背景色 background 为 #2d2d2d 深色,color 字体颜色 color 为 rgb(201,209,217) 灰白色,字体为 Consolas 代码字体,white-space 设置为 normal,取消预文本样式,作用后面介绍 span 的时候会说,行高 line-height 为 1.5 倍。

效果如下:

                    这是一个代码块
                


实现代码行的行号标注

当我实现了上述的代码块样式背景之后,忽然发现,我的代码块,为什么没有他们那个行号标注,这不行,我不能接受!然后我在他们的代码块的html布局里面发现他们的行号是一个叫 ::before 的东西,我去搜索了这个东西具体是什么,怎么使用,然后了解到,实际上就是在标签之前创建一个伪标签,可以对这个标签定义样式和内容,主要用于段前编号等。

搞清楚了这一点之后,行号的制作实际上就显得很简单了。但是简单归简单,这不是个真正的标签,我不知道怎么将文本写入进去,通过继续学习 ::before 的使用方法,得知是通过 css 里定义一个 content 的属性的值来控制输出,对于输出行号采用的方法是:在存放所有行的容器的 css 里定义一个 counter-reset 属性,值为一个自定义的名称,然后在每一行的 before 里面设置 counter-increment 用于自增长一个对应的标记名称,content:counter(标记名称) 来控制 before 里面显示标记名称的计数值,还可以在后面直接增加字符串,用空格隔开,对 before 显示的内容进行补充和自定义。

于是代码块的行号标记方法就显得十分简单了:

                    <pre id="code_block">
                        <span>print(1)<⁄span>
                        <span>print("hello world")<⁄span>
                        <span>print("hello again")<⁄span>
                    <⁄pre>
                

注意:因为外围我使用的是 pre 标签,而 pre 标签会将换行和换行之后自动进行的缩进保留下来,会导致代码块得不到想要的效果,所以所有的 span 必须放在同一行进行书写,pre 标签中的 white-space 被设置为 normal,将预文本格式放在 span 标签的 css 内,使 span 带有保留代码格式的预文本,这样的好处是 pre 内的代码块不用再顾忌预格式文本保留空格和换行而必须将所有的 span 写在同一行,使整个 html 的可读性更高,一个 span 代表一个代码行,利用 span 进行计数,利用 css 的块显示实现 span 自动换行。

以下为对应css的声明部分:

                    <!-- 在 #code_block 的 css 内,第十行 counter-reset: line; 已经定义了行数标记名称为 line -->
                    #code_block span {
                        display: block;
                        line-height: 1.5rem;
                        white-space: pre;
                    }
                    
                    #code_block span:before {
                        counter-increment: line;
                        content: counter(line);
                        display: inline-block;
                        width: 3em;
                        text-align: right;
                        border-right: 2px solid #999;
                        padding-right: .8em;
                        margin-right: 1em;
                        color: #999;
                    }
                
重点部分:
第 4 行,display:block; 将 span 设置为块级元素,实现自动换行效果。
第 5 行,white-space: pre; 使存放代码的 span 具有预格式文本效果。
第 9、10 行,counter-increment:line; 和 content:counter(line); 实现行号的自增长和输出,此处必须先自增长在输出,因为行号计数器的起始是 0。
第 11 行,通过设置 display 为 inline-block 将 before 和 span 同行。
第 12 行,通过设置 width 的值为 3em 保证最大容纳行号为 999,超过 999 行行号所在的 before 将代码内容 span 向后顶,导致 before 的右边框位置改变。

以上步骤实现的结果如下:

                    print(1)
                    print("hello world")
                    print("hello again")
                

行号很好的实现了,但是总感觉少了什么??代码只有格式,没有样式!下一步将通过 css 实现代码块样式的控制。


利用 code 和 css 实现代码样式效果

在选择样式的时候,想了很多选择,最后选择了比较常见而且样式少一些的 GitHub 的样式风格。至于为什么选择样式少的,因为没有使用 js,纯手动实现样式的效果,需要在每个设置样式的地方设置一个 code 进行样式调整,十分的耗时耗力,在下面的实例中就可以看出来了。

以下为样例 html 的内容:( python 中的 print 函数名显示颜色和关键字显示颜色一样,写这一部分记录的时候忽然发现这个事情,但是觉得没必要为了一个 print 专门再加一个 class 的名称,所以样例中直接使用的是 key_word 的 class 名)

                    <pre id="code_block">
                        <span><code class="key_word">print<⁄code>(<code class="value">1<⁄code>)<⁄span>    
                        <span><code class="key_word">print<⁄code>(<code class="string">"hello world"<⁄code>)<⁄span>    
                        <span><code class="key_word">print<⁄code>(<code class="string">"hello again"<⁄code>)<⁄span>    
                    <⁄pre>
                

以下为 css 的设置:

                    #code_block .key_word,
                    #code_block .operator,
                    #code_block .united {
                        color: rgb(255,123,114);
                    }
                    #code_block .value,
                    #code_block .default_function_name,
                    #code_block .attribute {
                        color: rgb(121,192,255);
                    }
                    #code_block .note {
                        color: rgb(139,148,158);
                    }
                    #code_block .created_function_name {
                        color: rgb(210,168,255);
                    }
                    #code_block .class_name {
                        color: rgb(247,162,87);
                    }
                    #code_block .string {
                        color: rgb(165,214,255);
                    }
                    #code_block .tag {
                        color: #7EE787;
                    }
                    #code_block .href_link {
                        color: rgb(165,214,255);
                        border-bottom: 2px solid rgb(165,214,255);
                    }
                

以下为样例的实际效果:

                    print(1)
                    print("hello world")
                    print("hello again")
                

对于每一个需要特殊显示的内容,都将它放在 code 标签内,标签的 class 为 特殊显示的类型,或者说是要特殊显示的内容的类型,目前我总共定义了的类型有:

类型 定义名称 色号 颜色
关键字 value rgb(255,123,144)
运算符 operator rgb(255,123,144)
单位 united rgb(255,123,144)
value rgb(121,192,255)
默认函数 default_function_name rgb(121,192,255)
属性 attribute rgb(121,192,255)
注释 note rgb(139,148,158)
自定义函数 created_function_name rgb(210,168,255)
类名 class rgb(247,162,87)
字符串 string rgb(165,214,255)
标签 tag #7EE787
超链接 href_link rgb(165,214,255)


总结

对于这个方法来说,最严重的不足就是手动添加导致几乎难以做到几百几千行的大量代码块的书写,改进方法使用 js 应该是可以的,因为不会 js 所以不是很确定,不过还有一个改进方法是我现在就可以做到的,但是还没有去做,就是通过 python 写一个将 python 或者 html 的代码作为文本输入进去,可以输出一个已经格式化好了的对应代码块的 html 代码,这样会省去大量人工添加的时间,而且在 python 上也很容易实现这个算法(但是还没有搞,因为刚刚才想到这个方法,而且急于这周四讲,写好这个 python 再继续写这个网站稍微有点耗时间)。

如果我真的完成了这个 python 的转换程序的话,也会作为一个有意思的项目,贴在这个个人博客上面~


如果你想下载这个项目的css,请点击这里:点击下载