☰
备忘录删除线实现:富文本属性与U+0336组合字符路线选型
2026/10/31 5:02:31 网站建设 项目流程

做便签类产品的这几年,被问得最多的一类问题不是同步、不是加密,而是——"你家备忘录能不能在字中间划一条线"。这个需求听起来简单到不值一提:把一段文字划掉,字还在,但明显被标记成"作废"或"已完成"。可真动手做,你会发现备忘录划删除线这件事分成了两条完全不同的技术路线:一条是给文字打上"删除线"这个格式属性,另一条是干脆把横线当成一个字符,硬粘在每一个字的中间。前者是格式,后者是字符,两者在便签里长得几乎一模一样,行为却天差地别——一个能被搜索到,一个搜不到;一个点两下能取消,一个取消不掉;一个复制到别处还在,一个可能瞬间崩成一串方块。

这篇东西想聊的就是这两条路怎么选、怎么做、怎么避坑。无论你是只想在手机便签里把已完成的事项划掉,还是想批量生成一段带横线的文字发到不支持格式的地方,又或者你正在做一个便签功能需要决定用哪种方案,下面的内容都能直接拿去用。我尽量把原理、参数、代码、踩坑都摊开讲,不绕弯子。

1. 先搞清楚"划掉"到底有几种做法

很多人把"划掉文字"当成一个功能,其实它是三个不同层次的东西。层次搞混了,后面所有的困惑都从这里开始:为什么我在A应用里划得好好的,复制到B应用就没了?为什么有的划线能删掉,有的删不掉?答案全在层次里。

1.1 格式层:真正的删除线属性

格式层的删除线,本质上是给一段文本附加了一个"装饰"标记。文字本身没变,码点没变,只是在渲染的时候,渲染引擎读到"这段有删除线"这个属性,于是在字符的垂直中线位置画一条横线。

这种做法的好处非常明显:文字还是原来的文字。你搜索"苹果"能搜到被划掉的"苹果",你复制它、粘贴它、导出它,语义都完整。取消也简单,选中文字点一下按钮就恢复了。手机上长按选中,在浮出的工具栏里找带横线的"abc"图标,或者去"Aa"字体面板里翻,位置各家略有差异,但路径大同小异。

它的问题在于:格式是有载体的。这段文字必须活在一个"认识格式"的环境里,删除线才存在。一旦离开这个环境,格式就丢了。这就是为什么你在备忘录里划得好好的文字,粘到短信、粘到搜索框、粘到某个只认纯文本的输入框,横线就凭空消失了——不是被吃掉了,是那个环境根本不知道有这回事。

1.2 字符层:把横线粘在字上的"假删除线"

字符层是另一套思路,也是"生成划掉的字"这类需求的核心。它不依赖任何格式属性,而是用 Unicode 里的组合附加符号,把一条横线"贴"在每个字符身上。

具体说,U+0336 这个码位叫 COMBINING LONG STROKE OVERLAY,翻译过来是"组合长横线覆盖"。它本身不占独立的字宽,作用是把一条横线叠加到它前面那个字符上。所以你写"苹果",得到的是"苹"、"果"三个码位;你写"苹̶果̶",得到的是四个码位——每个汉字后面多跟一个 U+0336。

这么干的好处是:它就是普通文字。任何能显示文字的地方都能显示它,不需要支持任何格式。发短信、发评论、填表单、写纯文本文件,横线都在。缺点是:它已经不是原来的文字了。搜"苹果"搜不到"苹̶果̶",因为码位对不上;有些字体缺这个组合符号的字形,会显示成方框或者位置飘移;字符长度直接翻倍,遇到有字数限制的输入框会被提前截断。

1.3 笔迹层:手写和批注

还有第三种,是手写笔迹或者批注层上的划线。它既不是格式也不是字符,而是在文字上方覆盖了一层独立的图形对象。平板上的手写备忘录、PDF 批注工具、截图标注工具,走的都是这条路。

这一层最自由,也最"假"——它跟文字没有任何绑定关系,你把文字挪走,线还在原地。所以它适合的是"我就要这个视觉效果",比如做一张像手写便签的图,不适合需要文字本身可编辑、可搜索的场景。

