首屏改成招聘方落地页:把简历和分身抬到折叠线以上
目标
站主的原话:
帮我把首页的 ai 分身聊天改的醒目一点,要不然就直接给个聊天框出来,然后给几个问的方式。然后简历下载也在这里做一个椭圆按钮一个简历预览按钮,可以大一点。主要是让 hr 进来就能看我简历,下载或者预览,然后也能简单询问我的 ai 分身。
以及一条独立要求:把聊天框里「我会保留少量访客记录(粗略城市 + 你的提问,会推到我手机),方便回访;隐私说明」两行删掉。
背景是站主在查 BOSS 直聘的收费机制时发现的一件事:招聘方每天的沟通/查看额度是花钱买的(免费账号每天只能发起 3 个新沟通、每个职位看 20 份简历),HR 点开一个候选人是有成本的。个人站的真正价值因此不是「帮 HR 省钱」,而是在他决定要不要花掉那一格额度之前,给他一个零成本看完你的入口。那这个入口就必须在折叠线以上。
先量,再改
改之前先在 375×812 实测各段高度,结果推翻了「内容太多」的直觉:
| 段落 | 高度 |
|---|---|
| nav | 49 |
| 招聘速览 | 168 |
| eyebrow | 45 |
| 名字 | 48 |
| claim | 55 |
| sub | 98 |
| AI 卡(含 chips) | 263 |
AI 卡底部落在 973px,视口只有 812——超出 161px。但真正的元凶是第三项之外的东西:hero 写的是 min-h-[100svh],而它上方还有 nav(49) + 招聘速览(168)。整个 hero 被推下去 160px,顶部空出一大块死白、底部同量溢出。改成 min-h-[calc(100svh-10rem)] 后,什么内容都没删就回收了 160px。
剩下的靠三刀:
- 窄屏隐藏 eyebrow——它写的「岗位 · 学历 · 届别」和上方常驻的招聘速览逐字重复,在窄屏纯属复读(-61px)。纯断点切换,HTML 里始终存在,爬虫与桌面不受影响。
- 招聘速览窄屏收紧字号/行距/内边距(168 → 111px)。
- chips 窄屏 13px → 12px——13px 时「你接受远程协作吗?」和「你最大的差异化优势是什么?」挤不进同一行,会折成三行多吃 41px;12px 正好两行两列。
最终 390×844 下:预览按钮、下载按钮、聊天输入行、4 个问题 chips、次要链接全部在折叠线以上,body.scrollWidth === 390。
首屏放真聊天框,但 bundle 零增长
「直接给个聊天框出来」有个陷阱:ChatPanel 依赖 ai-sdk,常驻首屏就把它拉进关键路径。
解法是让首屏那张卡是纯 RSC 静态壳——长得完全像聊天框(标题行 + 白色输入框 + 发送圆钮 + 问题 chips),但一行 ai-sdk 都不含。输入行和每个 chip 都挂 [data-chat-entry],复用日志 016 已有的 ChatExpander(白名单内的客户端组件,全局 capture 监听)在点击时才懒加载真面板。客户端 JS 白名单因此不需要新增成员。
两个入口走不同展开方式,这是刻意的:
- 输入行带
data-chat-inline→ 沿用「就地往下长出」,卡片自己长成聊天窗; - 问题 chip 不带 → 走定位下拉卡。因为 chips 在
flex-wrap容器里,520px 的面板插进去会把 chips 冲散。
chip 新增 data-chat-question 属性,ChatExpander 读到后透传给 ChatPanel 的 initialQuestion,面板挂载即自动发问——HR 点一下就能看到回答流出来,不用先打字。自动发送用 useRef 上锁而不是判断 messages.length:StrictMode 会双调用 effect,重渲染也会重跑。
无 JS 时每个入口都是 href="#twin",落到终章聊天岛的静态 FAQ 降级,链条完整。
简历预览:零新客户端 JS
/api/resume 原本强制 302 到静态 PDF、前端一律挂 download 属性 = 只能下载。预览只需要分岔一个查询参数:
- 预览
?view=1+target="_blank",不挂download→ PDF 无Content-Disposition,浏览器内置阅读器接手内联打开; - 下载 无参 +
download="黄一航-简历.pdf"→ 同域 download 属性触发存盘。
两条都是原生 <a>,无 JS 照样可点。计数上分开记(rv: / dl:):站主要区分「HR 只是瞄一眼」和「HR 存下来了」,后者才是真实意向信号。爬虫过滤沿用日志 028 后续那套 UA 正则。
踩坑
lg:py-12 比 sm:py-10 更大。 想给桌面更松的留白,写了 sm:py-8 lg:py-12,结果 1280×800 下卡片底部从 810 涨到 818——1280 宽同时命中 sm 和 lg,lg 赢。断点是「≥」不是「区间」,想收紧就别在更大的断点上加回去。删掉 lg:py-12 才降到 802。
英文站比中文站高 107px,差点漏掉。 中文改完全绿就想收工,顺手切 /en 才发现卡片底部 909、chips 第二行整排看不见。原因是英文 claim 在 42px 下折两行(105px vs 中文 50px)、sub 折五行(146px vs 72px)。压字号只救回 48px,最后是把英文 sub 文案本身收短到三行才解决——一屏 hero 里五行副文案本来就是设计问题,不分语言。 教训:双语站的版面验证必须两边都跑,中文的字符密度会掩盖英文的溢出。
删掉的文案要从数据源删干净。 按要求移除聊天框里的访客记录告知行后,构建出的 HTML 里仍能搜到那句话——它留在传给 ChatExpander 的序列化 props 里,虽然没有任何组件渲染它。既然彻底不用了就从 ui.ts 连类型带取值一起删,否则它会永远躺在每个页面的 RSC payload 里等着被 view-source 翻出来。
合规上的取舍(如实记)
访客记录告知行是日志 028 按 GDPR Art.13 / PIPL Art.17 特意加回输入框旁的。站主明确要求删除,本篇执行了。告知义务没有消失,只是换了承载位置:页脚常驻的「无广告追踪 · 不写访客 Cookie · 仅轻量自托管记录 → /privacy」全站每页可达,终章聊天岛的静态壳也仍写着「对话可能被记录用于改进」。采集行为本身、保留期、数据最小化设计一个字没改。这是「告知放在哪里」的取舍,不是「要不要告知」的取舍——如果日后要把告知拿回输入框旁,改 ChatPanel 底部那一个 <div> 即可。
同批文案改动
- 莫纳什 QS 37 → QS 31(中英共 10 处)
- Base「成都 · 接受远程」→ 「全国都可以接受」(站主选择不保留现居地)。
layout.tsx的 JSON-LD 同步去掉addressLocality、只留addressCountry: "CN"——钉死某个城市会让搜索侧按地域收窄匹配,与「全国都可以接受」自相矛盾。 - 到岗「最快 2026.08」→ 「最快 2026.09」(与新版简历「9 月可到岗」对齐;此前网站与简历口径打架)
- 简历 PDF 换成新版(新增手机号与个人网站行、求职意向改为「AI Agent 研发 / LLM 应用开发 / AI 应用工程师」)。手机号只留在 PDF 里,不上网站——公开域名上的手机号等于永久暴露给爬虫,骚扰不可逆。
验收
lint/typecheck/check:content/build全绿- 聊天四场景矩阵:① 无 env →
mode:demo, reason:not_configured② 指向 mock →mode:live③ 错误 key → 200 +reason:upstream_error(无 5xx)④ 连发 20 次 → 第 7 次起 429 + 友好文案 - 断点:390×844 / 1080×875 / 1280×800 三处首屏三件套均在折叠线以上,无横向滚动
- 交互:chip → 面板打开且自动发问、答案含新口径「2026.09 / 全国都可以接受」;Esc 关闭且滚动锁恢复;输入行 → 就地展开且不自动发问
- 预渲染 HTML 终检(中英各一遍):预览/下载按钮、聊天入口、4 个 chips 全在静态 HTML 里;无 QS 37、无「成都/Chengdu」、无访客记录告知残留
用时与备注
约 2.5 小时(含 BOSS 直聘收费机制调研与基线核对)。
开工前踩到一个更基础的坑:worktree 停在 claude/boss-zhipin-hr-reply-fees-c21db7 @ 2026-07-05,而线上跑的是 claude/resume-sync-on-live @ 2026-08-01,中间隔着日志 018-028 一整批。截图里的 QS 37、27 届、「复制候选人摘要」按钮在旧分支上压根不存在。先验基线 == 线上,再动手——否则做出来的东西回不去线上。切分支后逐字比对 hero.eyebrow 与线上截图确认一致才开始改。