使用方法
- 把页面
<title>粘进第一个框(上限 200 字符(示例已预填一段会被截断的标题)。 - 把元描述粘进第二个框(上限 500 字符)。
- 把网址粘进第三个框(上限 2048 字符)。只解析不访问——非
http/https开头的会直接拒绝。 - 三个框都是多行文本框,Enter 是换行,要生成预览请按 Ctrl+Enter(Mac 是 Cmd+Enter)。
- 预览区会显示还原后的搜索结果样子,每段后面挂一枚徽标:黄色「已截断」表示超过该段的像素上限,绿色「完整显示」表示没超。结果区下方的进度条按标题的占用比例填充。
这个搜索结果预览工具能解决什么问题
一是写完标题才发现被砍掉半截。中文站常见的说法是「标题 30 个字符以内」,但 SERP 是按像素宽度截断的:同样 30 个字符,纯汉字是 600px(刚好到边),而如果混了大量英文与数字,30 个字符可能只有 400px(还留了 200px 空白)。决定因素是汉字占比,不是字符数——这正是本页把宽度算出来而不是数字数出来的原因。
二是判断描述会不会只显示一行。描述的预算是两行 × 920px = 1840px。纯中文时每行 46 个汉字、两行 92 个;换成纯小写英文则是每行约 84 个字符、两行约 167 个。同一段文案,中文版和英文版的有效长度完全不同。
三是核对网址在结果里长什么样。Google 会去掉 https://、www. 和尾部 /,剩下部分按面包屑(用 › 分隔)显示在 480px 宽的斜体行里。路径层级太深时末级会被截掉,看起来像另一个页面。
四是发版前自查 snippet。同一份 HTML 模板在本地改完就能确认标题与描述的实际显示效果,不用等收录、不用反复提交。
本页不做这些事:不抓取真实 SERP(那需要发请求,也拿不到个性化结果)、不做 A/B 预测排名、不校验页面的实际 SEO 配置。要检查页面上真实的标签是否存在,请用Meta标签分析;要按关键词反推标题写法,请用SEO标题生成器;要直接比字符数,请用标题标签长度检测。
原理和变量
核心是一个自建的字符宽度表 + 像素预算判定,全部本地计算,可逐行复核:
宽度表按 font-size: 20px 建:汉字与全角 20px(即 1.0 em)、ASCII 大写与数字 13.3px、小写 11px、空格 5.6px、窄字符 . , : ; ' " ! | i l 6px。判定规则是:widthOf(seg) <= 预算 就完整显示,否则按字符回退到不超预算的最长前缀再加省略号。
三段预算是怎么来的?标题按 600px、描述按 920px 每行、2 行共 1840px、网址行按 480px。这三个数字是桌面 Google 排版的经验值,会随版本、字号、实验分组变动——所以本页把预算写出来给你看,而不是把它当成不可见的常量。你按自己站点实际 SERP 截图量出来的宽度,直接改这三个常量就能对齐。
为什么必须先 trim 再取 scheme?因为 " javascript:alert(1)" 前面有一个空格,天真的 startsWith('javascript:') 判断会被绕过。本页的做法是 trim() 之后用正则 /^([a-z][a-z0-9+.-]*):/i 取出协议名,再对照只含 http 与 https 的白名单。
这里有一个必须讲清的事实:new URL() 不是安全网关。实测 new URL('javascript:alert(1)') 不抛错,它照样解析成功,返回 protocol='javascript:'、hostname=''、pathname='alert(1)'。只有 new URL('not a url') 这种连协议名都没有的串才抛 TypeError: Invalid URL。所以白名单必须自己写死,不能指望 URL 构造器替我们拦。而且即使放行了 http 与 https,本页依然不发请求——只把 URL 拆成 host 与 path 做排版推算。
还有一个细节:new URL() 会把协议名与主机名自动小写,所以 HTTPS://X.COM/A 解析出的 protocol 是 https:、hostname 是 x.com。比对协议时用 protocol 字段而不是原始字符串。
完整示例
默认这组(数值仅作演示):
- 标题
露点计算器_气温与相对湿度换算露点温度含简化公式误差对照 - 柳泉工具,共 35 个字符,估算宽度 653.2px → 超 600px 上限 53.2px,按字回退到第 32 个字符处截断并补省略号。 - 描述共 94 个字符,估算宽度 1531.1px,未超 1840px 两行预算 → 两行内完整显示。
- 网址
https://www.liuquan.net/jisuanqi/ludiandianjisuanqi/→ 去掉https://、www.、尾部/后剩liuquan.net/jisuanqi/ludiandianjisuanqi,39 个字符、估宽 379px,未超 480px → 完整显示。
对照下面表格里第 6 行:同样是 43 个字符,那条标题因为汉字占比更高,估宽 780px,被截得更多。这张表就是「字符数不能代表显示长度」的证据。
输入范围与对照表
三段输入的上限:标题 200 字符(超过 600px 的部分必被截断,再长没有信息量)、描述 500 字符(两行 1840px 最多装 92 个汉字或 167 个小写字母)、网址 2048 字符。超限会明确告知并拒绝,不静默截断。
网址协议白名单实测(15 条,全部只解析不访问):
| 输入的网址 | 取到的协议 | 判定 | 原因 |
|---|---|---|---|
| https://x.com | https | 放行 | 正常 |
| http://x.com | http | 放行 | 正常 |
| javascript:alert(1) | javascript | 拒绝 | 可执行脚本协议 |
| JavaScript:alert(1) | javascript | 拒绝 | 大小写变形,被正则 i 标志捕获 |
| javascript:alert(1) | javascript | 拒绝 | 前导空白,trim 后命中 |
| data:text/html;base64,… | data | 拒绝 | 可执行 data 文档 |
| data:image/png;base64,iVBOR | data | 拒绝 | data 图片也不放行 |
| file:///C:/Windows/… | file | 拒绝 | 本地文件系统 |
| file://localhost/etc/passwd | file | 拒绝 | 本地文件 + 主机 |
| vbscript:msgbox | vbscript | 拒绝 | 老 IE 脚本协议 |
| blob:https://x.com/uuid | blob | 拒绝 | blob 本地对象 |
| about:blank | about | 拒绝 | about 协议 |
| ftp://x.com/a.txt | ftp | 拒绝 | ftp |
| chrome://settings | chrome | 拒绝 | 浏览器内部页 |
| view-source:https://x.com | view-source | 拒绝 | 源码视图 |
下表是 12 条不同长度与汉字占比的标题逐条量宽的结果,可直接看出字符数与像素宽不是一回事:
| # | 字符数 | 估宽 (px) | 是否截断 | 标题 |
|---|---|---|---|---|
| 1 | 24 | 433.2 | 否 | 露点计算器_露点温度与相对湿度换算 - 柳泉工具 |
| 2 | 29 | 481.7 | 否 | WebP转PNG转换器_本地解码与体积对照表 - 柳泉工具 |
| 3 | 24 | 433.2 | 否 | 日期转时间戳_时区与秒毫秒单位换算 - 柳泉工具 |
| 4 | 33 | 480.1 | 否 | CSS网格生成器_repeat与minmax参数输出 - 柳泉工具 |
| 5 | 19 | 371.0 | 否 | 搜索结果预览工具_标题描述截断宽度还原 |
| 6 | 43 | 779.7 | 是 | 露点计算器在线_气温湿度换算露点温度含简化公式误差对照与12行CSV导出 - 柳泉工具 |
| 7 | 1 | 13.3 | 否 | A |
| 8 | 31 | 487.5 | 否 | WebP 转 PNG 转换器 - 本地浏览器内完成,不上传文件 |
| 9 | 43 | 641.3 | 是 | 深度解析:Magnus 公式两个常数 17.625 与 243.12 的来历与误差实测 |
| 10 | 30 | 502.2 | 否 | 日期转时间戳:本地时区陷阱与 2038 年 32 位上限实测 |
| 11 | 36 | 469.3 | 否 | CSS 网格生成器:auto-fill 与 auto-fit 的实测差异 |
| 12 | 29 | 527.5 | 否 | 搜索结果预览工具:600px 标题宽度与两行描述的截断口径 |
| 13 | 25 | 500.0 | 否 | 露点计算器:气温、相对湿度到露点的换算与简化式误差 |
| 14 | 25 | 448.5 | 否 | WebP转PNG:本地解码、双层回退与体积放大倍数 |
| 15 | 30 | 482.3 | 否 | 日期转时间戳:Date.UTC 与本地时区构造的 8 小时差 |
| 16 | 28 | 419.7 | 否 | CSS网格生成器:minmax 与 fr 的分配算法实测 |
| 17 | 25 | 500.0 | 否 | 露点计算器在线使用:输入气温与湿度立即得到露点温度 |
| 18 | 34 | 499.3 | 否 | WebP转PNG转换器在线:体积、尺寸与 color type 对照 |
点「导出 CSV」拿走带 BOM 的表格。表格服务端直出,脚本不执行也能看到完整 12 行。
边界与精度
1. 像素模型是近似,不是渲染引擎。真实字距由浏览器的字体文件、字重与 hinting 决定,同一段文字在 Windows 的 Arial 与 macOS 的 Helvetica 上宽度能差几个百分点。本页的价值在于相对比较(哪条更可能被截、截多少),不是给出 Google 的精确裁切位置。所以表里一律保留 1 位小数,不假装精确到像素。
2. 字符数阈值与像素阈值是两套口径。业内常说「标题 50~60 字符」,那是像素预算的换算结果:600px ÷ 11px(小写字母宽)≈ 55 个小写字母;600px ÷ 20px(汉字宽)= 30 个汉字。所以「30 字符」和「580 像素」能同时存在,前者是汉字数、后者是像素宽。本页给的是后者。
3. 空串与纯空白分开处理。标题为空时预览区显示灰色占位「(标题为空)」而不是留白——因为真实 SERP 里没有 title 时 Google 会自己生成一个,那种情况应该去查页面而不是看预览。描述为空同理。网址为空则只显示前两段。
4. 网址的分隔符显示。Google 用 ›(U+203A)分隔层级,末级不重复显示在网址行。本页把 pathname 按 / 切开逐段用 › 连接;只有一段时只显示主机名。面包屑里的主机名会去掉 www.,与 Google 口径一致。
5. 描述按 2 行、1840px 判定。纯中文时 920 ÷ 20 = 46 个汉字每行、两行 92 个;纯小写英文时 920 ÷ 11 ≈ 84 个字符每行、两行约 167 个。这两个数字是「中文描述写多长才不浪费第二行」的依据。
6. 三个预算是经验值,会变。600px / 920px / 480px 会随 Google 的字号实验、桌面版布局调整而变。本页把它们做成页面内可见的常量并写进正文,你按自己站点的实际截图改这三个数即可对齐——这比相信一个藏在代码里的魔数要可靠。
7. 零请求是本页的可验证承诺。本页对用户填的网址只调用 new URL() 做字符串解析,不发任何网络请求。你可以在开发者工具的 Network 面板里自查:生成预览、载入示例、导出 CSV,全部操作之后面板应始终为空。如果某个版本出现了请求,那就是出了故障,请把请求 URL 反馈给我们。
常见问题
我填的网址会被你们访问吗?会不会泄露我的站点?
不会。本工具对网址只做字符串解析(new URL() 拆出协议、主机名、路径),不发任何网络请求,你可以在开发者工具的 Network 面板自查——打开页面、粘贴内容、生成预览、导出 CSV,做完之后面板应该始终是空的。这条承诺对 javascript:、data:、file: 这类协议尤其重要:它们被白名单直接拒绝,既不会被请求,也不会被塞进任何可执行上下文。
我的标题只有 28 个字符,为什么还是被截断了?
因为截断按像素不按字符。28 个字符如果全是汉字,宽度是 28 × 20 = 560px,没问题;但如果混进英文与数字,汉字占比一降,字符数不变而像素宽可能反而更小——反过来,汉字占比高时同样 28 个字符就更容易撞上 600px。你可以在预览区看那枚「已截断」徽标,以及统计条里「标题估宽 / 上限」的具体数值,把标题改短或减少汉字占比都能解决。
描述写满 500 字符是不是更好?
不是。描述的预算是两行 1840px:纯中文最多 92 个汉字、纯小写英文约 167 个字符。写到 500 字符时,超出部分永远不会被看到,纯粹是浪费字数。多数情况下 70~80 个中文字符(约 120~140 px × 2 行内)已经把两行用得比较充分。塞满反而有风险:如果前 40 个字没把核心信息说清,后面的内容在 SERP 里等于不存在。
为什么网址显示的是「liuquan.net › jisuanqi › ludiandianjisuanqi」而不是完整的 https 地址?
因为 Google 会去掉协议名、www. 前缀和尾部 /,剩下的路径层级用 ›(U+203A)分隔显示在 480px 宽的行里。本页照这个口径还原,末级不重复。所以预览里看到的面包屑本身就是 SERP 的实际形态——如果你想让末级更醒目,办法是缩短路径层级(少两层目录),而不是改 title。
宽度估算的 20px、13.3px、11px 这些数是怎么来的?
它们是按 font-size: 20px 建的近似字符宽度表:汉字是全角、宽等于 1.0 em 即 20px;大写字母与数字是 0.665 em ≈ 13.3px;小写字母 0.55 em = 11px;空格约 0.28 em 即 5.6px;窄字符(. , : ; ' " ! | i l)约 0.3 em 即 6px。这套表的价值是可解释、可自己改:你可以把 W 里的数字换成自己站点正文字体的实测宽度,预估就更准。本页也把这份表写在正文里,方便你核对。
我改成 javascript:alert(1) 会不会在页面上弹出来?
不会,而且这条输入会被明确拒绝。原因是三层防护:一,先 trim() 去掉前后空白,再用正则取协议名,所以 " javascript:..." 这种带前导空格的变形也会被抓住;二,协议名对照只含 http 与 https 的白名单,javascript、data、file、vbscript、blob、about、view-source 全部拒绝;三,被拒的字符串不会被写进 DOM,错误区用的是 textContent 而不是 innerHTML。
为什么 new URL() 拦不住 javascript:?
因为它本来就不是过滤器,只是解析器。实测 new URL('javascript:alert(1)') 不抛错,返回 protocol='javascript:'、hostname=''、pathname='alert(1)'——它认为这是一个合法的、非特殊的 URL。只有 new URL('not a url') 这种连协议名都没有的串才会抛 TypeError: Invalid URL。所以安全判断必须自己写白名单,这一条对任何「用户输入 URL」的场景都成立。
这个预览和真的 Google 结果会一模一样吗?
不会完全一样,差距在三处:一,Google 的 600px / 920px / 480px 预算会随版本与实验分组变动,本页用的是固定经验值;二,Google 会按查询词高亮命中词(<strong> 或颜色),本页不做高亮;三,移动端与桌面的预算不同(移动端约按视口宽的 88 % 折算,标题行更窄),本页只给桌面口径。要完全对齐只能对着自己站点的真实搜索截图逐段量。要检查页面上的真实标签而不只是猜显示效果,用SEO清单工具逐项过一遍。
相关工具
- 标题标签长度检测:按字符数查标题,本页按像素宽,两者互补。
- Meta标签描述长度检测:描述的字符数口径检查,配合本页的 46 汉字/行一起用。
- SEO标题生成器:标题写不出来时先按关键词生成,再拿本页验截断。
- Meta标签描述生成器:生成描述初稿,再用本页确认能否装进两行。
- Google摘要优化:从内容侧改善摘要质量,本页只管排版呈现。
- Canonical标签生成器:规范标签是收录侧的事,与本页的显示预览分开处理。
- SEO清单工具:上线前把 meta / 标题 / 描述逐项过一遍,本页是其中「显示效果」那一项的深挖。