路线本质能否搜索复制到纯文本能否取消典型场景
格式层文本属性能丢失随时取消备忘录、文档、笔记
字符层组合符号不能保留需手动清洗跨平台文案、纯文本框
笔迹层独立图形完全无关丢失擦除手写便签、截图标注

2. 为什么同一个"删除线",在有的便签里能用有的不能

这个问题我被问过太多次:明明都是备忘录,凭什么你的能划、我的不能?答案不在"备忘录"这个名字上,而在它背后的存储模型上。叫法一样,内核能差出十万八千里。

2.1 三种底层存储模型决定了一切

第一种是纯文本模型。它只存字符,不存任何样式。系统自带的最基础记事本、命令行里的文本文件、某些极简便签,都属于这一类。你在这类工具里,永远找不到删除线按钮,因为它压根没有地方存"这段有横线"这个信息。想划线,只能用字符层的 U+0336 硬贴。

第二种是富文本模型。它存的是带标记的文档结构,每个字符可以带一组属性(字体、字号、颜色、加粗、斜体、删除线……)。系统自带的备忘录、主流云笔记、办公套件,基本都是这个模型。删除线是它的原生能力,点一下就行,而且随时可逆。

第三种是标记语言模型。它存的还是纯文本,但用一套约定的符号表达格式。最典型的就是 Markdown,两个波浪线包住一段文字,渲染出来就是删除线。它的妙处在于:存储层是纯文本(好同步、好版本管理、好搜索),显示层有格式(好看)。但前提是——你用的那个编辑器得认这套语法。同一个.md文件,在支持 GFM 的编辑器里横线正常,扔进一个不支持的编辑器里,你看到的就是两个波浪线原样躺在那儿。

这三种模型没有优劣,只有匹配。你如果只是自己记待办,富文本最省事;你要做的是跨设备同步的纯文本笔记库,Markdown 更稳;你在一个只吃纯文本的输入框里想划线,不好意思,只有字符层这一条路。

2.2 常见便签载体支持情况对照

下面这张表是我这几年在各种工具上反复试出来的,遇到"我这能不能划"的问题,先对号入座,能省掉一大半试错时间。

载体类型删除线实现方式操作入口注意事项
系统自带备忘录(移动端)富文本属性选中文字→工具栏找横线图标或"Aa"面板部分旧版本不支持,需更新
主流云笔记客户端富文本 / Markdown 双模工具栏按钮,或输入~~自动触发模式切换后格式可能丢失
Markdown 编辑器~~文字~~(GFM 扩展)手动输入语法标准 CommonMark 不支持,需确认渲染器
纯文本编辑器只能用 U+0336手动粘贴组合符长度翻倍、无法搜索
电子表格单元格格式属性快捷键 Ctrl+5 切换只对整格生效,不能只划半个字
文字处理软件字体属性Ctrl+D 打开字体面板勾选,或工具栏按钮可用于修订痕迹
网页表单 / 聊天输入框多数不支持格式只能贴 U+0336部分平台会过滤组合字符
手写 / 批注工具独立笔迹图层画笔直接划与文字不绑定,文字动线不动

2.3 复制粘贴为什么会丢格式

这是最容易被误解的一环。很多人以为"复制粘贴就是把看到的东西搬过去",实际上剪贴板搬运的是数据,不是像素。

当你从备忘录里复制一段带删除线的文字,剪贴板里通常会同时写入两三个版本:一个是纯文本版本(text/plain,只有字符),一个是富文本版本(text/html或者内部格式,带样式标记)。目标应用在粘贴时会自己挑:它支持富文本,就拿带样式的那份;它只支持纯文本,就拿纯字符那份,横线自然就没了。

所以你会看到一个非常典型的现象:同一段划掉的文字,粘进聊天窗口就废了,粘进另一个笔记应用却完好。这不是玄学,就是目标应用挑了哪份数据的问题。想让它"到哪都带横线",只有字符层能做到,因为字符层的横线本身就在text/plain里面,跑不掉。

提示:如果你需要一段"必须带横线"的文字,先想清楚它最终会落在什么环境里。落在支持格式的地方,用真删除线;落在纯文本框、短信、表单里,只能用组合字符。别指望一种方案通吃。

