用一行代码修复 Dev.to 的滚动条错误

2025-06-08

用一行代码修复 Dev.to 的滚动条错误

很多文章都是事后才写的,作者要么忘记了,要么理所当然地认为他们犯了逻辑上的跳跃。这篇文章是我在解决问题的过程中写的,甚至在我知道自己能够解决这个问题之前。我希望这篇文章能让你更好地了解错误修复过程,从头到尾。闲话少叙:

=====================================

我正在编辑文章时,发现了一个非常恼人的问题——我输入的每个字符都会导致滚动条出现和消失。我的第一反应是打开开发者控制台查看,结果看到的是:

-oooooooo/-      .+ooooooooo:  +ooo+        oooo/
+MMMMMMMMMMm+   -NMMMMMMMMMMs  +MMMM:      /MMMM/
+MMMNyyydMMMMy  /MMMMyyyyyyy/   mMMMd      mMMMd
+MMMm    :MMMM. /MMMN           /MMMM/    /MMMM:
+MMMm    .MMMM- /MMMN            dMMMm    mMMMh
+MMMm    .MMMM- /MMMMyyyy+       :MMMM/  +MMMM-
+MMMm    .MMMM- /MMMMMMMMy        hMMMm  NMMMy
+MMMm    .MMMM- /MMMMoooo:        -MMMM+oMMMM-
+MMMm    .MMMM- /MMMN              yMMMmNMMMy
+MMMm    +MMMM. /MMMN              .MMMMMMMM.
+MMMMdddNMMMMo  /MMMMddddddd+       sMMMMMMs
+MMMMMMMMMNh:   .mMMMMMMMMMMs        yMMMMs
.///////:-        -/////////-         .::.

Hey there! Interested in the code behind dev.to? Well you're in luck - we're open source! Come say hi, tell us what you're debugging, or even lend a hand in our repo - https://github.com/thepracticaldev/dev.to
Did you find a bug or vulnerability? Check out our bug bounty info here: https://dev.to/security
Enter fullscreen mode Exit fullscreen mode

我很惊喜他们居然有安全漏洞悬赏计划。我继续研究悬赏计划,然后突然想起有个问题需要解决。

我打开了代码库,并在他们的问题中搜索“滚动条”。我偶然发现了https://github.com/thepracticaldev/dev.to/issues/3330,它描述了我遇到的确切问题。奇怪的是,只有一个用户报告了这个问题——这肯定比较罕见。或者人们不知道去 GitHub 报告这个问题。我创建AREPL的经验告诉我,对于人们费心报告的每一个问题,根据遥测数据,它可能已经发生过多次了。

在确认这是一个已报告的问题(带有“求助”标签!)后,我回到了开发工具。我注意到每次输入时,文本区域的高度样式都会发生变化。

之前:(无滚动条)

<textarea style="height: 968px;" class="articleform__body" id="article_body_markdown" placeholder="Body Markdown" name="body_markdown" ></textarea>
Enter fullscreen mode Exit fullscreen mode

之后:(滚动条)

<textarea style="height: 924px;" class="articleform__body" id="article_body_markdown" placeholder="Body Markdown" name="body_markdown"></textarea>
Enter fullscreen mode Exit fullscreen mode

这说得通——只有当高度不够显示所有内容时才会出现滚动条。但为什么高度会变呢?我又不是在换行,只是在现有行中添加了一个字符。真奇怪。

在这期间,我突然意识到——我可以写一篇关于这个的文章!这可以很好地记录我解决问题的思路。缺点是现在已经没有回头路了——如果我解决不了,我就会……

等等!我的天哪——我刚刚也遇到了一模一样的 bug:

错误演示
由flux提供的可怕的黄色

我暂时只能用记事本来记录了。不过,万幸的是,我可以重现这个问题。我把下面这段文字粘贴到一个新的草稿里。结果……啊,问题并没有出现在那里。后来我才想起,根据问题报告,只有当代码行数达到一定数量时才会出现这种情况。于是,我又在前面加了 21 行,问题又出现了🐛!

错误演示

下一个问题是,如果超过一定行数就会出现这种情况,为什么不是每个人都遇到这个问题?dev.to 的作者之间是否有一个不成文的约定,规定不要超过 21 行,就像 Twitter 的字符限制一样?我非常怀疑。我肯定漏掉了什么。也许与我输入的文本有关。

稍微修改了一下文本后,我发现如果删除行中的“I'll have a” The downside is there's no turning back now - If I fail to solve this I'll have a,问题就不再出现了。只有当行超出草稿宽度时,问题才会出现。

现在我应该可以创建一个最小可复现的示例了。我打开一个新草稿,输入“aaa....”直到溢出一行,然后添加了 21 行。没有错误🤔。

我又稍微修改了一下结尾,发现错误只会在非常特殊的情况下发生,即空格超出了草稿宽度。任何普通字符都会直接跳到下一行,但你可以在现有行中添加任意数量的空格。

