博客里的代码框一直有个问题,每行的内容太长,代码框的宽度没法完整容纳一行。网上有过加横向滚动条、鼠标移上去就代码框自动加长这两种解决方案,但都不太美观。自动换行的方案符合大部分人的习惯,于是我研究了代码框的自动换行。本文设置了一个“行号和内容分开复制、代码自动换行并不影响自动高亮”的代码框,文中有可以用的代码以及用到属性的归纳。
基础的HTML代码博客生成的代码框,格式经过简化就是如下的内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <figure class ="highlight javascript" > <table > <tbody > <tr > <td class ="gutter" > <pre > <span class ="line" > 0</span > <br > <span class ="line" > 1</span > <br > <span class ="line" > 2</span > <br > </pre > </td > <td class ="code" > <pre > <span class ="line" > "a "<span class ="keyword" > very</span > " very long line"</span > <br > <span class ="line" > a very very long line</span > <br > <span class ="line" > a very very long line</span > <br > </pre > </td > </tr > </tbody > </table > </figure >
这些代码均为自动生成,也没有什么可以讨论的。代码高亮通过span实现;由于代码与行号生成在两个td中,所以复制代码的时候不会复制到行号。
换行的CSS设置换行涉及到三个内容,具体实现的代码为:
1 2 3 4 figure .code span { white-space : pre-wrap; word-break : break-all; }
其中分别的作用为:
white-space:设置元素中的空白符如何处理
overflow-wrap:设置完整单词的断开方式(未用到)
word-break:设置完整单词(包含汉语等的句子)的断开方式
white-space空白符的处理简而言之是这样一张表:
属性
多个换行
空格和换行
自动换行
行末空格
normal
保留一个
保留一个
是
移除
nowrap
保留一个
保留一个
否
移除
pre
保留
保留
否
保留
pre-wrap
保留
保留
是
保留不换行
pre-line
保留
保留一个
是
移除
break-spaces
保留
保留一个
是
保留换行
我们的代码,对于多个换行需要全部保留,多个空格和换行需要全部保留,需要自动换行,行末空格保留但不需要因为空白字符换行。所以就white-space的属性可以选择pre-wrap。
overflow-wrap虽然空白符处理中我们设置了需要换行,但是过长的单词还是会导致行宽超出预设的宽度。
属性
如何处理过长单词
normal
保留
break-word
断开
我们不希望因为有过长的单词导致出现横向滚动栏,所以这里可以选择break-word。但考虑到与word-break属性的作用重合,而且word-break属性更适合汉语的特别处理,所以就不再使用overflow-wrap。
word-break换行的设置也可以使用这个,这个属性可以将汉语整句视为一个单词不换行(直到有标点符号为止)。
属性
英文处理
中文处理
normal
不断开单词
断开句子
break-all
断开单词
断开句子
keep-all
不断开单词
不断开句子
break-word
可能的话不断开单词
断开句子
其中break-all与break-word的区别为:若一行可以容纳一个单词但是无法容纳两个,break-all将断开第二个单词,break-word将把第二个单词放在第二行。
根据要求,我们就选用了break-all。这里其实和使用overflow-wrap: break-word是一样的效果。
换行的JS设置自动换行之后就需要行号的位置根据代码的长度做相应变化,博客里本来有代码框自动调整宽度的代码,这里将行高的调整也加进去。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 +function ($ ) { 'use strict' ; var CodeBlockResizer = function (elem ) { this .$codeBlocks = $(elem); }; CodeBlockResizer.prototype = { run: function ( ) { var self = this ; self.resize(); $(window ).smartresize(function ( ) { self.resize(); }); }, resize: function ( ) { var self = this ; self.$codeBlocks.each(function ( ) { var $gutter = $(this ).find('.gutter' ); var $code = $(this ).find('.code' ); var codePaddings = $code.width() - $code.innerWidth(); var width = $(this ).outerWidth() - $gutter.outerWidth() + codePaddings; $code.css('width' , width); $code.children('pre' ).css('width' , width); for (var i = 0 , m = $gutter.find('span' ).length; i < m; i++) { $gutter.find('span' ).eq(i).height( $code.find('span.line' )[i].offsetHeight); } }); } }; $(document ).ready(function ( ) { $.fn.hasHorizontalScrollBar = function ( ) { return this .get(0 ).scrollWidth > this .innerWidth(); }; var resizer = new CodeBlockResizer('figure.highlight' ); resizer.run(); }); }(jQuery);
这里与行号位置相关的部分就是29-32行的内容,根据offsetHeight调整height。
仅是这样还是无法更改行号的位置,原因在于目前显示代码使用的都是span元素。我们若需要通过height调整行号所占的高度,应将其显示方式改为inline-block,所以增加如下CSS:
1 2 3 4 figure .highlight pre > .line { display : inline-block; line-height : 18px ; }
其中如果不设置display: inline-block,line-height与height也将不相同,可能出现的小数将导致不必要的麻烦。
到这里就完成了全部关于代码换行的设置。