3. 富文本路线:在备忘录里正经画删除线

如果你的目标只是"在我自己的备忘录里把字划掉",那根本不用碰 Unicode,直接用富文本能力,又快又稳。这一节把各平台的操作路径和隐藏坑说清楚。

3.1 移动端备忘录的操作路径与坑

移动端的通用流程是三步:长按文字进入选择模式,拖动手柄选中要划掉的范围,然后在弹出的浮层工具栏里找删除线。

浮层工具栏的位置各家不同,大多藏在两个地方:一个是直接可见的格式条(一排图标里有带横线的字母),另一个是点开"Aa"或者画笔图标之后的次级面板。找不到的时候别急着怀疑人生,先看一下是不是文字还在选中状态——很多应用一旦你手指离开选区,工具栏就收起来了,你得重新选。

这里有几个我自己踩过的坑,值得单独拎出来说。

第一,划到一半的选区会连带格式。你在两个段落中间选,从第一段末尾拖到第二段开头,中间那个换行符也会被带上删除线属性,结果就是两段之间多出一条奇怪的横线空隙。解决办法是选中时避开段尾,或者划完之后把光标放到交界处再删一次格式。

第二,部分应用不支持跨段落应用删除线。你选了三大段,点删除线,只有第一段生效,后面两段纹丝不动。这种时候只能逐段处理。

第三,列表项和删除线打架。在待办清单里,勾选完成会自动带上删除线,你再手动加一次,某些应用会出现"双重划线"或者线条变粗错位。这种情况别手动加,交给清单的完成状态去处理。

第四,同步会吃掉格式。有的云笔记在本地划得好好的,同步到另一台设备就还原了,多半是两台设备的客户端版本不一致,旧版本不认识新版本写入的格式标记。更新客户端基本能解决。

3.2 桌面端快捷键:Word、Excel、网页

桌面端效率高得多,因为可以纯键盘操作。

文字处理软件里,选中文字后按 Ctrl+D 调出字体对话框,再按 Alt+K 勾选删除线,回车确认,这是最稳的一条路径,老版本新版本都通用。想更快的话,功能区的"开始"选项卡里字体组有现成的删除线按钮,点一下切换。有意思的是这个属性是"切换式"的,加过的再点一次就取消,不用去对话框里取消勾选。

电子表格的逻辑不太一样。单元格的删除线是按 Ctrl+5 切换,注意是主键盘区上方的数字 5,不是小键盘的。它作用于整个单元格,没法只划单元格里的某几个字——想实现"半个格子划线",只能把文字拆成两个格子,或者退回字符层用 U+0336。这一点经常有人踩,做价格对比表的时候想把原价划掉、现价保留,最省事的其实是拆成两列。

网页端最没辙。浏览器里 Ctrl+B 是加粗、Ctrl+I 是斜体、Ctrl+U 是下划线,删除线没有默认快捷键,而且绝大多数网页编辑器根本不提供这个按钮。你在网页表单里想划线,基本只能靠字符层。

注意:删除线在文档里是"装饰",不是"删除"。文字还在,复制、导出、检索都能拿到原文。所以千万不要用它来处理需要真正隐藏的内容,比如把作废的价格划掉就当它不存在了——它一直在那儿。

3.3 Markdown 的 ~~ 和 HTML 的 del/s 不是一回事

如果你在写 Markdown,删除线是两个波浪线包住文字:~~这段话划掉~~。渲染出来是带横线的效果。

但这里有个很多人不知道的细节:删除线不是 Markdown 标准语法。原始的 CommonMark 规范里没有它,它是 GFM(GitHub 风格 Markdown)以及很多衍生方言的扩展。这意味着你把同一个文件扔进不同的渲染器,结果可能完全不同——有的正常划线,有的原样显示两个波浪线。所以在跨平台使用之前,先确认目标渲染器认不认这个语法,别等发布出去才发现满屏波浪线。

如果你在写 HTML,选择就更多了,而且它们语义不同,别乱用:

  • <del>表示"这段内容已被删除",通常配合<ins>表示新增,用在修订记录里最合适。
  • <s>表示"这段内容不再准确或不再相关",但它并没有被删除,比如"原价 ~~199~~ 现价 99"。
  • text-decoration: line-through是纯样式,不携带任何语义,只负责画线。

