WordPress 的 SyntaxHighlighter Evolved 是一个可以高亮显示代码的插件,它使用方便,界面也非常好看,很适合技术博客使用。

SyntaxHighlighter Evolved 有两个大版本,2.x3.x

且不论这两个版本的代码效率之类,光看肉眼可辨的,就是他们处理行号自动换行的区别。

 

下面介绍一下两个版本的原理:

2.x 版本:它将自动生成的行号和当前行的代码制作成一个 tabletable 外层再嵌套一个 div,代码块就是许多这样的 div 组成的。只要不手动换行,插件自动把它识别为一行,但是由于本身特性,长代码会自动换行。由于行号和代码是在一个 table 里的,所以在复制多行代码的时候注定会把行号给复制进去。为了解决这个问题,插件在右上角提供了 查看源代码 的工具栏,只有通过 查看源代码 才能复制无行号的代码。

2.x 结构示例
2.x 结构示例

3.x 版本:它与 2.x 版本的行号控制完全不同,2.x 版本是在生成 table 的时候同时生成行号,但是 3.x 版本是最后才按行给代码加行号。若允许代码自动换行,将导致下图结果发生。为了避免这种情况,它相比于 2.x 版本,在 styles/shCore.css 中增加了 .syntaxhighlighter .line {white-space: pre !important;} 一句,导致长代码不再自动换行,也就不会再出现下图的情况,可是他也无法支持自动换行了。它的代码块也不同于 2.x 版本,3.x 代码块是只有一个大的 table,行号放在一个 td 内,代码放另外一个 td 里。选取多行代码时,就只能选取到存放代码的 td 里的内容,所以不会复制到行号。

3.x 强行自动换行效果
3.x 强行自动换行效果
3.x 结构示例
3.x 结构示例

 

作为一个追求完美的强迫症来说,2.x 的使用工具栏的 查看源代码 进行复制多行代码和 3.x 的无法自动换行都是无法接受的。于是,博主在想有没有不改变整体结构的情况下同时支持自动换行和避免行号被复制。

 

开始时,博主想到使用 javascript 来阻止复制到行号,但是仔细想了想就放弃了。javascript 要阻止你复制全部内容是很容易的,但是它并不能做到阻止复制小范围的特定内容。

这里插一句:由于博主的性格和习惯,那些太古老的浏览器版本就不打算再支持了,本博客在 IE 8 下还算能看,只是圆角全部失效,但是在 IE 7 及以下版本的 IE 浏览器下,简直惨不忍睹。所以博主的想法是,最基本的浏览器都应该是 IE 9 以上了,而 IE 9 已经支持部分 HTML 5 和 CSS 3 了。

 

后来,博主想到了一个 css 3 属性——user-select,详细点这里。这个属性可是一个好属性,通过它,我们可以利用这个新属性轻松精确的控制用户可以选择哪些文本。

这个属性可以设置 4 个值:nonetextallelement,其中 element 属性只在 IE 下有效。而这个属性需要添加特定的浏览器标识,即 -webkit-user-select-moz-user-select-ms-user-select

none:任何内容都不允许被选中
text:只允许选中文本内容
all:所有内容都可以选中
element:选中的内容受到元素边界的约束

各浏览器对该属性的支持见下图:

user-select 浏览器支持情况
user-select 浏览器支持情况

 

于是我马上开始测试:

先写一个简单的 HTML,仿照 2.x 版本的结构,css 属性添加上 .number {-moz-user-select: none;-webkit-user-select: none;-ms-user-select: none;},以后给行号加上 class="number"

测试结果:

IE 10、IE 11:想直接选中行号是不行的,但是先从其他文本选中,就会顺带把行号选中。

IE 10、IE 11 测试效果
IE 10、IE 11 测试效果

使用 Ctrl+CCtrl+V 后,结果还是复制到了行号,果然是所见即所得啊。

#我是第一行我是第一行我是第一行我是第一行我是第一行我是第一行我是第一行
13  #我是第二行我是第二行我是第二行我是第二行我是第二行我是第二行我是第二行
14  #我是第三行我是第三行我是第三行我是第三行我是第三行我是第三行我是第三行
15  #我是第四行我是第四行我是第四行我是第四行我是第四行我是第四行我是第四行

Chrome 38:不管怎么选,都无法选中行号,只能选中后面的文字。(果然壮哉我大 Chrome (〜 ̄△ ̄)〜)

Chrome 测试效果
Chrome 测试效果

使用 Ctrl+CCtrl+V 后,呵呵,Chrome 这个奇葩,结果…行号都带着呢,坑货,比 IE 还奇葩 (╯°口°)╯(┴—┴。

#我是第一行我是第一行我是第一行我是第一行我是第一行我是第一行我是第一行
13  #我是第二行我是第二行我是第二行我是第二行我是第二行我是第二行我是第二行
14  #我是第三行我是第三行我是第三行我是第三行我是第三行我是第三行我是第三行
15  #我是第四行我是第四行我是第四行我是第四行我是第四行我是第四行我是第四行

FireFox:由于我没装火狐浏览器,就没做测试了,网上查了查。FireFox 在选中时,除了第一个行号,其他行号都会被选中。但是使用 Ctrl+CCtrl+V 后,行号都没有被黏贴上,这就是我们想要的效果。

 

最后发现:

只有 FireFox 可以使用 user-select 属性阻止用户复制到行号的,然而选中时会显示行号被选中,容易给人误导。

Chrome 虽然选中时显示行号没被选中,但是实际复制时还是会带上行号,奇了个葩的。

IE 10+ 充分地吸取了上面两者的弊端,行号既会被选中,也会被复制,但 IE 最诚实,所见即所得嘛,是不是应该夸奖下 (-_-#)。

 

这个最靠谱的方法都失败了,博主又在网上找啊找,最后找到了一个方法:通过把行号放进添加了属性 disabled="disabled"input 来阻止行号被复制,原博客。结果嘛,想出这个办法的人去除了行号… _(:3」∠)_

<input disabled="disabled" type="text" value="01" />

至少效果是:选中是看起来还是会选中行号,结果…我没试,但是即使可以阻止复制行号,样子是很难看的。

 

下面给出最终结论:

代码高亮插件 SyntaxHighlighter Evolved 的行号问题果然是一个无法解决的难题。要是你既不想使用工具栏的 查看源代码,又不想出现横向滚动条,博主的建议是——请不要显示行号

这确实是一次失败的尝试 (╯°口°)╯(┴—┴

 

在设置不显示行号后,连左边的绿条和容器的边框都被去掉了,这样式,简直了,于是为了找回遗失的绿条和边框,可以在主题样式中加上以下两段:

:root .syntaxhighlighter-gutter.nogutter {
  border:1px solid #E0E0E0 !important;
}

:root .syntaxhighlighter-gutter.nogutter .line .content {
  border-left:3px solid #6CE26C !important;
}

然后在插件设置界面的附加 CSS 处加上 syntaxhighlighter-gutter

不过这就有个问题了,对于古老的IE 6-IE 8,是不支持 :root 这个 CSS 3 选择器的,于是在 IE 6-IE 8上,依旧没有效果。


原创文章,转载请以链接形式注明出处:https://blog.ttionya.com/article-518.html