yggdrasil/input.css
xfy 07d737af0f fix(markdown): 修复窄表格在 table-wrap 内边框被裁切
overflow-x:auto 会强制 overflow-y 也建滚动盒,裁切 table 向外 spread 的 1px
box-shadow 描边,导致不需要滚动的窄表格右下角边框断裂。

给 .table-wrap 加 padding:1px 为描边预留空间,负 margin:-1px 抵消外部尺寸
偏移,使 wrap 不撑大父容器、左上仍贴齐正文边缘。
2026-07-23 16:18:12 +08:00

1109 lines
29 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@import "tailwindcss";
@custom-variant dark (&:where(.dark, .dark *));
@theme {
/* 覆盖 Tailwind v4 默认 --font-sans(ui-sans-serif, system-ui, sans-serif, ...):
默认栈不含 CJK sans,font-sans 类一旦生效,body 的中文字体栈会被绕过,
中文 fallback 到系统衬线体。这里对齐 body 的 CJK sans 栈,根治全项目。 */
--font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif, 'Noto Sans SC', 'PingFang SC', 'Microsoft YaHei';
--font-serif: 'Source Serif 4', 'Noto Serif SC', 'Source Han Serif SC', 'Songti SC', Georgia, serif;
/* Catppuccin Latte亮色。语义 token → 调色板角色:
theme=base entry=mantle primary=text secondary=subtext1
tertiary=overlay0 content=subtext0 code-block=crust code-bg=surface0
border=surface1 accent=green accent-2=teal主/次强调色) */
--color-paper-theme: #eff1f5;
--color-paper-entry: #e6e9ef;
--color-paper-primary: #4c4f69;
--color-paper-secondary: #5c5f77;
--color-paper-tertiary: #9ca0b0;
--color-paper-content: #6c6f85;
--color-paper-code-block: #dce0e8;
--color-paper-code-bg: #ccd0da;
--color-paper-border: #bcc0cc;
--color-paper-accent: #40a02b;
--color-paper-accent-soft: #ccd0da;
--color-paper-accent-2: #179299;
--color-paper-accent-2-soft: #ccd0da;
/* 圆角三档梯度:容器 32 → 内容 16 → 微元素 8。
按钮/头像/徽章另用胶囊Tailwind rounded-full独立于本梯度。 */
--radius-card: 2rem; /* 32px文章卡片、封面、admin 主面板 */
--radius-paper: 16px; /* 16px代码块、正文图片、iframe、表格、输入框、admin 卡片 */
--radius-mini: 8px; /* 8px标签、复制按钮、toc、paginav */
--gap-paper: 24px;
--content-gap-paper: 20px;
--nav-width-paper: 1024px;
--main-width-paper: 720px;
}
@layer base {
html {
scroll-behavior: smooth;
background-color: var(--color-paper-theme);
}
body {
background-color: var(--color-paper-theme);
color: var(--color-paper-primary);
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans SC', 'PingFang SC', 'Microsoft YaHei', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
@keyframes page-enter {
0% {
opacity: 0;
transform: translateY(16px) scale(0.995);
}
100% {
opacity: 1;
transform: none;
}
}
.animate-page-enter {
animation: page-enter 400ms cubic-bezier(0.22, 1, 0.36, 1) both;
}
/* Popover / 确认框淡入缩放(比 page-enter 更轻、更快) */
@keyframes popover-enter {
0% {
opacity: 0;
transform: translateX(-50%) scale(0.95);
}
100% {
opacity: 1;
transform: translateX(-50%) scale(1);
}
}
.animate-popover-enter {
animation: popover-enter 150ms cubic-bezier(0.22, 1, 0.36, 1) both;
}
/* Minimalist custom scrollbars */
* {
scrollbar-width: thin;
scrollbar-color: var(--color-paper-border) transparent;
}
::-webkit-scrollbar {
width: 6px;
height: 6px;
}
::-webkit-scrollbar-track {
background: transparent;
}
::-webkit-scrollbar-thumb {
background-color: var(--color-paper-border);
border-radius: 10px;
}
::-webkit-scrollbar-thumb:hover {
background-color: var(--color-paper-tertiary);
}
.dark {
/* Catppuccin Mocha暗色。accent-soft 带绿调、accent-2-soft 带 teal 调,
在 surface0 暗底上透出微弱主/次强调色。 */
--color-paper-theme: #1e1e2e;
--color-paper-entry: #181825;
--color-paper-primary: #cdd6f4;
--color-paper-secondary: #bac2de;
--color-paper-tertiary: #6c7086;
--color-paper-content: #a6adc8;
--color-paper-code-block: #313244;
--color-paper-code-bg: #313244;
--color-paper-border: #45475a;
--color-paper-accent: #a6e3a1;
--color-paper-accent-soft: #1e2e22;
--color-paper-accent-2: #94e2d5;
--color-paper-accent-2-soft: #1e2a28;
}
}
@layer components {
.post-single {
margin: 0 auto;
}
.post-header {
margin: 48px auto 48px auto;
display: flex;
flex-direction: column;
gap: 16px;
}
.post-title {
font-size: clamp(2.5rem, 6vw, 4.5rem);
font-weight: 800;
line-height: 1.1;
color: var(--color-paper-primary);
word-break: break-word;
letter-spacing: -0.04em;
margin: 0;
}
.post-description {
color: var(--color-paper-secondary);
font-size: 1.125rem;
font-weight: 500;
line-height: 1.7;
margin: 0;
}
.post-meta {
margin-top: 8px;
color: var(--color-paper-tertiary);
font-size: 15px;
display: flex;
align-items: center;
gap: 0.75rem;
flex-wrap: wrap;
font-weight: 500;
}
.post-meta a {
color: var(--color-paper-secondary);
text-decoration-style: dotted;
text-underline-offset: 0.3rem;
text-decoration: underline;
}
.post-meta a:hover {
color: var(--color-paper-primary);
}
.breadcrumbs {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.2rem;
color: var(--color-paper-secondary);
font-size: 14px;
margin-bottom: 10px;
}
.breadcrumbs a {
font-size: 16px;
color: var(--color-paper-primary);
}
.breadcrumbs a:hover {
text-decoration: underline;
text-underline-offset: 0.2rem;
}
.entry-hint {
display: inline-flex;
margin-left: 0.5rem;
color: var(--color-paper-secondary);
}
details.toc {
margin-bottom: var(--content-gap-paper);
background: var(--color-paper-code-bg);
border-radius: var(--radius-mini);
border: 1px solid var(--color-paper-border);
}
details.toc summary {
padding: 0.3rem 1.2rem;
border-radius: var(--radius-mini);
cursor: pointer;
display: list-item;
width: 100%;
user-select: none;
color: var(--color-paper-primary);
}
details.toc .title {
display: inline;
font-weight: 500;
margin-inline-start: 0.2rem;
}
details.toc .inner {
margin: 0 2.4rem;
padding-bottom: 0.6rem;
}
details.toc ul {
list-style: none;
padding: 0;
margin: 0;
}
details.toc li {
margin: 0.3rem 0;
}
details.toc a {
color: var(--color-paper-secondary);
text-decoration: none;
font-size: 14px;
}
details.toc a:hover {
color: var(--color-paper-primary);
text-decoration: underline;
text-underline-offset: 0.3rem;
}
details.toc li ul {
margin-inline-start: var(--gap-paper);
}
details {
interpolate-size: allow-keywords;
}
details::details-content {
height: 0;
opacity: 0;
overflow: clip;
transition: height 150ms ease, opacity 150ms ease, content-visibility 150ms allow-discrete;
}
details[open]::details-content {
height: auto;
opacity: 1;
}
/* 正文折叠块(作者手写的 <details>,区别于 .toc 导航块)。
复用代码块/blockquote 的视觉语言:同款底色 + 边框 + 16px 圆角;
自绘 chevron 替代浏览器原生三角,展开时旋转 90°。
:not(.toc) 避免与上面的 TOC 专用样式冲突。 */
.md-content details:not(.toc) {
margin: 1rem 0;
background: var(--color-paper-code-bg);
border: 1px solid var(--color-paper-border);
border-radius: var(--radius-paper);
}
.md-content details:not(.toc) > summary {
padding: 0.6rem 1rem;
cursor: pointer;
user-select: none;
list-style: none;
color: var(--color-paper-primary);
font-weight: 500;
display: flex;
align-items: center;
gap: 0.4rem;
transition: background-color 120ms ease;
}
/* 去掉 WebKit/Blink 原生三角,统一用 ::before 自绘 chevron。 */
.md-content details:not(.toc) > summary::-webkit-details-marker {
display: none;
}
/* 自绘 chevron实心三角展开时旋转 90° 平滑过渡。
用 currentColor 继承 summary 文字色,随主题变化。 */
.md-content details:not(.toc) > summary::before {
content: "";
display: inline-block;
flex-shrink: 0;
width: 0;
height: 0;
border-style: solid;
border-width: 0.32rem 0.42rem 0.32rem 0;
border-color: transparent currentColor transparent transparent;
transform: rotate(0deg);
transition: transform 150ms ease;
margin-inline-start: 0.1rem;
}
.md-content details:not(.toc)[open] > summary::before {
transform: rotate(90deg);
}
.md-content details:not(.toc) > summary:hover {
background-color: color-mix(in srgb, var(--color-paper-accent) 8%, transparent);
}
/* 键盘可访问focus-visible 给可见轮廓WCAG 2.4.7)。
.dark 前缀走暗色主题色。 */
.md-content details:not(.toc) > summary:focus-visible {
outline: 2px solid var(--color-paper-accent);
outline-offset: -2px;
border-radius: var(--radius-paper);
}
/* 展开内容左右内边距(代码块/段落不贴边),末元素留底部呼吸空间。 */
.md-content details:not(.toc)[open] > *:not(summary) {
padding-inline: 1rem;
}
/* 首元素紧接 summary 去顶部 margin末元素去底部 margin容器已留白。 */
.md-content details:not(.toc)[open] > *:not(summary):first-of-type {
margin-top: 0;
}
.md-content details:not(.toc)[open] > *:not(summary):last-child {
margin-bottom: 0;
padding-bottom: 0.8rem;
}
.entry-cover {
margin-bottom: var(--content-gap-paper);
}
/* 封面用 blur-img 结构:去 margin、保持圆角内层 img cover 填充 */
.entry-cover .blur-img {
margin: 0;
border-radius: var(--radius-card);
overflow: hidden;
}
.entry-cover img {
width: 100%;
height: 100%;
object-fit: cover;
}
.post-content {
color: var(--color-paper-content);
margin: 30px 0;
}
.md-content h1 {
margin: 40px auto 32px;
font-size: 40px;
color: var(--color-paper-primary);
letter-spacing: -0.01em;
}
.md-content h2 {
margin: 32px auto 24px;
font-size: 32px;
color: var(--color-paper-primary);
letter-spacing: -0.01em;
}
.md-content h3 {
margin: 24px 0 16px;
font-size: 24px;
color: var(--color-paper-primary);
}
.md-content h4 {
margin: 24px 0 16px;
font-size: 16px;
color: var(--color-paper-primary);
}
.md-content h5 {
margin: 24px 0 16px;
font-size: 14px;
color: var(--color-paper-primary);
}
.md-content h6 {
margin: 24px 0 16px;
font-size: 12px;
color: var(--color-paper-primary);
}
/* 锚点目标偏移scrollIntoView / 原生 fragment-scroll 落点避开 80px sticky header。
[id] 限定只作用于带锚点 id 的标题6rem = 80px header + 16px 呼吸空间。 */
.md-content :is(h1, h2, h3, h4, h5, h6)[id] {
scroll-margin-top: 6rem;
}
.md-content a:not(.anchor) {
text-underline-offset: 0.3rem;
text-decoration: underline;
color: var(--color-paper-accent);
}
.md-content a:not(.anchor):hover {
color: var(--color-paper-accent-2);
}
.md-content p {
margin-bottom: var(--content-gap-paper);
line-height: 1.85;
}
.md-content p:last-child {
margin-bottom: 0;
}
.md-content blockquote {
margin: 1rem 0;
padding-inline-start: 1rem;
border-inline-start: 0.3rem solid var(--color-paper-content);
color: var(--color-paper-secondary);
}
.md-content blockquote p:last-child {
margin-bottom: 0;
}
/* 脚注引用上标:[^id] 渲染成的 <sup class="fn-ref">。
* line-height: 0 防止上标撑高所在行行高font-size 缩小为 0.75em。 */
.md-content .fn-ref {
font-size: 0.75em;
line-height: 0;
vertical-align: super;
margin-inline-start: 0.1em;
}
/* 引用数字链接:不加下划线(上标下划线极难看),用 accent 色区分。 */
.md-content .fn-ref-link {
text-decoration: none;
color: var(--color-paper-accent);
}
.md-content .fn-ref-link:hover {
color: var(--color-paper-accent-2);
}
/* 脚注定义块:仿 blockquote 的左侧边框视觉语言但更轻0.2rem + 稍小字号)。 */
.md-content .footnote-definition {
margin: 1rem 0;
padding-inline-start: 1rem;
border-inline-start: 0.2rem solid var(--color-paper-content);
font-size: 0.875em;
color: var(--color-paper-secondary);
}
.md-content .footnote-definition:last-child {
margin-bottom: 0;
}
/* 定义内末段去底距,避免与 back-link 间距过大。 */
.md-content .footnote-definition > p:last-child {
margin-bottom: 0;
}
/* 定义编号上标:与正文引用数字呼应。 */
.md-content .footnote-definition-label {
font-size: 0.75em;
line-height: 0;
vertical-align: super;
margin-inline-end: 0.25em;
color: var(--color-paper-tertiary);
}
/* 返回正文链接:↩ 符号弱色hover 转 accent。 */
.md-content .fn-backref {
margin-inline-start: 0.25em;
text-decoration: none;
color: var(--color-paper-tertiary);
}
.md-content .fn-backref:hover {
color: var(--color-paper-accent);
}
/* 多引用时的数字上标(↩² 中的 ²)。 */
.md-content .fn-backref-num {
font-size: 0.75em;
vertical-align: super;
}
.md-content ol,
.md-content ul {
padding-inline-start: 1.25rem;
margin-bottom: var(--content-gap-paper);
}
/* Tailwind Preflight 把 list-style 清成 none,这里恢复被清掉的 marker。
* 任务列表项(含 checkbox 的 li另有规则覆盖为 none不受影响。 */
.md-content ul {
list-style-type: disc;
}
.md-content ol {
list-style-type: decimal;
}
.md-content li {
margin-top: 0.3rem;
}
.md-content li p {
margin-bottom: 0;
}
/* 任务列表pulldown-cmark 把 - [ ] / - [x] 渲染成裸 <li><input type="checkbox">…
* (无 <label> 包裹,也无 data-type 标记)。用 :has() 识别含 checkbox 的 li
* 布局成 flex 让复选框与文本对齐;不支持 :has() 的浏览器降级为普通列表,仍可读。 */
.md-content li:has(> input[type="checkbox"]) {
list-style: none;
margin-left: -1.25rem;
display: flex;
align-items: center;
gap: 0.5rem;
}
.md-content li > input[type="checkbox"] {
/* appearance:none 全自定义:告别浏览器原生方框形状/边框差异。
对勾用内联 SVG background<input> 是替换元素,吃不到 ::after
颜色按主题烘焙——亮色中绿底配白对勾,暗色浅绿底配深对勾,对比最强。
文章内 checkbox 是 disabled 的纯展示态,故不加 focus/cursor 交互。 */
appearance: none;
-webkit-appearance: none;
flex-shrink: 0;
width: 1.15rem;
height: 1.15rem;
margin: 0;
border: 1.5px solid var(--color-paper-border);
border-radius: 4px;
background-color: transparent;
background-position: center;
background-repeat: no-repeat;
background-size: 0.75rem;
cursor: default;
transition: background-color 0.15s ease, border-color 0.15s ease;
}
.md-content li > input[type="checkbox"]:checked {
background-color: var(--color-paper-accent);
border-color: var(--color-paper-accent);
/* 亮色:中绿 #40a02b 底 + 白对勾(对比 ≥ 4.5:1 */
background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2016%2016'%20fill='none'%20stroke='%23ffffff'%20stroke-width='2.2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M3.5%208.5l3%203%206-6.5'/%3E%3C/svg%3E");
}
/* 暗色:浅绿 #a6e3a1 底上白对勾对比不足,改深色对勾(主题底色 #1e1e2e */
.dark .md-content li > input[type="checkbox"]:checked {
background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2016%2016'%20fill='none'%20stroke='%231e1e2e'%20stroke-width='2.2'%20stroke-linecap='round'%20stroke-linejoin='round'%3E%3Cpath%20d='M3.5%208.5l3%203%206-6.5'/%3E%3C/svg%3E");
}
.md-content hr {
margin: 30px 0;
height: 2px;
background: var(--color-paper-tertiary);
border: 0;
}
/* table-wrap渲染器给宽表格套的滚动容器移动端窄屏可横向滚动。
(见 src/api/markdown.rs::wrap_tables。min-width 让窄表仍撑满、宽表撑开触发滚动。
padding 为 table 的 1px box-shadow 描边预留空间overflow 容器overflow-x:auto 会
强制 overflow-y 也建滚动盒)会裁切向外 spread 的阴影,导致右下边框断裂。
负 margin 抵消 padding 的外部尺寸,使 wrap 不撑大父容器、左上仍贴齐正文边缘。 */
.md-content .table-wrap {
margin: -1px;
padding: 1px;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
.md-content table {
margin-bottom: var(--content-gap-paper);
width: 100%;
min-width: 100%;
border-collapse: separate;
border-spacing: 0;
border-radius: var(--radius-paper);
box-shadow: 0 0 0 1px var(--color-paper-border);
}
.md-content table thead th {
background: var(--color-paper-code-block);
font-weight: 600;
color: var(--color-paper-primary);
padding: 16px 24px;
text-align: left;
border-bottom: 1px solid var(--color-paper-border);
white-space: nowrap;
}
.md-content table thead th:first-child {
border-top-left-radius: var(--radius-paper);
}
.md-content table thead th:last-child {
border-top-right-radius: var(--radius-paper);
}
.md-content table tbody tr:last-child td:first-child {
border-bottom-left-radius: var(--radius-paper);
}
.md-content table tbody tr:last-child td:last-child {
border-bottom-right-radius: var(--radius-paper);
}
.md-content table tbody td {
padding: 16px 24px;
line-height: 1.6;
border-bottom: 1px solid var(--color-paper-border);
color: var(--color-paper-secondary);
}
.md-content table tbody tr:last-child td {
border-bottom: none;
}
.md-content table tbody tr {
transition: background-color 0.2s ease;
}
.md-content table tbody tr:hover {
background: var(--color-paper-entry);
}
/* 排除 CodeMirror 编辑器内的 <img>CM 用 <img class="cm-widgetBuffer">width:0、
height:1em 的占位符)对齐折叠 widget 的基线。若被这里的 margin/height 命中,
会把折叠那行 .cm-line 撑高约 32px上下各 1rem margin。用 :where() 把
.cm-editor 后代的 img 优先级压到 0确保 CM 内部任何 img 都不受正文图片样式影响。 */
.md-content img:where(:not(.cm-widgetBuffer)) {
border-radius: var(--radius-paper);
margin: 1rem 0;
max-width: 100%;
height: auto;
}
.dark .md-content img:not(.blur-img-placeholder):not(.blur-img-full),
.dark .md-content .blur-img,
.dark .lightbox-img {
filter: brightness(0.9);
}
.md-content-img-zoomable {
cursor: zoom-in;
transition: opacity 0.2s ease-out;
}
.md-content-img-zoomable:hover {
opacity: 0.9;
}
.md-content iframe {
max-width: 100%;
border-radius: var(--radius-paper);
}
.md-content code {
padding: 0.2rem 0.3rem;
font-size: 0.85em;
line-height: 1.5;
background: var(--color-paper-code-bg);
border-radius: 0.2rem;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
}
.md-content pre {
position: relative;
margin-bottom: var(--content-gap-paper);
background: var(--color-paper-code-block);
border-radius: var(--radius-paper);
overflow-x: auto;
}
.md-content pre code {
display: block;
padding: 16px;
background: transparent;
border-radius: 0;
overflow-x: auto;
white-space: pre;
font-size: 1rem;
line-height: 1.6;
}
.md-content pre code span {
display: inline !important;
}
.copy-code {
display: none;
position: absolute;
top: 8px;
right: 8px;
color: var(--color-paper-theme);
background: var(--color-paper-tertiary);
border-radius: var(--radius-mini);
padding: 4px 8px;
font-size: 12px;
user-select: none;
cursor: pointer;
border: none;
font-family: inherit;
transition: background 0.2s ease-out;
}
.copy-code:hover {
background: var(--color-paper-accent);
}
pre:hover .copy-code,
.highlight:hover .copy-code {
display: block;
}
/* ── mermaid 图表容器 ──
data-mermaid-rendered 由 yggdrasil-core/mermaid.ts 渲染成功后标记在 <pre> 上。
渲染后 pre 唯一子元素是 <svg>mermaid 块不注入 copy-code 按钮flex 安全。
居中 + 缩放适配宽度,消除常规图的横向滚动;超宽图 overflow-x:auto 兜底。 */
.md-content pre[data-mermaid-rendered] {
display: flex;
justify-content: center;
align-items: center;
padding: 24px 16px;
overflow-x: auto;
}
.md-content pre[data-mermaid-rendered] > svg {
max-width: 100%;
height: auto;
display: block;
}
/* 渲染失败:保留原始源码,加 accent 色左边条提示(站点 accent 为绿,沿用配色体系) */
.md-content pre.mermaid-error {
border-left: 3px solid var(--color-paper-accent);
}
.anchor {
display: none;
text-decoration: none;
color: var(--color-paper-secondary);
}
.md-content h1:hover .anchor,
.md-content h2:hover .anchor,
.md-content h3:hover .anchor,
.md-content h4:hover .anchor,
.md-content h5:hover .anchor,
.md-content h6:hover .anchor {
display: inline-flex;
margin-inline-start: 0.5em;
font-weight: 500;
user-select: none;
text-decoration: none;
color: var(--color-paper-secondary);
}
.anchor:hover {
color: var(--color-paper-primary) !important;
}
.post-footer {
margin-top: var(--content-gap-paper);
}
.post-tags {
display: flex;
flex-wrap: wrap;
gap: 10px;
list-style: none;
padding: 0;
margin: 0 0 var(--content-gap-paper) 0;
}
.post-tags li {
display: inline-block;
}
.post-tags a {
display: block;
padding: 0 14px;
color: var(--color-paper-secondary);
font-size: 14px;
line-height: 34px;
background: var(--color-paper-code-bg);
border-radius: var(--radius-mini);
border: 1px solid var(--color-paper-border);
text-decoration: none;
transition: all 0.2s ease-out;
}
.post-tags a:hover {
background: var(--color-paper-accent-soft);
border-color: var(--color-paper-accent);
color: var(--color-paper-accent);
}
.paginav {
display: flex;
border-radius: var(--radius-mini);
background: var(--color-paper-code-bg);
border: 1px solid var(--color-paper-border);
overflow: hidden;
}
.paginav a {
width: 50%;
display: flex;
flex-direction: column;
gap: 0.5rem;
padding: 0.8rem;
text-decoration: none;
color: var(--color-paper-primary);
transition: background 0.2s ease-out;
}
.paginav a:hover {
background: var(--color-paper-border);
}
.paginav .next {
margin-inline-start: auto;
text-align: right;
}
.paginav .title {
letter-spacing: 1px;
font-size: 0.8rem;
color: var(--color-paper-secondary);
}
.paginav .post-title-nav {
font-size: 16px;
font-weight: 500;
}
.back-to-home {
margin-top: calc(var(--content-gap-paper) * 1.5);
padding-top: var(--content-gap-paper);
border-top: 1px solid var(--color-paper-border);
}
.back-to-home a,
.back-to-home button {
color: var(--color-paper-secondary);
font-size: 14px;
text-decoration: none;
background: none;
border: none;
cursor: pointer;
padding: 0;
font-family: inherit;
}
.back-to-home a:hover,
.back-to-home button:hover {
color: var(--color-paper-primary);
text-decoration: underline;
text-underline-offset: 0.3rem;
}
/* 卡片封面blur-img 结构,固定 21:9 比例hover 缩放。
双类选择器提升特异性,可靠覆盖 .blur-img 的 aspect-ratio: var(--ar)
(卡片不写 --arvar(--ar) 解析为空会导致高度塌陷)。
21:9 与后台编辑器封面区统一比例,宽屏横幅式。 */
.blur-img.post-card-cover-blur {
margin: 0;
aspect-ratio: 21 / 9;
}
.post-card-cover-blur img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s ease-out;
}
.group:hover .post-card-cover-blur img {
transform: scale(1.05);
}
a.accent-link {
color: var(--color-paper-accent);
text-decoration: none;
transition: color 0.2s ease-out;
}
a.accent-link:hover {
color: var(--color-paper-primary);
}
.post-card-accent {
position: relative;
}
.post-card-accent::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 0;
height: 2px;
background: var(--color-paper-accent);
transition: width 0.3s ease-out;
}
.post-card-accent:hover::after {
width: 100%;
}
/* ========== Blur-up 渐进图片加载 ==========
放在 @layer components 内,与 .blur-img.post-card-cover-blur 同层,
这样特异性能正常生效layer 外规则会无条件覆盖 layer 内规则,
导致卡片的 aspect-ratio:4/3 败给全局 var(--ar))。 */
.blur-img {
position: relative;
display: block;
overflow: hidden;
aspect-ratio: var(--ar);
/* 加载中灰底(占位图未加载完时) */
background: var(--color-paper-code-bg);
border-radius: var(--radius-mini);
margin: 1em 0;
}
.blur-img-placeholder {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
/* 重置 .md-content img 的 margin/max-width/height避免把 absolute 图层推偏 */
margin: 0;
max-width: none;
/* 20px 占位图放大后模糊scale 遮边缘 */
filter: blur(20px) saturate(1.2);
transform: scale(1.1);
transition: opacity 0.4s ease;
}
.blur-img-full {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
object-fit: cover;
/* 重置 .md-content img 的 margin/max-width/height避免把 absolute 图层推偏 */
margin: 0;
max-width: none;
opacity: 0;
z-index: 1;
}
/* full 加载完成后由 JS 直接设 opacity:1不依赖 CSS transition
避免合成层重绘时机导致 opacity 卡在 0。 */
.blur-img-full.is-loaded,
.blur-img.is-loaded .blur-img-full {
opacity: 1;
}
/* 容器标记 loaded 后:显式隐藏占位图 + 去掉灰底,避免重绘时机导致残留/灰边 */
.blur-img.is-loaded .blur-img-placeholder {
opacity: 0;
}
.blur-img.is-loaded {
background: transparent;
}
/* ========== 主题切换图标进入动画 ==========
点击切换主题时 theme.set 立即换 SVG配合 RSX 的 key 强制重挂载),
该动画为新挂载的图标播放一次缩放+淡入,给用户即时反馈。
仅作用于 .theme-toggle 内的 svg不影响页面其它 svg。 */
.theme-toggle svg {
animation: theme-icon-enter 0.3s ease-out;
}
@keyframes theme-icon-enter {
from {
opacity: 0;
transform: scale(0.5) rotate(-60deg);
}
to {
opacity: 1;
transform: scale(1) rotate(0deg);
}
}
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@media screen and (max-width: 768px) {
.post-title {
font-size: 32px;
}
.md-content h1 {
font-size: 32px;
}
.md-content h2 {
font-size: 26px;
}
.md-content h3 {
font-size: 20px;
}
.paginav {
flex-direction: column;
}
.paginav a {
width: 100%;
}
.paginav .next {
margin-inline-start: 0;
text-align: left;
border-top: 1px solid var(--color-paper-border);
}
details.toc .inner {
margin: 0 1rem;
}
/* 旧文章兜底:未重建的文章是裸 table无 .table-wrap 包裹),移动端需 block 化才能滚动。
选择器 .md-content > div > table 精确命中「片段容器直接子代的裸 table」
不会误伤新文章 .table-wrap 内的 table后者多一层 div圆角视觉完整
block 化会损 thead/tbody 圆角,但仅移动端 + 仅旧文章,可接受。 */
.md-content > div > table {
display: block;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
}
@keyframes pageEnter {
from {
opacity: 0;
transform: translateY(6px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.page-enter {
animation: pageEnter 0.15s ease-out;
}
@media (prefers-reduced-motion: reduce) {
html {
scroll-behavior: auto;
}
details::details-content {
transition: none;
}
.page-enter {
animation: none;
}
.theme-toggle svg {
animation: none;
}
}
/* ========== Blur-up 渐进图片加载(已移入 @layer components ========== */
@source "./src/**/*.{rs,html}";
/* ========== CodeMirror 代码运行器高度自适应优化 ========== */
.code-runner-editor {
min-height: 120px;
max-height: 400px;
display: flex;
flex-direction: column;
}
.code-runner-editor .cm-editor {
flex: 1 1 auto !important;
}
.code-runner-editor .cm-scroller {
overflow: auto;
}