Skip to main content

博客样式设计

之前参加了 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;
}
Webmentions (加载中...)

如果你想回应这篇文章,可以在你的文章或社交媒体帖子中链接这篇文章,然后提交你的 URL,你的回应随后会显示在此页面上。 (关于 Webmention)