搜索引擎和无障碍工具会读这些语义标签。用<del>标价格划线,语义上是错的,因为价格没被删除,只是失效了。这种细节平时没人管,但做内容站的时候会影响结构化数据的质量。

4. 字符路线:自己生成"划掉的字"

好,重头戏来了。当目标环境不支持任何格式,你又必须要那条横线,就只能走字符层。这一节从原理讲到代码,从生成讲到清洗,尽量让你看完就能自己攒一个小工具。

4.1 原理拆解:U+0336 到底是个什么东西

Unicode 里有一大类字符叫组合附加符号(Combining Marks),它们的共同特点是:不占独立字宽,渲染时会叠加到前一个基字符上。常见的例子是音标里的重音符、德语字母上的两点,都是这么来的。

删除线用的就是这一类里的几个成员:

码位名称效果适用
U+0336COMBINING LONG STROKE OVERLAY长横线最常用,覆盖整个字符宽度
U+0337COMBINING SHORT STROKE OVERLAY短横线窄字符,或想要更短的线
U+0338COMBINING LONG SOLIDUS OVERLAY长斜线做"划掉"的斜杠风格
U+20E5COMBINING REVERSE SOLIDUS OVERLAY反斜线斜线方向相反
U+0305COMBINING OVERLINE上划线想划在字上方而非中间

它的工作方式是"粘附":苹后面跟一个 U+0336,渲染引擎读完苹之后,发现后面跟了个组合符号,就把横线画在苹的中线上。如果你把 U+0336 放在字符串开头,前面没有基字符,它就无处附着,通常会渲染成一个独立的、位置奇怪的符号,或者干脆被丢掉。这就是为什么自己拼的时候,组合符必须跟在字符后面,不能单独出现在行首。

还有一个必须知道的点:它是零宽度,但不是零长度。渲染上不占位,但字符串长度里它算一个码位。十个汉字加十道横线,len()出来就是二十。所有跟长度相关的逻辑——输入框字数限制、数据库字段长度、短信分段计费——都会被这个翻倍影响。

4.2 手工生成:一个字符一个字符地贴

如果只是偶尔用一次,真没必要写代码。最土但最可靠的办法是:找一个已经带横线的字符,把那个横线单独复制出来,然后在你自己的文字后面一个个贴。

操作上可以这样:先把 U+0336 这个组合符单独放在一个地方(比如便签的第一行),选中它复制。然后输入你的文字,把光标放到第一个字后面,粘贴;移到第二个字后面,粘贴。听着很蠢,但划三五个字的时候,这比打开编辑器写脚本快得多。

更省事的办法是"借壳":随便找一个现成的带删除线文字样本,把里面的字母逐个替换成你要的。因为横线是跟着基字符走的,你替换基字符,横线位置自动跟着调整,不用重新对齐。

提示:手动贴的时候,务必确认你的编辑器没有开启"输入法自动替换"或者"智能标点"。某些输入法会把组合符号当成异常字符清掉,导致你贴了十次只成功三次,还找不到原因。

4.3 代码实现:Python、JavaScript、表格公式

要批量处理,就得靠代码。逻辑非常简单:遍历字符串,每个字符后面拼一个 U+0336。

Python 版本,注意处理换行符:

STROKE = "\u0336" def strike(text: str) -> str: out = [] for ch in text: if ch == "\n": out.append(ch) # 换行不加横线,否则横线会飘到下一行开头 else: out.append(ch + STROKE) return "".join(out) def unstrike(text: str) -> str: return text.replace(STROKE, "") if __name__ == "__main__": s = strike("这行字已经作废") print(s) print(len("这行字已经作废"), len(s)) # 7 和 14 print(unstrike(s))

JavaScript 版本,关键差别是要用Array.from而不是下标遍历,否则遇到 emoji 这类代理对字符会把一个字符拆成两半,横线就贴错位置了:

const STROKE = '\u0336'; function strike(text) { return Array.from(text) .map(ch => (ch === '\n' ? ch : ch + STROKE)) .join(''); } function unstrike(text) { return text.split(STROKE).join(''); } console.log(strike('临时方案已废弃')); console.log(strike('临时方案已废弃').length); // 12

