1. 从一个小红点说起:CSS 伪元素到底能做什么
列表右上角那个未读小红点,几乎每个前端都写过。用 CSS 伪元素::before/::after实现小圆点,是成本最低、最不污染 DOM 的做法:不用额外塞一个<span>,不用改组件结构,样式层自己就能把点画出来。核心就三件事——content撑出伪元素、position: absolute定位、border-radius: 50%变圆。适合谁?适合正在写消息列表、Tab 角标、状态指示器,又不想动模板结构的前端同学。
但真实项目里,样式只是半条命。另一半是:你写完样式想验证,得调模型接口、跑本地请求、确认通道通不通。这时候如果每个项目都散落着不同的 Key、不同的 base_url,验证成本会高得离谱。所以这篇把两件事绑在一起讲:先用伪元素把小红点写利索,再用 TaoToken 的统一 Key/API 通道,把settings.json配置骨架和本地验证动作一次跑通。你照着做,样式和通道能同时落地。
我试过把这两步拆开做,结果样式调好了、接口却因为 Key 写错卡了半小时。合在一起写,反而顺手。
2. TaoToken 前置:统一 Key 与 API 通道是什么
TaoToken 做的事情很直白:把模型调用收敛到一个入口。你不用在settings.json、.env、各种 SDK 初始化里各写一份不同的地址和密钥,而是统一走一个 API 通道,Key 也统一管理。官网在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 入口是 https://taotoken.net/api 。
对前端同学来说,它的价值在于「配置骨架稳定」。你写settings.json时,只需要关心三样东西:base_url指向 API 入口、api_key用统一 Key、model填你要调的模型名。剩下的鉴权、路由、转发,通道自己处理。这样你在验证 CSS 小圆点之余,顺手就能发一个请求确认通道活着。
需要先拿到 Key 的话,去控制台创建:https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,然后在 API Keys 页面生成:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。Key 只显示一次,复制好再关页面。
注意:Key 属于敏感信息,别提交到 Git。本地用
settings.json时,建议配合.gitignore把配置文件排除,或者用环境变量注入。
3. 可复制配置:settings.json 骨架与伪元素样式
先给settings.json的骨架。这个文件在不同工具里字段名略有差异,但核心结构一致:一个base_url、一个api_key、一个默认model。下面这份可以直接抄,把sk-开头的占位换成你自己的 Key。
{ "base_url": "https://taotoken.net/api", "api_key": "sk-你的统一Key", "model": "claude-sonnet-4-20250514", "timeout": 30000, "max_tokens": 1024 }字段说明用表格对照更清楚:
| 字段 | 作用 | 建议值 |
|---|---|---|
| base_url | API 通道入口 | https://taotoken.net/api |
| api_key | 统一鉴权 Key | 控制台生成的 sk- 开头串 |
| model | 默认调用模型 | 按你订阅的模型填 |
| timeout | 请求超时毫秒 | 30000 |
| max_tokens | 单次最大输出 | 1024 起 |
再来看 CSS 伪元素写小圆点。原始写法用&.unread嵌套加:after,思路对,但有几个坑:content: ' '里是空格,某些压缩器会把它吃掉;right: -4px在父元素overflow: hidden时会被裁掉。下面给一份更稳的写法,用::after(双冒号规范)并显式声明display: block。
.icon-size-12 { cursor: pointer; width: 16px; height: 16px; margin: 22px 30px 0 0; background-position: center; background-repeat: no-repeat; float: right; position: relative; } .icon-size-12.unread::after { content: ""; display: block; position: absolute; right: -4px; top: -2px; width: 8px; height: 8px; background-color: #f5222d; border-radius: 50%; box-shadow: 0 0 0 2px #fff; }关键改动有三处。第一,content: ""用空字符串而不是空格,避免被优化掉。第二,border-radius: 50%比写死4px更通用,圆点尺寸改了也不用同步改圆角。第三,加了一圈box-shadow白色描边,红点压在深色图标上时边界更清晰,这是实际项目里很实用的一招。
如果你想要的是列表项前面的小圆点(不是角标),把定位改成左侧即可:
.list-item { position: relative; padding-left: 16px; } .list-item::before { content: ""; position: absolute; left: 0; top: 50%; width: 6px; height: 6px; margin-top: -3px; background-color: #1677ff; border-radius: 50%; }margin-top: -3px是垂直居中的经典补偿,等于高度的一半。用transform: translateY(-50%)也行,但老项目里margin兼容性更省心。
4. 验证请求:确认通道真的生效
配置写完不验证,等于没写。最直接的验证动作是发一个最小请求,看返回里有没有正常内容。用curl最快,不用装任何依赖。
curl -X POST https://taotoken.net/api/v1/messages \ -H "Content-Type: application/json" \ -H "x-api-key: sk-你的统一Key" \ -H "anthropic-version: 2023-06-01" \ -d '{ "model": "claude-sonnet-4-20250514", "max_tokens": 64, "messages": [ {"role": "user", "content": "只回复两个字:通了"} ] }'成功的话,返回体里会有content数组,里面是模型输出。如果返回401,说明 Key 不对或没带上;返回404,检查base_url后面有没有多写或少写/v1;返回超时,把timeout调大再试。
想更直观地看模型输出,可以直接用模型对话页面发一条:https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。在页面里选好模型、输入一句话,能收到回复就说明通道没问题。这一步和curl是互补的:curl验证的是你本地配置的 Key 和地址,对话页面验证的是账号本身可用。
如果你在写 Node 脚本,用fetch验证也一样:
const res = await fetch("https://taotoken.net/api/v1/messages", { method: "POST", headers: { "Content-Type": "application/json", "x-api-key": process.env.TAOTOKEN_KEY, "anthropic-version": "2023-06-01" }, body: JSON.stringify({ model: "claude-sonnet-4-20250514", max_tokens: 64, messages: [{ role: "user", content: "只回复两个字:通了" }] }) }); const data = await res.json(); console.log(data.content);把 Key 放环境变量TAOTOKEN_KEY,比硬编码在settings.json里更安全。本地跑之前先export TAOTOKEN_KEY=sk-你的Key。
5. 本篇常见错排查
小圆点不显示。九成是content没写或写成空。伪元素必须显式声明content,哪怕是空字符串。另一个原因是父元素没有position: relative,绝对定位的伪元素会跑到别的地方去。
圆点被裁掉。父级有overflow: hidden时,right: -4px这种负偏移会被裁。解决办法是把圆点往内收,或者给父级留出 padding 空间。
::after和:after混用。单冒号是 CSS2 写法,双冒号是 CSS3 规范。现代浏览器两者都认,但混着写容易在压缩工具里出问题,统一用双冒号。
请求返回 401。检查三处:Key 有没有复制完整、请求头字段名对不对(Anthropic 风格是x-api-key,OpenAI 风格是Authorization: Bearer)、Key 有没有过期。去 API Keys 页面重新生成一个最省事:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。
请求返回 404。多半是base_url拼错。正确入口是 https://taotoken.net/api ,注意不要在后面重复加/v1导致路径变成/api/v1/v1/messages。
settings.json改了不生效。有些工具会缓存配置,改完要重启进程。另外确认 JSON 语法合法,多一个逗号就会静默失败。
模型名写错。返回里会提示 model not found。去接入文档核对可用模型名:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。
6. 长期编码与 Agent 场景怎么接
如果你只是偶尔验证一下接口,上面这套settings.json加curl就够了。但如果你在长期写代码、跑 Agent 任务,每次手动配 Key、切模型会很烦。这种场景更适合用 Coding Plan,把通道和额度固定下来,配置一次长期复用:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。
如果你在用 Claude Code 这类命令行工具,接入方式在文档里有专门说明:https://taotoken.net/doc/claudecode-anthropic?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= 。核心还是那三样:base_url、api_key、model,和settings.json骨架一致。
回到 CSS 小圆点这件事。样式层的东西,写完就该忘掉它,让它安安静静工作。通道配置也一样,配好、验证通、不再折腾,才是好配置。把settings.json骨架存成模板,下次新项目直接复制,改个 Key 就能跑。这比每次重新查文档快得多。