博客样式设计
之前参加了 CSS Naked Day 2026,发现博客不需要什么样式其实也能看,少去了一些字体和 JS,加载还更快一些。想着或许可以趁着每年 CSS Naked Day 期间将博客样式重写一次,减少一些不必要的样式,让博客更轻量一些。有个说法是,日本的伊势神宫会每隔 20 年重建一次,目的是为了让每一代的工匠都有修建的经验,不至于丢失修建的能力。每年翻修一下博客样式,也能让自己更清楚需要什么。
大体的设计还是基于 我的博客设计,相比上个版本而言,移除了字体,暂时只用系统自带的字体,这样博客可以少加载些资源。另外移除了 pagefind 提供的搜索功能以及 littlefoot 的脚注增强功能,一个考虑是最近的供应链攻击比较多,这两个都是外部的 JS,不受我控制(虽然我可以下载下来,避免它们更新),而且也不是必不可少的功能,还是少加载一些 JS 吧。不过由于 Webmention 需要渲染 HTML 内容,还是保留了一个 purify.min.js 的外部 JS 依赖。剩下的一些 JS 都是我自己编写的,都比较简短,也在我的控制下。
这次重写,使用了 @layer 去分类样式,也尝试用 文学编程 的形式去描述设计,尝试尝试新东西。这个文档应该会持续迭代,样式会基于这份文档生成。
main.css
@layer base
layer start
@layer base {
变量
首先定义一些 CSS 变量,主要是颜色相关的。
:root { --color-taxodium-purple: #7c7cd1; --color-taxodium-yellow: #bd8c42; --color-bg: #eee; --color-bg-secondary: #ffffffe6; --color-bg-src-block: oklch(from var(--color-bg) l c h / 0.5); --color-text: #2e2e2e; --color-text-secondary: #787878; --color-border: #ddd; --color-link: var(--color-taxodium-purple); --color-link-visited: var(--color-taxodium-yellow); --color-border-table: #777; --color-bg-table: #ddd; --color-box-shadow: rgba(0, 0, 0, 0.3); --color-todo: #ff5f59; --color-lyrics: #7c0100; --color-code: #8f0075; --color-bg-code: #ddd; --color-bg-code-highlighted: oklch(0 0 0 / 0.1); --color-fucus-visible-outline: oklch(from var(--color-link) l c h / 0.8); --dark-color-bg: #232323; --dark-color-bg-secondary: #1e1e1e; --dark-color-bg-src-block: oklch(from var(--dark-color-bg) l c h / 0.7); --dark-color-text: aliceblue; --dark-color-text-secondary: #b8b8b8; --dark-color-border: #595959; --dark-color-link: oklch(from var(--color-link) .75 c h); --dark-color-link-visited: var(--color-link-visited); --dark-color-border-table: #7d7d7d; --dark-color-bg-table: #1e1e1e; --dark-color-box-shadow: rgba(255, 255, 255, 0.3); --dark-color-todo: #ff5f5f; --dark-color-lyrics: #e95632; --dark-color-code: #f78fe7; --dark-color-bg-code: #474747; --dark-color-bg-code-highlighted: oklch(1 0 0 / 0.3); --dark-color-fucus-visible-outline: oklch(from var(--dark-color-link) l c h / 0.8); --table-border: 2px solid var(--color-text); --table-cell-border: 1px solid var(--color-border); --content-width: 90vw; --half-content-margin: calc((100vw - var(--content-width)) / 2); /* footnote 数字的点击范围 */ --extra-active-area-size: -0.8em; }
html / body
定义 <html> 的样式,指定字体、字号,后面基于 <html> 字体大小,使用 rem 作为长度单位。
html { font-family: system-ui; font-size: 20px; -webkit-text-size-adjust: 100%; } @media screen and (width >= 70em) { html { font-size: 22px; } }
在手机上, <body> 占据整个屏幕 (100vw),只留些许的 padding 和屏幕边缘保留一些距离,因为手机屏幕本来就小,还要留一些边距 (margin) 的话,留给内容的空间就更少了。
在大屏上 (width >= 55rem),限制最大宽度,避免一行内容太长,需要频繁左右来回看。设置左右边距 (margin-inline) 为 auto,使得 <body> 居中,而不是靠左,这样就不用侧着头看;居中也不会让一侧留白太多。
除此之外,设置页面整体的字体颜色;1.5 的行高,避免行之间过于拥挤;设置 word-wrap 使得较长的连续文字能够换行,不至于产生横向滚动条。
另外在还设置了一个背景图片,使得背景不那么单调乏味。背景图会自动基于明暗模式适配。
body { max-width: var(--content-width); margin: .5rem auto; line-height: 1.5; word-wrap: break-word; color: var(--color-text); color: light-dark(var(--color-text), var(--dark-color-text)); background-image: url("/images/background/xv.png"); background-attachment: fixed; @media screen and (width <= 400px) { margin-inline: 0; padding-inline: .5rem; max-width: 100vw; } } @media screen and (width >= 55rem) { :root { --content-width: 45rem; } }
在页面之间切换时,添加 view-transition 的效果,我希望切换看起来平缓一些,所以设置了较长的动画时间。
@view-transition { navigation: auto; } ::view-transition-group(root) { animation-duration: 0.6s; } /** * @see: https://www.a11yproject.com/posts/understanding-vestibular-disorders/ */ @media (prefers-reduced-motion: reduce) { @view-transition { navigation: none; } }
导航栏
导航栏内容不多,简单布局能够放下就行。需要处理一下手机屏幕下空间不足的问题,主题切换下拉框会移动到导航栏下方。
导航的链接不需要 :visited 颜色标记,固定成链接本身的颜色。
#preamble nav { display: grid; grid-template-columns: auto max-content; gap: 2px; @media screen and (width <= 350px) { grid-template-columns: 1fr; justify-items: start; } & ul { display: grid; gap: 8px; grid-template-columns: repeat(3, max-content); list-style: none; padding: 0; margin: 0; align-items: center; } a:visited { color: var(--color-link); color: light-dark(var(--color-link), var(--dark-color-link)); &:hover { color: #fff; background: var(--color-link); background: light-dark(var(--color-link), var(--dark-color-link)); } } }
主题下拉框样式,field-sizing 可以让下拉框基于内容长度自适应宽度。
#lightdark { text-align: center; field-sizing: content; max-width: 100%; }
skip nav
处理 Skip navigation 的样式,默认是隐藏的,只要在 focus 时才显示。样式实现参考了 Stefan Judis 的博客。
其中 @starting-style 用于设置元素加载前的样式初始值,这里设置的目的是在页面切换,发生 view transition 的时候,先隐藏 .a11y-nav 元素,避免出现一个收起的动画。
.a11y-nav { width: max-content; position: fixed; left: 0; right: 0; top: 0; margin: 0 auto; padding: 0.5rem; z-index: 5; background-color: var(--color-bg-secondary); background-color: light-dark(var(--color-bg-secondary), var(--dark-color-bg-secondary)); font-weight: 600; /* hide the link */ transform: translateY(-60px); @starting-style { transform: translateY(-60px); opacity: 0; } &:focus { transition: transform 0.375s ease-in-out; transform: translateY(0); } }
title & subtitle
标题居中,子标题字体降低一些,颜色变淡一些,从而和主标题区分。
.title { max-width: fit-content; margin-inline: auto; } .subtitle { color: var(--color-text-secondary); color: light-dark(var(--color-text-secondary), var(--dark-color-text-secondary)); font-size: 1.2rem; margin-block-start: 0; margin-block-end: 1.5rem; text-align: center; }
heading
设置标题的字号,默认都加粗。因为标题本身字体就很大,行高太大,就会有很多多余的空白,所以将行高降低为 1.2。
h1, h2, h3, h4, h5, h6 { line-height: 1.2; font-weight: 700; padding: 0; margin-block-end: 0.5rem; } h1 { font-size: 2.25rem; } h2 { font-size: 1.85rem; } h3 { font-size: 1.65rem; } h4, h5 { font-size: 1.45rem; } h6 { font-size: 1rem; }
图片/视频
限制图片宽度,避免溢出,让图片在限定宽度內显示全。对于暗色主题下,降低图片的亮度,避免刺眼,尤其是有大片白色的图片。
img, video { max-width: 100%; object-fit: contain; } img { @media (prefers-color-scheme: dark) { filter: brightness(0.85) contrast(1.05); } } .dark img { filter: brightness(0.85) contrast(1.05); }
链接
设置链接的颜色、hover、visited 时的颜色。
hover 样式只在电脑屏幕上启用,因为手机本身不支持 hover,如果开启了 hover 样式,会在页面滚动时不小心触发 hover 样式,显得有些凌乱。
a { color: var(--color-link); color: light-dark(var(--color-link), var(--dark-color-link)); text-underline-offset: 5px; text-decoration-style: solid; text-decoration-thickness: 2px; &:has(> img) { &:hover { background: none; } } @media (pointer: fine) and (hover: hover) { &:hover { text-decoration: none; background: var(--color-link); background: light-dark(var(--color-link), var(--dark-color-link)); color: #fff; & code { color: #fff; } } } &:visited { color: var(--color-link-visited); color: light-dark( var(--color-link-visited), var(--dark-color-link-visited) ); @media (pointer: fine) and (hover: hover) { &:hover { background: var(--color-link-visited); background: light-dark( var(--color-link-visited), var(--dark-color-link-visited) ); text-decoration: none; color: #fff; } } } /* make safari :visited hover works */ @media (pointer: fine) and (hover: hover) { &:visited:hover, &:visited:hover { background: var(--color-link-visited); background: light-dark( var(--color-link-visited), var(--dark-color-link-visited) ); text-decoration: none; color: #fff; } } }
段落
设置一个较大的,明显大于行高的间距,使得段落之间区分明显。
p { margin: 1.25rem 0; }
markup
一些常用标记的样式。
code { font-size: 0.85rem; color: var(--color-code); color: light-dark(var(--color-code), var(--dark-color-code)); } em { text-emphasis: "\23f6"; text-emphasis-position: under; font-style: unset; } b { font-weight: 700; } .underline { text-decoration-color: var(--color-border); text-decoration-color: light-dark(var(--color-border), var(--dark-color-border)); text-decoration-line: underline; text-decoration-style: wavy; text-underline-offset: 4px; text-decoration-thickness: 2px; } del { color: var(--color-text-secondary); color: light-dark(var(--color-text-secondary), var(--dark-color-text-secondary)); opacity: 0.65; } dt { font-weight: 700; } dd + dt { margin-top: 1rem; } dd { margin-inline-start: 1.5rem; }
hr
分割线样式,将分割线设置为 * * * 而不是一根直线,主要是因为页面上有不少的线条,例如 blockquote、代码块、note,太多线条会让内容看起来比较乱。
hr { display: block; border: 0; margin: 2.5rem 0; padding: 0; border-color: var(--color-border); border-color: light-dark(var(--color-border), var(--dark-color-border)); text-align: center; &::before { content: "* * *"; text-align: center; } }
kbd
kbd { background-color: var(--color-bg); background-color: light-dark(var(--color-bg), var(--dark-color-bg)); color: var(--color-text); color: light-dark(var(--color-text), var(--dark-color-text)); border: 1px solid; border-color: var(--color-border); border-color: light-dark(var(--color-border), var(--dark-color-border)); border-radius: 0.25rem; box-shadow: 1px 2px 2px var(--color-box-shadow); box-shadow: 1px 2px 2px light-dark(var(--color-box-shadow), var(--dark-color-box-shadow)); display: inline-block; font-weight: bold; padding: 0.2rem 0.25rem 0.1rem; line-height: 1; white-space: nowrap; font-size: 0.85rem; }
ruby
适当放大 <rt> 的字号,增加间距。
rt { font-size: 0.65rem; margin-block-end: 0.1rem; }
代码块
参考了 Protesilaos Stavrou 的样式 。
pre { background: var(--color-bg-src-block); background: light-dark(var(--color-bg-src-block), var(--dark-color-bg-src-block)); font-size: 0.75rem; margin: 1em 0; padding: 1rem; white-space: pre-wrap; overflow-x: auto; word-break: normal; word-wrap: inherit; border-block: 5px solid; border-color: var(--color-border); border-color: light-dark(var(--color-border), var(--dark-color-border)); }
引用 blockquote、verse
blockquote 和 verse 样式都是一样的,左侧有边框,颜色比正文淡一些,正文区分开。
.verse, blockquote { margin: 1rem 0; padding: 0 0.5rem; color: var(--color-text-secondary); color: light-dark(var(--color-text-secondary), var(--dark-color-text-secondary)); border-inline-start: 4px solid var(--color-border); border-inline-start: 4px solid light-dark(var(--color-border), var(--dark-color-border)); } .verse + .verse, blockquote + blockquote { margin-block-start: 2em; }
figure
移除 figure 的左右边距,使得 figure 能够占满 body 的宽度,让图片显示得更大一些。
figcaption 字号减小,颜色变淡,和正文区分。
figure { margin-inline: 0; } figcaption { font-size: 0.85em; color: var(--color-text-secondary); color: light-dark(var(--color-text-secondary), var(--dark-color-text-secondary)); }
details
details 添加 border,便于在内容很多的时候,能够知道哪些内容是属于 details 的。
summary 的 marker 换成一只指向的手,比黑漆漆的三角形好看点。感兴趣可以看看 Zine#32::The Secret History of the Manicule, the Little Hand that’s Everywhere。
details { padding: 0.5rem 1rem; border-radius: 1rem; border: 2px solid var(--color-border); border-color: light-dark(var(--color-border), var(--dark-color-border)); margin-block: 1rem; summary { cursor: pointer; &::marker, :is(::-webkit-details-marker) { content: "☞ "; } } &[open] summary::marker, &[open] summary::-webkit-details-marker { content: "☟ "; } }
iframe
iframe 一般我会用来展示一些 HTML 示例,添加边框使其和内容区分开。
iframe { width: 100%; min-height: 350px; border: 2px dotted var(--color-border); border: 2px dotted light-dark(var(--color-border), var(--dark-color-border)); }
select
博客下拉框很少,主要就是导航栏的主题下拉框。
select { font-size: 1rem; padding: 4px; border-radius: 0.25rem; color: var(--color-text); color: light-dark(var(--color-text), var(--dark-color-text)); }
button
给按钮的点击添加一个效果,使得点击这个动作更明显。
button { border-radius: 0.25rem; padding: 0.25rem; cursor: pointer; &:active { transform: scale(0.97); } } input.button:active { transform: scale(0.97); }
table
参考了 Styling Tables the Modern CSS Way。
table { border-block-start: var(--table-border); border-block-end: var(--table-border); border-collapse: collapse; border-color: var(--color-border-table); border-color: light-dark(var(--color-border-table), var(--dark-color-border-table)); text-align: start; caption-side: bottom; word-break: normal; } .table-wrapper { overflow: auto; margin-block: 1rem; } /* override org publish default style */ table th.org-left { text-align: start; } thead { border-block-end: var(--table-border); border-color: var(--color-border-table); border-color: light-dark(var(--color-border-table), var(--dark-color-border-table)); white-space: nowrap; } thead, tfoot { background: var(--color-bg-table); background: light-dark(var(--color-bg-table), var(--dark-color-bg-table)); } tbody tr:nth-child(even) { background: var(--color-bg-table); background: light-dark(var(--color-bg-table), var(--dark-color-bg-table)); background: light-dark(color-mix(in srgb, var(--color-bg-table), transparent 60%), color-mix(in srgb, var(--dark-color-bg-table), transparent 60%)); } table tr { border-block-start: var(--table-cell-border); border-color: var(--color-border); border-color: light-dark(var(--color-border), var(--dark-color-border)); } thead th { vertical-align: bottom; } td, th { padding: 0.3rem 1rem; vertical-align: baseline; @media screen and (width <= 400px) { padding: 0.3rem 0.6rem; } }
list
给 <li> 增加一些边距,避免过分拥挤。
:where(ol,ul) li { margin-block: .2rem; }
org-publish 渲染的 HTML,在嵌套 list 的时候,有的内容会用 <p> 包裹,导致某个 <li> 的边距过大。针对这个情况,重置 <p> 的边距。
:where(ol,ul) li > p:first-child { margin-block: 0; }
在手机屏幕下,减少列表和列表內元素的边距,使得在手机屏幕上可以呈现更多内容。
@media screen and (width <= 400px) { :where(ol,ul) { padding-inline-start: 1rem; & li > details, & li > :is(pre.example, .org-src-container) { margin-block: 1rem; margin-inline-start: -1rem; } } .dl dd { margin-inline-start: 1rem; } }
footnote
覆盖 org-publish 默认的样式,让 footnote 的序号和内容在同一行。
#text-footnotes { margin-block-start: 1.25rem; } .footdef { display: grid; grid-template-columns: max-content auto; gap: 0.5em; font-size: 0.9em; } [role="doc-footnote"] *:nth-child(1) { margin-block-start: 0; }
postamble
底部内容样式,设置了一个分割线,内容可以自定义,偶尔换换。
页脚的内容因为比较次要,减少字号,淡化一些,重置 <p> 的间距。
#postamble { margin-block-start: 1em; &::before { /* content: 'EASY COME, EASY GO ...'; */ content: "つづく To Be Continued"; color: var(--color-border); color: light-dark(var(--color-border), var(--dark-color-border)); display: block; text-align: end; } footer { font-size: 0.85rem; color: var(--color-text-secondary); color: light-dark(var(--color-text-secondary), var(--dark-color-text-secondary)); & p { margin-block: 0.25rem; } } }
layer end
}
@layer print
打印时,将字号适当缩小,让内容占满窗口,使得一页纸可以放下更多内容;将链接显示出来;隐藏对打印无用的内容。
更多可以参考 关于页面打印。
@layer print { @media print { html { font-size: 16px; } body { background-image: none; margin: 0; max-width: 100vw; } #preamble, #postamble, #back-to-top, .code-copy-btn { display: none; } a::after { word-break: break-all; content: " (" attr(href) ")"; } /* 部分链接意义不大,不需要展示出来 */ a:where(.footref, .footnum)::after, #table-of-contents a::after { content: ""; } } }
@layer function
layer start
@layer function {
back-to-top
Back to top 按钮样式。
#back-to-top { position: fixed; bottom: 1rem; right: 1rem; width: 2rem; height: 2rem; z-index: 1; cursor: pointer; padding: 0.5rem; border: 2px; border-style: solid; border-color: var(--color-border); border-color: light-dark(var(--color-border), var(--dark-color-border)); background-color: var(--color-bg); background-color: light-dark(var(--color-bg), var(--dark-color-bg)); color: var(--color-text); color: light-dark(var(--color-text), var(--dark-color-text)); border-radius: 0.25rem; opacity: 0; visibility: hidden; transition: opacity 0.25s ease-in-out, visibility 0.5s; } @media screen and (width >= 1200px) { #back-to-top { right: calc(var(--half-content-margin) - 4rem); } } #back-to-top svg { display: block; width: 100%; height: 100%; fill: currentColor; } #back-to-top.show { opacity: 0.4; visibility: visible; } #back-to-top.show:hover { opacity: 1; }
代码高亮
参考了 Styling Tables the Modern CSS Way,仅高亮几种关键字的颜色。
.org-comment { color: #7f0000; color: light-dark(#7f0000, #c0a38a); font-style: italic; } .org-comment-delimiter { color: #7f0000; color: light-dark(#7f0000, #c0a38a); font-style: italic; } .org-diff-added { color: #005000; color: light-dark(#005000, #a0e0a0); background-color: #c3ebc1; background-color: light-dark(#c3ebc1, #00371f); } .org-diff-indicator-added { color: #006700; color: light-dark(#006700, #279c40); background-color: #c3ebc1; background-color: light-dark(#c3ebc1, #00371f); } .org-diff-indicator-removed { color: #aa2222; color: light-dark(#aa2222, #f36649); background-color: #f4d0cf; background-color: light-dark(#f4d0cf, #450f1f); } .org-diff-removed { color: #8f1313; color: light-dark(#8f1313, #ffbfbf); background-color: #f4d0cf; background-color: light-dark(#f4d0cf, #450f1f); } .org-doc { color: #304463; color: light-dark(#304463, #8aa0df); font-style: italic; } .org-function-name { color: #602938; color: light-dark(#602938, #35afbf); } .org-number { color: #000000; color: light-dark(#000000, #b8c6d5); } .org-string { color: #00598b; color: light-dark(#00598b, #df9080); } .org-variable-name { color: #00603f; color: light-dark(#00603f, #6a9fff); }
代码复制按钮
code-enhanced.js 会在代码块附近添加一个复制按钮,用于复制代码块的内容。按钮放置在右上角,始终展示。
.org-src-container { display: grid; grid-template-columns: auto; grid-template-areas: "copy-btn" "code"; &:has(.code-copy-btn) { pre { margin-block-start: 0.25rem; } } } .code-copy-btn { grid-area: copy-btn; cursor: pointer; max-width: fit-content; border-color: var(--color-border); border-color: light-dark(var(--color-border), var(--dark-color-border)); border-radius: 0.5rem; font-size: 1rem; justify-self: end; &:hover { background: var(--color-link); background: light-dark(var(--color-link), var(--dark-color-link)); color: #fff; } }
代码悬浮高亮
org-publish 支持标记代码行,并能够通过链接指向代码行,使其高亮。
高亮逻辑由 code-highlighted.js 实现,会添加 .code-highlighted 类。
交互见: 在 Emacs 中用 Elfeed 阅读订阅流。
.code-highlighted { transition: background-color 0.1s ease-in-out; background-color: var(--color-bg-code-highlighted); background-color: light-dark(var(--color-bg-code-highlighted), var(--dark-color-bg-code-highlighted)); } a.coderef { font-size: 0.85rem; background: var(--color-bg-code); background: light-dark(var(--color-bg-code), var(--dark-color-bg-code)); border-radius: 6px; padding: 0.05rem 0.2rem; color: var(--color-text); color: light-dark(var(--color-text), var(--dark-color-text)); text-decoration: none; &:visited { color: var(--color-text); color: light-dark(var(--color-text), var(--dark-color-text)); } &:hover { color: #fff; background: var(--color-link); background: light-dark(var(--color-link), var(--dark-color-link)); & code { color: #fff; } } }
Webmentions
webmention 相关样式。
.webmention { font-size: 0.9rem; & form { display: grid; grid-template-columns: max-content auto max-content; gap: 0.5em; align-items: center; @media screen and (width <= 680px) { grid-template-columns: 1fr; } & input { border: 1px; border-style: solid; border-color: var(--color-border); border-color: light-dark(var(--color-border), var(--dark-color-border)); border-radius: 0.2rem; padding: 0.3rem; font-size: 1em; &::placeholder { padding-inline-start: 0.5rem; } &.button { cursor: pointer; padding: 0.2rem 0.5rem; border-radius: 0.2rem; &:hover { opacity: 0.8; } } &[readonly] { cursor: not-allowed; } } } &:not(:has(.webmention__list li)) { & hr { display: none; } } } .webmention__tip { margin: revert; font-size: revert; color: var(--color-text-secondary); color: light-dark( var(--color-text-secondary), var(--dark-color-text-secondary) ); } .webmention__list { list-style: none; padding-inline: 0; display: flex; flex-direction: column; margin-block: 0; gap: 2.5rem; & blockquote { padding-inline: 1rem; } @media screen and (width <= 400px) { list-style: none; padding-inline-start: 0; } } .webmention__profile { display: grid; grid-template-columns: max-content auto; grid-template-areas: "avatar author" "avatar source"; column-gap: 1rem; } .webmention__avatar { object-fit: contain; border-radius: 0.5rem; width: 3.5rem; align-self: start; grid-area: avatar; @media screen and (width <= 400px) { width: 2.5rem; } } .webmention__author { margin-inline-end: 1rem; grid-area: author; } .webmention__source { word-break: break-all; grid-area: source; margin: 0; align-self: end; } .webmention__content { clear: both; margin-block-start: 1rem; &:empty { display: none; } } .webmention__date { margin-block: .5rem 0; font-size: .75rem; color: var(--color-text-secondary); color: light-dark(var(--color-text-secondary), var(--dark-color-text-secondary)); word-break: break-all; } .h-card[aria-hidden="true"] { display: none; }
:focus-visible
使用 tab 聚焦到可点击元素时的样式,增加了动画,使得被聚焦的元素更明显。
/** :focus-visible is a neat pseudo-class that only applies focus styles when users navigate with the keyboard. */ *:focus-visible { outline-color: var(--color-fucus-visible-outline); outline-color: light-dark(var(--color-fucus-visible-outline), var(--dark-color-fucus-visible-outline)); outline-style: solid; outline-offset: .25rem; outline-width: .2rem; border-radius: .1rem; } @media (prefers-reduced-motion: no-preference) { *:focus-visible { animation: outline-bounce .5s; } } @keyframes outline-bounce { 0% { outline-offset: .25rem } 50% { outline-offset: .5rem } 100% { outline-offset: .25rem } }
heading-enhanced
heading-enhanced.js 使得 heading 可点击,因此给 heading 添加了相关样式。
h1, h2, h3, h4, h5, h6 { &:not(h1):hover { cursor: pointer; text-decoration: underline; text-underline-offset: .5rem; } }
note section
note section 一般用于一些补充内容,设置一个特殊的样式,使其正文区分。
section[role="note"] { border: 2px dashed; border-color: var(--color-border); border-color: light-dark(var(--color-border), var(--dark-color-border)); color: var(--color-text-secondary); color: light-dark(var(--color-text-secondary), var(--dark-color-text-secondary)); padding-inline: 1rem; margin-block: 1rem; border-radius: 0.5rem; position: relative; &::before { /* ✏ 的 Unicode \270F, \FE0E 是文本变体选择器,选择纯文本形式展示 */ content: "\270F\FE0E"; position: absolute; font-size: 2rem; inset-block-start: -1rem; inset-inline-start: 0; color: var(--color-border); color: light-dark(var(--color-border), var(--dark-color-border)); transform: rotate(135deg); } & + section[role="note"] { margin-block-start: 1rem; } }
sidenote
footnote 增强。
@media (max-width: 1500px) { .sidenote-container, .sidenote { display: none !important; } } .sidenote-container { position: absolute; top: 0; left: 0; right: 0; pointer-events: none; z-index: 1; } .sidenote { /* 屏幕宽度减去内容宽度后,剩余 margin 的一半用于展示 sidenote, 宽度减少 1em 避免内容溢出到右侧,导致横向滚动条 */ width: calc(var(--half-content-margin) - 1rem); font-size: 0.8em; pointer-events: auto; display: grid; grid-template-columns: min-content 1fr; gap: 0.2em; transition: opacity .25s ease-in-out; opacity: 0.65; align-items: start; &:hover { opacity: 1; } } .sidenote-num { display: inline-block; cursor: pointer; margin-inline-end: .5em; white-space: nowrap; } .sidenote-content { min-width: 0; } #content a[role="doc-backlink"], .sidenote-num { position: relative; &::before { content: ''; position: absolute; top: var(--extra-active-area-size); left: var(--extra-active-area-size); right: var(--extra-active-area-size); bottom: var(--extra-active-area-size); cursor: pointer; } &:hover&::before { border: 3px solid; border-color: var(--color-box-shadow); border-color: light-dark(var(--color-box-shadow), var(--dark-color-box-shadow)); border-radius: 5px; } } .sidenote-num:hover, .sidenote-ref-highlight, .sidenote-ref-highlight a[role="doc-backlink"] { &::before { border: 3px solid; border-color: var(--color-box-shadow); border-color: light-dark(var(--color-box-shadow), var(--dark-color-box-shadow)); border-radius: 5px; } } .sidenote-content *:nth-child(1) { margin-block-start: 0; }
layer end
}
@layer special
layer start
@layer special {
emacs mark
主要用在 Emacs Elevator Pitch - Only Emacs can save your soul。
mark.emacs { background: linear-gradient(to right bottom, #8482c7, #943dc1); box-shadow: 1px 2px 2px var(--color-box-shadow); box-shadow: 1px 2px 2px light-dark(var(--color-box-shadow), var(--dark-color-box-shadow)); color: #fff; border-radius: 5px; padding: 0px 4px; }
retro theme
样式借鉴了 rohit。
/* scan-line, retro style */ /* inspire from https://seated.ro/blog/tinkering-a-lost-art */ body:where(.dark-retro)::after { content: ""; position: fixed; top: 0; left: 0; bottom: 0; right: 0; background-repeat: repeat; background-attachment: fixed; pointer-events: none; z-index: 3; } body.dark-retro::after { --scan-line-width: 1px; background-image: linear-gradient(oklch(0 0 0 / .8) var(--scan-line-width), transparent var(--scan-line-width)); background-size: calc(2 * var(--scan-line-width)) calc(2 * var(--scan-line-width)); @media screen and (width <= 400px) { --scan-line-width: .7px; } }
image-list
目前用于 日常#12 - 苹果设备的联动、最近做的一些菜式、死亡搁浅、深圳美术馆看展。
/* 只支持全部都是 <figure> 或者全部都是 <a> */ .image-list { display: flex; justify-content: center; gap: 1em; flex-wrap: wrap; overflow: auto; max-height: 65vh; border: 2px dashed; border-color: var(--color-border); border-color: light-dark(var(--color-border), var(--dark-color-border)); color: var(--color-text-secondary); color: light-dark(var(--color-text-secondary), var(--dark-color-text-secondary)); padding: 1em; margin-block: 1em; border-radius: .5em; & a { height: auto; } & figure { margin: 0; } & img { max-height: 50vh; } }
blockquote/verse
.vertical-rl
有的 blockquote/verse 文字是纵向的,针对它们调整间距等样式。
blockquote.vertical-rl, p.verse.vertical-rl { writing-mode: vertical-rl; padding: 0; border: none; padding-block-start: 0.5rem; font-size: 0.9rem; width: 100%; max-width: 100%; overflow: auto; container-type: scroll-state; container-name: vertical-rl; position: relative; .footref { writing-mode: initial; } @media screen and (width >= 580px) { &.center { align-content: center; } } } @container vertical-rl scroll-state(scrollable: block-end) { p.verse.vertical-rl::after { content: "☟"; position: absolute; inset-block-end: 0; inset-inline-end: 0; font-size: 1.2rem; } }
.indent-paragraph
带有 .indent-paragraph 的内容,段落首行缩紧 2 个字。
details.indent-paragraph p, blockquote.indent-paragraph { text-indent: 2rem; }
.single
带有 .single 的引用,会使用引号包裹起来。
:where(.verse,blockquote).single {
border: none;
position: relative;
margin-block: 2rem;
&::before,
&::after {
color: var(--color-border);
color: light-dark(var(--color-border), var(--dark-color-border));
font-size: 4rem;
position: absolute;
}
&::before {
content: "“";
top: 0.2rem;
left: -0.1rem;
line-height: 0.2rem;
}
&::after {
content: "”";
right: -0.1rem;
bottom: -0.6rem;
line-height: 0.2rem;
}
}
.hidden-link
有的彩蛋链接,为了避免暴露,将链接颜色改成和正文颜色一样。静待有缘人发现 :P
.hidden-link a { text-decoration: none; color: var(--color-text); color: light-dark(var(--color-text), var(--dark-color-text)); &:hover { color: #fff; } &:visited { color: var(--color-text); color: light-dark(var(--color-text), var(--dark-color-text)); } }
inline image
行内图片,和文字一样大的图片,很少用到。
img.inline-image { width: 1rem; height: 1rem; vertical-align: -3.5px; }
float image
添加 .float-start 或 .float-end 可以让图片浮动,图片会占据一半的内容空间。当屏幕较小时,取消浮动,让图片显示得更大一些。
例如:
figure { &:has(.float-start) { float: inline-start; margin-block: 0; margin-inline-end: 1rem; max-width: 50%; } &:has(.float-end) { float: inline-end; margin-block: 0; margin-inline-start: 1rem; max-width: 50%; } &:has(.center) { text-align: center; } @media screen and (width <= 765px) { &:has(:is(.float-start, .float-end)) { float: none; margin-inline: 0; margin-block: 1rem; max-width: fit-content; } } }
layer end
}
index.css
首页的样式。
@import "./88-31-button.css";
标题
header { & h1 { transition: text-shadow 0.25s ease-in-out, color 0.25s ease-in-out; &:hover { color: transparent; text-shadow: var(--color-taxodium-purple) -5px -5px 1px, var(--color-taxodium-yellow) 10px 10px 5px; } } } h2 { text-align: center; width: 100%; } /* 文章标题的子标题 */ .sitemap-subtitle { color: var(--color-text-secondary); color: light-dark(var(--color-text-secondary), var(--dark-color-text-secondary)); font-size: 0.85rem; } /* 标题下的一句话 */ header + p { text-align: center; color: var(--color-text-secondary); color: light-dark(var(--color-text-secondary), var(--dark-color-text-secondary)); } /* 移除 postamble 的内容 */ #postamble::before { display: none; }
quick access
.quick-access { text-align: center; line-height: 1; a { text-decoration: none; position: relative; display: inline-block; transition: transform 0.2s; &:active { transform: scale(0.9); } &.anime { filter: grayscale(1) brightness(0.75); transition: all 0.8s; } &.black-hole { padding-inline: 0.5rem; cursor: none; } &:hover { background: unset; &.changelog { transform-origin: center bottom; animation: jelly 0.7s; } &.music-rank { animation: infinite play-cd 1s linear; transform-origin: 48% 45%; } &.black-hole { cursor: none; &::before { cursor: none; } } &.anime { filter: grayscale(0) brightness(120%); } &.tools { transform-origin: center center; animation: infinite heat-hammer 0.8s linear; } } /* 扩大 icon 的 hover 范围 */ &::before { content: ""; position: absolute; top: var(--extra-active-area-size); left: var(--extra-active-area-size); right: var(--extra-active-area-size); bottom: var(--extra-active-area-size); cursor: pointer; } &::after { display: none !important; } } } @keyframes jelly { 0% { transform: scale(1, 1); } 30% { transform: scale(1.25, 0.75); } 40% { transform: scale(0.75, 1.25); } 50% { transform: scale(1.15, 0.85); } 65% { transform: scale(0.95, 1.05); } 75% { transform: scale(1.05, 0.95); } 100% { transform: scale(1, 1); } } @keyframes play-cd { 0% { transform: rotate(0); } 100% { transform: rotate(360deg); } } @keyframes heat-hammer { 0% { transform: rotateZ(-25deg); } 100% { transform: rotateZ(15deg); } } @keyframes unroll { 0% { clip-path: inset(0 0 100% 0); opacity: 0; } 100% { clip-path: inset(0 0 0 0); opacity: 1; } }
列表
实现类似书籍目录的样式。
页码实现可以参考 Zine#14::Responsive TOC leader lines with CSS。
#content ul { padding-inline-start: 0; counter-reset: step; counter-set: step -1; transition: background 0.25s ease-in-out; li { counter-increment: step; display: grid; grid-template-columns: auto max-content; grid-template-areas: "chapter page"; gap: 0 0.5rem; margin-block: 0.5rem; &::after { grid-area: page; content: counter(step); color: var(--color-border); color: light-dark(var(--color-border), var(--dark-color-border)); font-size: 1.2rem; text-align: end; } & a { grid-area: chapter; overflow: hidden; position: relative; &::after { position: absolute; content: " . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " ". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . "; text-align: end; padding-left: 0.5rem; color: var(--color-border); color: light-dark(var(--color-border), var(--dark-color-border)); } } .timestamp { display: none; } } }
album.css
专辑分享页面的特殊样式。
.figure-number { display: none; } #postamble::before { content: "take a sad song and make it better"; @media screen and (width <= 400px) { font-size: 0.8rem; } } p.verse { border: none; padding: 0; } :is(.footpara, .sidenote-content) p.verse { padding: 0; } .sidenote { font-size: 0.95rem; } img[src*="images\/album"] { border-radius: 10px; @media (prefers-color-scheme: light) { box-shadow: 5px 2px 5px var(--color-box-shadow); } @media (prefers-color-scheme: dark) { box-shadow: 0 0 10px var(--dark-color-box-shadow); } } .light img[src*="images\/album"] { box-shadow: 5px 2px 5px var(--color-box-shadow); } .dark img[src*="images\/album"] { box-shadow: 0 0 10px var(--dark-color-box-shadow); }
lyrics
一些特殊歌词样式。
见:
.lyrics { & i { color: var(--color-text); color: light-dark(var(--color-text), var(--dark-color-text)); } } .lyrics--cute i { font-family: Schoolbell, var(--font-family); } .lyrics--color { color: var(--color-lyrics); color: light-dark(var(--color-lyrics), var(--dark-color-lyrics)); } .lyrics--small { font-size: 0.8rem; } .lyrics--large { font-size: 1.2rem; } .lyrics--huge { font-size: 1.5rem; }
album-wall.css
Album Wall 页面的特殊样式。
.figure-number { display: none; } .filter { text-align: center; align-items: center; justify-content: center; display: flex; gap: 0.2rem; & label, input { cursor: pointer; } } #content:has(#filter-shared:checked) figure:has(a[href*="images\/album"]) { display: none; } .album-wall { display: grid; grid-template-columns: repeat(auto-fill, calc(20px * 14)); gap: 0 1.5rem; justify-content: center; width: 99vw; position: relative; left: 50%; right: 50%; margin-left: -49.5vw; margin-right: -49.5vw; @media screen and (width <= 1920px) { grid-template-columns: repeat(auto-fill, calc(20px * 12)); } @media screen and (width <= 800px) { grid-template-columns: repeat(auto-fill, calc(20px * 10)); } @media screen and (width <= 650px) { grid-template-columns: repeat(2, calc(20px * 8)); gap: 1rem 0.5rem; width: 100%; left: 0; right: 0; margin: 0; } @media (pointer: fine) and (hover: hover) { & figure { &:hover { transform: rotate(0); z-index: 1; filter: grayscale(0) blur(0); & figcaption { opacity: 1; transform: translateY(0); } } } } p { display: none; } & figure { margin: 0; position: relative; transform: perspective(500px) rotateX(5deg) rotateY(-5deg) rotateZ(1deg); transition: transform 0.25s ease-in-out, opacity 0.8s ease-in-out, filter 1.5s ease-in-out, display 0.25s allow-discrete ease-in-out; transform-origin: center bottom; filter: grayscale(0.95) blur(0.55px); & figcaption { transition: transform 0.25s ease-in-out, opacity 0.25s ease-in-out; transition-delay: 0.5s; opacity: 0; transform: translateY(-25%); } @starting-style { opacity: 0; } @media screen and (width <= 400px) { transform: unset; filter: grayscale(0) blur(0); & figcaption { opacity: 1; transform: none; } } } & img { object-fit: cover; aspect-ratio: 1; width: 100%; box-shadow: -5px 5px 5px var(--color-box-shadow) !important; border-radius: 3px; } }
88-31-button.css
88x31 按钮的特殊样式,在页面按需引用。
.buttons-container { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.5em; figure { margin: 0; width: fit-content; display: inline-block; max-width: 88px; max-height: 31px; img { max-width: 88px; max-height: 31px; } } p { display: inline-flex; width: 88px; height: 31px; border: 2px dashed; border-color: var(--color-border); border-color: light-dark(var(--color-border), var(--dark-color-border)); font-size: 0.5em; white-space: nowrap; margin: 0; align-items: center; justify-content: center; box-sizing: border-box; &:hover { background: var(--color-link); background: light-dark(var(--color-link), var(--dark-color-link)); a { color: #fff; } } a { color: var(--color-text); color: light-dark(var(--color-text), var(--dark-color-text)); text-decoration: none; &:hover { background: none; } } } }
image-enhance.css
图片增强样式:
- 隐藏 figure-number
- 图片增加圆角和阴影
.figure-number { display: none } img { border-radius: 10px; @media (prefers-color-scheme: light) { box-shadow: 5px 5px 8px var(--color-box-shadow); } @media (prefers-color-scheme: dark) { box-shadow: 0 0 10px var(--dark-color-box-shadow); } } .light img { box-shadow: 5px 5px 8px var(--color-box-shadow); } .dark img { box-shadow: 0 0 10px var(--dark-color-box-shadow); }
text-indent.css
对于大量文字为主的文章,可以考虑首行缩进,通过引入额外样式实现。
#content p { text-indent: 2em; } #content :where(blockquote,[role=note],.sidenote-content,.footpara) p { text-indent: 0em; }