顺手给一个网页版的实时转换,扔进浏览器就能用,适合做成自己常用的小工具页:

<textarea id="src" rows="4" cols="40" placeholder="在这里输入原文"></textarea> <textarea id="out" rows="4" cols="40" readonly></textarea> <script> const STROKE = '\u0336'; const src = document.getElementById('src'); const out = document.getElementById('out'); src.addEventListener('input', () => { out.value = Array.from(src.value) .map(c => (c === '\n' ? c : c + STROKE)) .join(''); }); </script>

电子表格里也能做,用的是UNICHAR(822),822 就是 U+0336 的十进制值。在支持动态数组的版本里,一行公式搞定:

=TEXTJOIN("",TRUE,MID(A1,SEQUENCE(LEN(A1)),1)&UNICHAR(822))

注意这个公式会返回一个由一到多个字符组成的"字串",视觉效果是划线,但LEN()算出来会是原长度的两倍。如果你后面还要对这个结果做匹配、去重、统计,记得先清洗。

4.4 视觉效果调优:中英文为什么不一样

代码跑通了不代表好看。字符层划线最大的槽点就是视觉不稳,原因在于横线的垂直位置是字体设计者定的,而不同字体对"中线"的理解完全不同。

西文字体里,这条横线通常画在 x-height 的一半左右,也就是小写字母的腰部。你划 "hello" 看起来正正好。但换成大写字母 "HELLO",因为字母更高,横线就偏低了,看起来像是划在字的胸口而不是中间。换成中文,方块字的高度又不一样,同一个横线有的字体画在正中,有的偏上,有的偏下。

实测下来有几条经验值得记:

  • 中英混排时不要指望对齐。一行里既有汉字又有英文单词,横线高度必然不齐,这是字体度量决定的,改不了。要么接受它,要么统一用中文或统一用英文。
  • 短横线(U+0337)在窄字符上更好看。像 "i"、"l" 这种窄字母,长横线会明显超出字符宽度,糊到旁边去。这时候换 U+0337 能收回来一点。
  • 斜线变体适合"批注感"。U+0338 是长斜线,画出来是斜着划过去的,视觉上更像潦草的手写批注,适合做那种"随手一划"的便签风格。但它比横线更容易错位。
  • 字号放大后错位会更明显。小字号下横线偏差一两个像素看不出来,字号一放大到标题级别,偏位就非常刺眼。所以字符层划线基本只适合正文和小标题,不适合做视觉主标题。
  • 行距会被撑开。部分渲染引擎为了容纳组合符号,会把行高略微撑大,导致同一段文字里,划线的行和没划线的行间距不一致。这个没法通过代码控制,只能调行高来抹平。

4.5 反向清洗:把横线摘下来

字符层是单向门,进去容易出来难,所以清洗函数必须提前准备好。

最简单的就是全局替换,把 U+0336 全部删掉,前面 Python 里的unstrike就是干这个的。但实际场景里往往更麻烦:用户可能从别的地方粘来一段已经带横线的文字,里面混着好几种组合符,甚至还有重复叠加的(两次划线,横线叠了两层,看起来更粗)。这时候要清得干净:

import unicodedata STROKES = {"\u0336", "\u0337", "\u0338", "\u20e5", "\u0305"} def clean(text: str) -> str: # 先按 NFD 拆开组合字符,再逐个过滤 normalized = unicodedata.normalize("NFD", text) kept = [c for c in normalized if c not in STROKES] return unicodedata.normalize("NFC", "".join(kept))

这里用 NFD 先拆解是必要的,因为有些字符是以"预组合"形式存在的,不拆开的话,逐个码位过滤会漏。拆完之后统一清,再合成回去,能覆盖绝大多数情况。

清洗还有一个用途是长度校验。用户在输入框里粘贴带横线的文字,你前端显示 10 个字,实际码位 20 个,提交到后端被字段长度限制截断,截断点很可能正好卡在基字符和组合符之间,留下一个孤零零的组合符——渲染的时候它会往前找基字符,把横线画到上一个字身上,视觉上就是"某个字莫名其妙多了一道线"。所以后端接收前一定要清洗一遍,或者至少校验清洗后的长度。

