这套主题现在跑到 1.34.0,你正在看的这个博客前台整站都是它。重写它的起因不是什么宏大目标,是我实在受不了旧主题那种「层次靠阴影堆」的做法:一张卡片要同时有实阴影、渐变底、圆角和一圈边框,看着像 2014 年的后台面板。所以我给自己定了一条规矩——一条 1px 的蓝灰线就够了。
层次只留三样东西
卡片不靠阴影靠留白:卡内 8px/12px 内缩、#e3e8f7 描边、12px 圆角,加一层几乎看不见的浅投影。整站颜色全在 :root 里,浅色 103 条令牌、深色 66 条,两边一一对齐。这里说的「对齐」是同一个语义名在两套里都存在,不会出现深色缺一根、只能就地硬写一个十六进制的情况。
深浅那两层也不是两套色板,是一个墨色加一组透明度派生出来的:文字、描边、底色、hover 全从同一个 RGB 三元组乘出来。好处是换墨色只改一行;代价是每加一根令牌都得先问一句「这个颜色能不能从墨色推出来」,推不出来就说明它是装饰,而装饰一律不加。
换肤只填一个色值
后台「强调色」填一个 #4482e5 这样的十六进制就够了:链接、按钮、hover、标签底色、代码块那三个红绿灯圆点的光环都从它派生,深色模式再按亮度自己算一个更亮的变体(PHP 里 noline_parse_hex / noline_luminance / noline_mix 三个函数,混色只往灰里混,不往别的色相跑)。
为什么不用 CSS 的 color-mix():一是老 Safari 的兼容坑,二是混色结果得可预期——我要的是「同一个颜色在深色下更亮一点」,不是「浏览器自由发挥」。
密度是旋钮,不是断点
全站字号 rem 化,根字号是可调的一个值。移动端不降字号,只收留白。这一条是我从别的主题身上抄过来又立刻删掉的东西:390px 宽就把 16px 正文缩成 13px,那不叫适配,那叫欺负拿手机看长文的人。桌面模式在窄屏只保留拖动和摇晃、卡片收小到 42vw,字号照旧。
首页
masthead 头图上面自动压一层渐变罩,保证站名和座右铭读得清;信息流封面卡带缩略图、阅读时长和最近评论预览;分类是吸顶药丸条,放不下的收进「更多」面板,面板支持方向键漫游;下一页在滚动接近底部时就预取,翻页不留白屏。
命中「动态分类」的文章渲染成微博式动态卡:不显示标题、正文原地铺开、超过 6 行折叠出一个「全文」。这个分类是配置项,我的「日记」走的就是这条。


右栏
双列 card-widget 骨架:月历、那年今日、分类、标签、目录、近期评论、站点信息。三处刻意的取舍:
- 分类卡默认关。分类已经在信息流顶上那条药丸条里出现过一次,右栏再来一份是重复。
- 近期评论不在单篇文章和各类独立页上出——正文下面就是这篇文章自己的评论区。而且连查询一起跳过,不给这些页面白跑一次
Widget_Comments_Recent。 - 只有尾部那几张 sticky 跟着滚。列表改成无限加载之后正文会一直往下长:整栏都固定住,前面四张滚走以后右栏就空了;整栏都不固定,滚过一屏之后右栏还是空的。所以固定的是尾巴,不是整栏。
重查询(分类统计、那年今日这些)按天缓存到 usr/uploads/noline_cache,发新文章会主动失效。
文章页
hero 头图 + 正文排版(二级标题下划线、引用块、表格、脚注、图片圆角、嵌套列表)、highlight.js 高亮、红绿灯圆点钉住横向滚动、复制按钮不随内容滚、图片灯箱、回到顶部、相关文章、文末版权卡。
有一个我自己很在意的细节:失效图不留浏览器那个碎图标。图挂了会换成主题自带的占位说明「图片资料已失效」,圆形头像换成中性剪影,顶栏 logo 换回首字母块;没被链接包住的失效图,点一下会拿原地址重试。博客是常年没人回去管的存档,图床搬家、对象存储换厂商都是必然事件,与其让碎图标一颗颗长出来,不如一开始就画好一张「这里曾经有图」。

性能上花的钱
- CSS 走压缩版,
design.css130 KB 压到 70 KB,带?v=版本号做缓存指纹。 -
design.css和顶栏头像在<head>顶部就 preload。头像那个<img>排在几百行 HTML 之后,不提前起请求就会在换页那一瞬闪出一块空位。 - 站点头像转存成站内文件(
usr/uploads/noline_avatar/,文件名带原地址哈希)。Gravatar 镜像发的是cache-control: max-age=300, no-cache,每开一张新页都要先 304 问一次才敢画;转存之后它就是站内一张静态图,浏览器直接命中缓存。目录不可写、抓取失败或者超过 512 KB,都原样退回外部地址,失败只记一笔、六小时内不再重试。评论头像不转存——那是别人的一张张图,数量和时效都不该由主题背。 - 浏览量去重 + 爬虫 UA 过滤,计数落在
usr/uploads/noline_views/<cid>.txt。 -
canonical+ Open Graph + Twitter card + JSON-LD 一次配齐。
明确不做的事
- 不做「首屏关键 CSS 内联 + 其余异步」。异步补 CSS 会重新引入首屏白闪,这一版宁可留全量阻塞 CSS。
-
第三方文件不收进
vendor/。highlight.min.js、matter.min.js、atom-one-dark.min.css平铺在js/和css/下面。不少面板和 nginx 配置会给任何带/vendor/的请求直接回 404(防 Composer 目录外泄那一条),线上表现就是桌面模式「加载失败」、文章页代码没高亮,而本地怎么测都是好的。这个坑我踩过,别帮我「整理」回去。 - 不上 PJAX。跳转要软,但软跳转不等于假 SPA,那部分单独写一篇。
- 归档页一次列全部文章,查询数是 O(文章数),文章上千会慢。这是偷懒的代价,我认。
- 首页公告和底部版权原样存 HTML,不做标签清洗。这是有意的:公告里要能放链接和样式。代价是拿到接口密钥的人能往前台注入脚本,所以写接口有独立开关。
桌面模式
首页底栏那颗「桌面」按下去,信息流里的卡片就变成有碰撞体积的方块:能拖着走、会互相压、落到底板上会歪着倒。「摇晃」同时是一次换一批——先去别的分页随机抓一批文章换上桌,再把这一批整摞掀起来,松手它们自己重新堆好;收回桌面时抓来的那批下桌、首页那批原卡原样回到信息流里。
抓的地址只从核心渲染的页码条里读,不自己拼 URL,所以开不开伪静态都成立。物理用 vendored 的 matter-js,只在按下开关那一刻才懒加载那一份脚本;位置按文章 cid 存进 localStorage,关掉再开还是那一堆。文章不足 4 篇时整块入口不渲染,默认关。

装它之前要知道的两件事
- 发布包是 Release 附件
noline.zip,包里有两个根:noline/落到usr/themes/noline,plugins/NolineApi/落到usr/plugins/NolineApi。插件是可选的,不装就没有健康页和记账页的数据、没有接口、没有后台那个「主题管理」页,主题其余部分照常工作。要求 Typecho 1.2.x 以上、PHP 7.4+。 -
views/目录别删。里面是历史浏览量的兜底文件:新计数写在usr/uploads/noline_views/,找不到就读views/。删了全站计数从 0 重来——我那 192 个文件是从上一套主题一次性迁过来的,一个都没丢。
后台一共 15 个设置项,加上插件那一大堆(自动更新、图床、后台皮肤、接口),也单独写一篇。
评论 0
还没有评论,来抢沙发