带行号的预格式化文本响应式样式异常问题排查
我自己写了一段JS给预格式化文本添加样式,没有使用专门的语法高亮工具,但在响应式模式下出现了布局错乱的问题。我给.code-inner设置了width:80%,但它仍然会占据全屏宽度。想请教这是不是overflow:auto属性导致的溢出问题,还是我的代码存在错误?
以下是我的实现代码:
JavaScript 代码
function preformatted() { var pre = document.getElementsByTagName('pre'), pl = pre.length; if(jQuery(pre).find('.line-number').length){ return; } for (var i = 0; i < pl; i++) { pre[i].innerHTML = '<span class="line-number"></span>' + pre[i].innerHTML + '<span class="cl"></span>'; var num = pre[i].innerHTML.split(/\n/).length; for (var j = 0; j < num; j++) { var line_num = pre[i].getElementsByTagName('span')[0]; line_num.innerHTML += '<span>' + (j + 1) + '</span>'; } } } preformatted();
CSS 代码
.code-inner { position: relative; width: 80%; } pre { overflow:auto; margin:0 0 1em; padding:.5em 2em; white-space: pre-line; } .code-wrap { background: linear-gradient(to right, #264567 60px, #73b9ff 0% 80%); width: 100%; height: 200px; padding: 20px 10px; border-radius: 5px; box-shadow: 0 0 18px -7px #000; overflow-y: scroll; } pre code, pre .line-number { font:normal normal 16px/14px Lato, "Courier New",Courier,Monospace; color:black; display:block; line-height: 30px; } pre .line-number { float:left; margin:0 1em 0 -1em; text-align:right; color:#fff; } pre .line-number span { display:block; padding:0 .5em 0 1em; } pre .cl { display:block; clear:both; } /* Vertical Scroll */ .code-wrap::-webkit-scrollbar { width: 4px; } /* Track */ .code-wrap::-webkit-scrollbar-track { border-radius: 10px; margin: 10px; } /* Handle */ .code-wrap::-webkit-scrollbar-thumb { background: #fff; border-right: 4px #555555 solid; }
HTML 代码
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <div class="code-inner"> <div class="code-wrap"> <pre> <code> ° Vivamus feugiat quam sed ipsum varius aliquam. ° In ac augue eu leo dignissim cursus hendrerit sed nulla. ° Sed dapibus justo id lectus rhoncus pulvinar. ° Aliquam sit amet enim ut nisl gravida lobortis. ° Nunc a sapien non lorem mollis viverra. ° Donec feugiat nunc quis condimentum feugiat. </code> </pre> </div> </div>
问题根源分析
咱们来一步步拆解问题:
盒模型计算错误导致宽度溢出
你给.code-wrap设置了width:100%,同时还加了padding:20px 10px。默认情况下,CSS的盒模型是content-box,也就是元素的总宽度=设置的width + padding + border。这就导致.code-wrap的实际宽度会是.code-inner的80%宽度再加上左右各10px的padding,直接撑破了父容器,看起来就像.code-inner占了全屏。white-space属性设置不当
你给<pre>设了white-space:pre-line,这个属性会合并连续空格,只保留换行符,但<pre>标签的初衷是保留原始的换行和空格。同时这个设置加上overflow:auto,在内容溢出时会触发横向滚动,但父容器宽度已经计算错误,进一步加剧了布局混乱。JS行号计数的小bug
你的JS用pre[i].innerHTML.split(/\n/).length来统计行数,但innerHTML会包含HTML标签,拆分出来的换行数量可能不准确,导致行号多生成或者少生成,间接影响布局对齐。
具体修复方案
1. 统一盒模型(最关键)
给所有元素添加box-sizing:border-box,让padding和border都包含在设置的width里面,避免溢出:
* { box-sizing: border-box; }
2. 调整容器宽度设置
把.code-wrap的width:100%去掉(或者保留也没关系,因为border-box已经让它的宽度计算正确了),同时给.code-inner加个margin:auto让它居中,更符合视觉习惯:
.code-inner { position: relative; width: 80%; margin: 0 auto; /* 新增:让容器居中 */ } .code-wrap { background: linear-gradient(to right, #264567 60px, #73b9ff 0% 80%); /* 去掉width:100%,块级元素默认占满父容器 */ height: 200px; padding: 20px 10px; border-radius: 5px; box-shadow: 0 0 18px -7px #000; overflow-y: scroll; }
3. 修正<pre>的换行行为
把white-space:pre-line改成white-space:pre-wrap,这样既保留预格式化的换行和空格,又能在容器宽度不足时自动换行,避免横向滚动条出现:
pre { overflow:auto; margin:0 0 1em; padding:.5em 2em; white-space: pre-wrap; /* 替换pre-line */ }
4. 修复JS的行号计数逻辑
用textContent代替innerHTML来拆分换行,这样就能获取到纯文本的真实行数,避免HTML标签干扰:
function preformatted() { var pre = document.getElementsByTagName('pre'), pl = pre.length; if(jQuery(pre).find('.line-number').length){ return; } for (var i = 0; i < pl; i++) { // 用textContent获取纯文本,统计真实行数 var lineCount = pre[i].textContent.split(/\n/).length; pre[i].innerHTML = '<span class="line-number"></span>' + pre[i].innerHTML + '<span class="cl"></span>'; var line_num = pre[i].getElementsByTagName('span')[0]; for (var j = 0; j < lineCount; j++) { line_num.innerHTML += '<span>' + (j + 1) + '</span>'; } } } preformatted();
修复后的效果
做完这些修改后:
.code-inner的80%宽度会正确生效,不会被子容器撑破- 响应式模式下,容器会随屏幕宽度自适应缩放,布局不会错乱
- 行号和代码的对齐会更准确,滚动条也能正常工作
内容的提问来源于stack exchange,提问作者MAQ Khan