5. 三个场景的完整实操流程

原理和代码说完了,落到实际用起来,场景差异还是挺大的。挑三个我自己反复遇到的,把完整流程走一遍。

5.1 待办清单:保留"做过但不想删"的痕迹

最典型的场景:一天下来列了十几条待办,做完的不想删掉(因为要回顾今天干了什么),但又想一眼看出哪些没做。

正确做法是用清单自带的完成状态,勾选之后自动划线并置灰。这条路最稳,因为状态和文字是绑定的,同步、搜索、归档都不会出问题。手动去加删除线格式反而是错的——你会得到一个"看起来完成了但状态还是未完成"的条目,统计功能直接失效。

如果应用没有清单状态,只有普通文本,那就只能手动划。这时候我建议用富文本删除线而不是字符层,因为待办清单是要长期积累、经常搜索的。你想想,划了三十条,某天想搜"报销",结果因为字符层的关系搜不到,那这个清单就废了。

还有一种情况是"作废但保留原文",比如"周五交报表"这条因为计划变更作废了,但你不想删掉,想留个记录说明为什么变更。这种我会在划线后面补一句原因,格式是:~~周五交报表~~ → 改到下周一,原因是数据延迟。这样既保留了痕迹,又不会让后来的人(或者三个月后的自己)困惑。

5.2 跨平台文案:对方不支持格式怎么办

第二个场景是做运营或者发朋友圈、发评论区、发短信的时候,你希望某几个字带横线。这些地方一律不支持格式,只能上字符层。

流程是这样:先在本地用工具把文字转好,转之前想清楚三件事。

第一,确认目标平台不会被过滤。有些平台在提交时会做字符清洗,把组合附加符号当异常字符去掉,你发出去横线就没了。发之前先用同样的文字发一条测试,或者发给自己看,别直接发给客户。

第二,算好字数。字符层会让长度翻倍,如果平台限制 140 字,你实际只能写 70 个字。更坑的是有些平台按"显示宽度"算,有些按"码位"算,同一个字符串在两处显示的字数不一样。安全起见,按码位算,留够余量。

第三,别用在关键信息上。价格、日期、联系方式这类,划掉之后对方可能看不清原文,或者复制走之后变成一堆带横线的乱码,沟通成本反而更高。字符层划线适合做修饰,不适合承载信息。

5.3 截图风便签:让划线看起来像手写

第三个场景比较偏视觉:你想做一张看起来像手写便签的图,上面有几行被划掉的文字。

这种别用字符层。字符层的横线太规整了,永远水平、永远等宽、永远同一个粗细,一眼就是机器画的,没有手写味。

做法是在画图工具里单独画线:文字用正常字体排好,然后新建一个图层,用画笔工具手动画横线,画的时候刻意让线两端略微超出文字、粗细不均、略带倾斜。想要更真一点,可以把画笔的不透明度调到 85% 左右,让文字能隐隐透出来,模拟墨水覆盖的效果。线的颜色不要纯黑,用深灰或者带一点墨蓝,看起来更像笔迹。

如果要做成一套可复用的模板,就把"文字图层"和"划线图层"分开存,换文字的时候只动文字层,划线层根据新文字长度手动调整。这样比每次重画省事得多。

6. 常见问题与排查速查

字符层和格式层的坑我都踩过,这里集中列一下,遇到问题直接对照。

6.1 显示类问题:方框、错位、飘到下一行

显示成方框或者问号,说明当前字体没有 U+0336 这个字形。这在中文字体里不算罕见,尤其是那些精简过的手机系统字体。解决办法是换字体,或者换成系统默认字体。你没法用代码强制渲染,因为这是字体文件里有没有这个字形的问题。

横线位置偏上或偏下,是字体度量的问题,前面 4.4 说过。缓解办法是换用短横线 U+0337 试试,或者干脆换字体。指望通过代码调整位置是不现实的,组合符号的绘制完全交给字体和渲染引擎。

横线飘到下一行开头,几乎都是换行符后面多加了组合符导致的。检查你的生成函数,换行符必须跳过。这个 bug 特别隐蔽,因为只有文字刚好在行尾换行的时候才会暴露。