现在我可以复现了,这已经成功了一半。接下来是调试!

但在此之前,我想检查一下——我在设置中注意到我正在使用 V1 编辑器。这个问题在 V2 编辑器中还会出现吗?

没有。问题并没有出现在那里。
而且比我想象的还要严重——新用户默认使用 v2 编辑器,所以这个问题只影响像我这样的老用户,而且只影响一小部分老用户。

好吧,这真是浪费时间。:|

好的一面是,我可以把解决方案(切换到 v2 编辑器)发到问题评论里,这样应该能帮到一些人。为了自尊,我会花 10 分钟时间尝试解决这个问题。现在就开始。

十一分钟后

事实证明,这个问题在 v2 编辑器中仍然存在,幸好我再次检查了一下。只是在 v2 编辑器中,当你的空格超过草稿宽度时,光标会停留在同一个位置,所以看起来一切正常。但稍微调整一下,仍然可能会重现错误。

现在我们开始调试吧。
终于,你说对了!

我为 textarea 元素的属性修改设置了一个断点。我编辑了该元素,导致高度发生变化,最终导致代码在断点处停止。可惜的是,该文件是空白的,所以我看不到代码停止的地方。不过,我查看了堆栈跟踪,发现在文件夹TextareaAutosize.js的 文件夹中有一个名为 的文件。所以,dev.to 的textarea 实现使用了preact (React 的变体)包。我用 Google 搜索了一下,找到了https://github.com/DisplaySweet/preact-textarea-autosize,结果出现了 404 错误。preact-textarea-autosizenode_modules

因此我转到下一个链接——npm 包:

https://www.npmjs.com/package/preact-textarea-autosize

代码库链接指向https://github.com/evenius/react-textarea-autosize,它已经两年多没有更新了,而且也没有问题版块。这很好。然而,它是从一个更受欢迎的代码库fork 过来的,这个代码库确实存在问题,并且有一个演示网站。我搜索了相关问题,但没有找到那里报告的滚动条问题。我去了演示网站,结果发现,你可以在他们的演示网站上重现这个问题!所以问题可能不在于 dev.to 代码,而在于调用库的方式,或者库本身的问题。

现在已经凌晨一点了,所以我去睡觉了。睡眠对健康有益,大家。

我,准备睡觉了:
哈巴狗,不知何故既是世界上最可爱又最丑陋的动物:

