展示HN:OverType – 一个仅仅是文本区域的Markdown所见即所得编辑器

24作者: panphora6 个月前原帖
嗨,HN!我对现代的所见即所得(WYSIWYG)编辑器感到非常沮丧,因此我开始尝试自己构建一个。 我遇到的问题很简单:我想要一种低技术的方式来输入格式化文本,但我不想加载一个复杂的500KB库,尤其是在同一页面上需要初始化多次的情况下。 在普通的 `<textarea>` 中使用 Markdown 是一个比完整 WYSIWYG 更好的替代方案,但它的主要缺点是没有任何格式时看起来很丑。我可以接受,但我的客户肯定无法接受。 我在可编辑内容(ContentEditable)方面探索了几年,但总是意识到别人解决这个问题的方式比我想象的要好得多。 我不断回到这个问题:为什么我不能拥有一个简单、高效、美观的 Markdown 编辑器?我见过的最好的解决方案是 Ghost 的分屏编辑器:左侧是 Markdown,右侧是预览,并且支持同步滚动。 大约一年前,我脑海中闪现了一个想法:如果我们在 `<textarea>` 后面叠加一个预览窗格会怎样?如果我们将它们完美对齐,那么即使你只是在编辑纯文本,它看起来和感觉起来也像是在编辑富文本! 当然,这样做会有一些缺点:你必须使用等宽字体,所有内容必须使用相同的字体大小,并且所有的 Markdown 标记必须在最终预览中显示。 但这些都是我可以接受的权衡。 总之,版本 1 的效果并不好……事实证明,保持 `<textarea>` 和渲染预览的对齐比我想象的要难。以下是我发现的问题: - 列表对齐困难 - 项目符号会影响字符对齐。通过使用保持等宽的 HTML 实体(• 作为项目符号)解决了这个问题。 - 并非所有等宽字体都是真正的等宽 - 即使在“等宽”字体中,粗体和斜体文本的宽度也可能不同,打破了完美的叠加效果。 - 嵌入是个噩梦 - 从父页面继承的任何 CSS(边距、内边距、行高)都会导致对齐偏移。即使是 1 像素的偏移也会彻底破坏这种错觉。 解决方案是进行强迫规范化: ```javascript // 整个技巧:在预览 div 上叠加一个透明的 textarea layerElements(textarea, preview) applyIdenticalSpacing(textarea, preview) // 使 textarea 隐形,但保持光标可见 textarea.style.background = 'transparent' textarea.style.color = 'transparent' textarea.style.caretColor = 'black' // 保持它们同步 textarea.addEventListener('input', () => { preview.innerHTML = parseMarkdown(textarea.value) syncScroll(textarea, preview) }) ``` 一周前,我开始尝试版本 2,并发现 GitHub 的 `<markdown-toolbar>` 元素,它在普通的 `<textarea>` 中处理 Markdown 格式化非常好。 这个实验变成了 OverType([https://overtype.dev](https://overtype.dev)),今天我向你们展示的就是这个——它是一个富 Markdown 编辑器,实际上只是一个 `<textarea>`。关键的见解是,一旦你解决了对齐问题,你就可以免费获得所有原生 textarea 提供的功能:撤销/重做、移动设备键盘、可访问性和原生性能。 到目前为止,它在各个浏览器和移动设备上表现得相当不错。我在一个小包(总共 45KB)中获得了高效的富文本编辑。这有点傻,但它确实有效!我计划在我所有的项目中使用它,并希望保持简单和简约。 如果你能试用一下,并告诉我你的想法,我会非常高兴。祝你编辑愉快! --- 演示和文档:[https://overtype.dev](https://overtype.dev) GitHub:[https://github.com/panphora/overtype](https://github.com/panphora/overtype)
查看原文
Hi HN! I got so frustrated with modern WYSIWYG editors that I started to play around with building my own.<p>The problem I had was simple: I wanted a low-tech way to type styled text, but I didn&#x27;t want to load a complex 500KB library, especially if I was going to initialize it dozens of times on the same page.<p>Markdown in a plain &lt;textarea&gt; was the best alternative to a full WYSIWYG, but its main drawback is how ugly it looks without any formatting. I can handle it, but my clients certainly can&#x27;t.<p>I went down the ContentEditable rabbit hole for a few years, but always came to realize others had solved it better than I ever could.<p>I kept coming back to this problem: why can&#x27;t I have a simple, performant, beautiful markdown editor? The best solution I ever saw was Ghost&#x27;s split-screen editor: markdown on the left, preview on the right, with synchronized scrolling.<p>Then, about a year ago, an idea popped into my head: what if we layered a preview pane behind a &lt;textarea&gt;? If we aligned them perfectly, then even though you were only editing plain text, it would look and feel like you were editing rich text!<p>Of course, there would be downsides: you&#x27;d have to use a monospace font, all content would have to have the same font size, and all the markdown markup would have to be displayed in the final preview.<p>But those were tradeoffs I could live with.<p>Anyways, version 1 didn&#x27;t go so well... it turns out it&#x27;s harder to keep a textarea and a rendered preview in alignment than I thought. Here&#x27;s what I discovered:<p>- Lists were hard to align - bullet points threw off character alignment. Solved with HTML entities (• for bullets) that maintain monospace width<p>- Not all monospace fonts are truly monospace - bold and italic text can have different widths even in &quot;monospace&quot; fonts, breaking the perfect overlay<p>- Embedding was a nightmare - any inherited CSS from parent pages (margin, padding, line-height) would shift alignment. Even a 1px shift completely broke the illusion<p>The solution was obsessive normalization:<p><pre><code> &#x2F;&#x2F; The entire trick: a transparent textarea over a preview div layerElements(textarea, preview) applyIdenticalSpacing(textarea, preview) &#x2F;&#x2F; Make textarea invisible but keep the cursor textarea.style.background = &#x27;transparent&#x27; textarea.style.color = &#x27;transparent&#x27; textarea.style.caretColor = &#x27;black&#x27; &#x2F;&#x2F; Keep them in sync textarea.addEventListener(&#x27;input&#x27;, () =&gt; { preview.innerHTML = parseMarkdown(textarea.value) syncScroll(textarea, preview) }) </code></pre> A week ago I started playing with version 2 and discovered GitHub&#x27;s &lt;markdown-toolbar&gt; element, which handles markdown formatting in a plain &lt;textarea&gt; really well.<p>That experiment turned into OverType (<a href="https:&#x2F;&#x2F;overtype.dev" rel="nofollow">https:&#x2F;&#x2F;overtype.dev</a>), which I&#x27;m showing to you today -- it&#x27;s a rich markdown editor that&#x27;s really just a &lt;textarea&gt;. The key insight was that once you solve the alignment challenges, you get everything native textareas provide for free: undo&#x2F;redo, mobile keyboard, accessibility, and native performance.<p>So far it works surprisingly well across browsers and mobile. I get performant rich text editing in one small package (45KB total). It&#x27;s kind of a dumb idea, but it works! I&#x27;m planning to use it in all my projects and I&#x27;d like to keep it simple and minimal.<p>I would love it if you would kick the tires and let me know what you think of it. Happy editing!<p>---<p>Demo &amp; docs: <a href="https:&#x2F;&#x2F;overtype.dev" rel="nofollow">https:&#x2F;&#x2F;overtype.dev</a><p>GitHub: <a href="https:&#x2F;&#x2F;github.com&#x2F;panphora&#x2F;overtype" rel="nofollow">https:&#x2F;&#x2F;github.com&#x2F;panphora&#x2F;overtype</a>