复制到某处变成一串带横线的乱码,通常是目标环境的字体回退机制在作怪——它认识基字符,但不认识组合符,于是把组合符单独渲染成一个可见的怪符号。这种没法从源头解决,只能换方案。

6.2 数据类问题:字数、截断、搜索、排序

字数翻倍被截断,前面反复提过。所有涉及长度的地方都要按"清洗后的长度"来校验,而不是原始码位长度。

截断产生孤儿组合符,是最恶心的一类 bug。字符串被硬切在基字符和组合符之间,剩下的那个组合符会往前找宿主,把横线画到别的字上。如果你的系统里有任何按字节或按码位截断的逻辑(比如列表页摘要截取前 50 字),一定要先清洗再截断。

搜不到。字符层的文字和原文码位不同,全文检索、站内搜索、数据库LIKE查询全都匹配不上。如果你的便签应用允许用户输入带横线的文字,搜索前应该做一次归一化:把组合符去掉再比对,同时保留原始的显示。这个在设计搜索索引的时候就要考虑进去。

排序和去重失效。同样的道理,苹̶果̶和苹果在字符串比较里是两个完全不同的值,去重、分组、排序全都会把它们当成不同的数据。做数据清洗的时候记得统一。

导出后格式丢失或错乱。导出成 PDF 的时候,如果目标字体不含组合符,渲染器会做字体替换,替换之后横线的位置就变了,可能出现横线压到上一行的情况。导出前先在目标环境里预览一遍。

6.3 排查速查表

现象最可能的原因处理方式
横线完全不显示目标环境不支持格式,或组合符被过滤改走字符层 / 换平台
显示成方框字体缺字形换系统默认字体
横线偏高偏低字体中线定义不同换字体,或换 U+0337
横线跑到上一行或下一行换行符后误加组合符生成函数跳过\n
字数超限被截断码位翻倍按清洗后长度校验
出现孤儿组合符截断点在基字符与组合符之间先清洗再截断
站内搜不到码位不同搜索前归一化
去重、排序异常字符串比较不等价清洗后比较
导出 PDF 后错位字体替换导出前在目标环境预览

7. 几条踩坑之后的经验

写了这么多方案,最后说几句掏心窝的话,都是从实际翻车里换来的。

能不用字符层就别用。字符层看着万能,其实是拿"文字的可搜索性、可计算性、可编辑性"去换"一定能显示出来"。除非目标环境真的不支持任何格式,否则老老实实用真删除线。我自己做内容的时候,凡是能富文本的地方一律用格式层,只有在发短信、填表单这种没法商量的地方才动用组合符,而且用完立刻在本地留一份干净的原文。

给字符层的文字留一份"干净副本"。我现在的习惯是,任何用组合符处理过的文案,都在同一个文档里附一行不带横线的原文。原因很简单:三个月后你想改其中一句话,对着一串带横线的字符,你连光标该放哪都找不准,改一个字的成本比重新打一遍还高。

长度校验一定要写两遍,前端一遍后端一遍。前端的长度校验是给用户看的,后端的长度校验是保命的。用户可能绕过前端直接调接口,也可能从别处粘贴一段带各种组合符的文本进来。后端拿到数据先做一次清洗,再按清洗后的长度判断,能挡掉一大批诡异的截断问题。

别在价格、条款、凭证这类文字上用字符层划线。划线在视觉上表示"作废",但它不是删除,原文完整地留在那里,随便复制一下就能拿到。更麻烦的是,对方可能压根看不清被划掉的内容是什么,反而造成误解。这类场景要么干脆删掉不显示,要么用明确的结构(比如单独一列"已停用")来表达。

我自己在实际操作中的体会是,删除线这个功能之所以这么多年一直被反复问,是因为它同时承载了两个需求:一是"标记状态"(完成了、作废了、失效了),二是"保留痕迹"(别真删,我还想看得见)。前者是功能,应该用结构化的状态来表达;后者是心理,用视觉装饰来满足。把这两个需求分开对待,很多选择就变得清楚了——需要状态就用清单、用标签、用独立字段;纯粹想要"划一道"的视觉感,才轮到删除线和组合字符出场。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询