第二天,我在15Five结束了一天的忙碌工作,读了大约 100 页的Scythe之后,又回去工作了。我把昨天的工作记录了下来,并在过程中发现了另一个react-autosize-textarea名为. (不要与 混淆react-textarea-autosize的 React Textarea 包。它们有多少个??虽然 dev.to 上的 textarea 脚本显示为空白,但我注意到它是从捆绑文件中源映射过来的,于是我点击了左下角的小 {} 来美化打印,在库中搜索与最近提交匹配的代码,并确认我找的是正确的。呼。已经过去一个小时了,现在我终于可以开始调试了。

你不是已经打算这么做了吗?

呃,是的。总之:

我开始尝试调试打包的最小化代码,结果简直是一场噩梦。我很快做出了明智的决定——放弃,克隆了代码库,并制作了一个可复现的示例,其中包含一些我可以轻松调试的代码。

或者至少我应该这么做。接下来的一个小时,我又回去尝试调试打包的代码。

哎呀

有趣的事实:看到断点所在的那一行了吗m=1/0?它对应于这一

let maxHeight = Infinity;

你没看错,在 JavaScript 中,1/0 等于无穷大!如果你真的想看得晕头转向,试试在控制台里执行这行代码(按 F12 键打开):

"b" + "a" + +"a" + "a"

输出是 baNaNa。我是说,呃。你还指望什么呢。不过,JavaScript 的 WTF 本身就是一本好书1。让我们回到正题。

我以为代码是每隔一个字符设置一次高度,但结果好像不是这样。calculateNodeHeight执行时,textarea 的高度已经不一样了。我猜想这与原生 textarea 的工作方式以及 HTML 的约束有关。谜团越来越深了……

我尝试在Winmerge中比较两个文本区域对象,但没有发现任何可疑之处。

如果这是 HTML 的问题,那就该去学习一下了。我读了https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight。然后我突然意识到:为什么一开始还要滚动条呢?浏览器屏幕边缘已经有滚动条了。已经把文本区域无限扩展到2 的react-textarea-autosize长度了。滚动条完全没必要。

于是我在 Google 上搜索“禁用滚动条”,偶然发现了一篇论坛帖子,推荐了这种 CSS 样式overflow:hidden。它可以禁用滚动条——你可以在这里hidden阅读更多overflow选项。把它应用到 textarea 样式上,问题就解决了!🎉

接下来我尝试了不同的页面布局——它还能在半窗口宽度下工作吗?四分之一窗口宽度下?手机上?iPad上?答案是肯定的,肯定的,肯定的,肯定的。


感谢 chrome devtools 的这个可爱功能,我能够从我的笔记本电脑上测试所有的移动布局,甚至不需要手机。

现在浏览器又不一样了。我把它放到IE浏览器里,结果吓坏了,页面竟然没有滚动条,这说明textarea必须得有滚动条!我的计划泡汤了!IE浏览器该死!3

但后来我注意到,页面甚至没有“保存更改”按钮——它已经完全崩溃了,我根本不用担心支持 IE。问题就这么解决了。

然后我尝试了 Edge。我输入了大约 19 行,但当我输入新行时,垂直滚动条开始随机闪烁。哇哦。你甚至可以在底部的页脚内输入内容——你甚至可以看到那里的光标。所以 Edge 已经有很多 bug 了(我怎么就不惊讶了)。添加后overflow:hidden解决了垂直滚动条的问题,并且没有在其他地方引发其他问题。

最后我尝试了 Firefox。修复后,这个问题甚至在 Firefox 中都没有出现,Firefox 真棒!

确认修复有效后,我创建了一个PR。甚至不需要打开编辑器——我只需打开https://github.com/thepracticaldev/dev.to/blob/master/app/assets/stylesheets/preact/article-form.scss,点击编辑铅笔图标,进行修改,然后提交即可。Github 自动创建了 fork 的仓库——然后我点击“创建 Pull 请求”,填写一个简短的模板描述修改内容,就大功告成了!

女人在快乐中旋转

嗯,不完全是。审阅者有一条评论(审阅者总是这样),要求提供前后对比图。有了ShareX,提供起来相当简单。几天后,我的 PR 就被合并了!

你可以自己检查一下——创建一个新文章,右键单击文本区域,然后单击检查元素,下面.articleform__body有一行 css,overflow: hidden可以防止滚动条出现🎉

那么,我们可以从中得到什么呢?

  1. Bug 可以用意想不到的方式解决。你应该留意各种变通方法、捷径和其他新颖的方法来彻底绕过问题。这绝不是使用肮脏、难以理解的 hack 的借口。(看看你的正则表达式,亲爱的,爱你,但你确实遇到了一些问题)记住,过早优化是万恶之源,你阅读代码的时间会远远超过编写代码的时间。
  2. 进入开源世界,你不需要任何高深的算法知识,也不需要昂贵的MacBook。你只需要一个网页浏览器。随着repl.it等软件的进步,几乎所有事情都可以在云端完成。你可以用所有空闲的硬件空间来拍性感的黄瓜照片(恕不评判)。
  3. 更多的公司应该开源他们的代码。这样你就能免费贡献代码,还能获得免费的公关宣传。在某些情况下,贡献者可以成为员工,为你节省数千美元的招聘成本。最终,开源打破了“通过隐藏实现安全4 所带来的虚假安全感——开源意味着你必须确保代码安全,以免被人看到。尽管实际上只有少数人会费心寻找漏洞,其中大多数可能是安全研究人员或赏金猎人。你确实有安全赏金,对吧?
  4. 修复 Bug 的大部分工作在于重现 Bug、找出 Bug 发生的原因、找到修复方案并测试修复方案。编码只是其中很小的一部分。
  5. 遇到问题时,请尝试找到相关的 GitHub 仓库并向维护人员报告问题。只需提供详细的复现步骤,就能帮他们大忙5,有时仅仅是研究问题本身就能让你找到解决方法(或者让你觉得自己是个傻瓜,做了蠢事)。最后,如果代码是开源的,修复它也是有可能的!只是需要付出一些努力🔨。

  1. 请参阅https://github.com/denysdovhan/wtfjs  

  2. 如果你想深入研究技术,你“最多”能读几十亿行代码,内存就用完了。UTF-8 编码下,每个 ASCII 字符占一个字节,所以 4GB 的内存足够容纳 40 亿个字符。你懂的越多越好!~~~ ⭐ 

  3. 我当时正想找一张图片来做这个,结果看到了这张绝妙的复古表情包。它简直太精彩了,简直糟糕透了,我差点就把它放进去了 。↩

  4. 请注意,模糊性作为纵深防御措施是可以的,只是你不应该依赖它 。↩

  5. 一份好的 Bug 报告包含五个部分:A. 摘要 B. 复现步骤 C. 预期结果 D. 实际结果 E. 当前设置(例如:Windows、Chrome)以及你是否真的想要解决问题 F. 问题的图片/视频。这样的报告会让开发者对你赞不绝口😇。大多数问题只有 A 部分写得很糟糕,甚至连理解到底发生了什么都让人很沮丧 。↩

鏂囩珷鏉ユ簮锛�https://dev.to/almenon/fixing-dev-to-s-scrollbar-bug-with-a-single-line-of-code-4f8l
PREV
我做了一个开源平台来学习计算机科学。如果你对 MERN 技术栈感兴趣,可以看看这个。
NEXT
克服解决问题的挑战 回归基础(有点)熟能生巧(不,真的)