一直显示?点击任意区域即可关闭
个性化配置

VitePress 代码框 CSS 魔改记录

本文档详细记录了在 feat/update-code-blocks 分支中对博客文章代码框进行 CSS 魔改的详细细节。

1. 涉及文件与位置

  • 修改文件:[.vitepress/theme/style/post.scss](file:///opt/1panel/www/sites/blog.chgr.cc/index/.vitepress/theme/style/post.scss)
  • 影响范围:文章页内所有带语言标记的代码块组件(div[class*="language-"]

2. 修改前后的 CSS Diff 对比

diff
diff --git a/.vitepress/theme/style/post.scss b/.vitepress/theme/style/post.scss
index 16f15ca..555f4bd 100644
--- a/.vitepress/theme/style/post.scss
+++ b/.vitepress/theme/style/post.scss
@@ -251,23 +251,30 @@
   div {
     &[class*="language-"] {
       position: relative;
-      display: flex;
-      flex-direction: row-reverse;
+      display: grid;
+      grid-template-columns: auto 1fr;
+      grid-template-rows: 36px 1fr;
+      grid-template-areas:
+        "header header"
+        "ln code";
       border-radius: 12px;
       background-color: var(--main-card-background);
       border: 1px solid var(--main-card-border);
-      padding-top: 36px;
       margin: 1rem 0;
-      overflow: hidden;
+      overflow: auto;
+      max-height: 450px;
+      width: 100%;
       .copy,
       .lang {
-        position: absolute;
+        grid-area: header;
       }
       .lang {
-        width: 100%;
-        height: 36px;
+        position: sticky;
         top: 0;
         left: 0;
+        z-index: 3;
+        width: 100%;
+        height: 36px;
         display: flex;
         flex-direction: row;
         align-items: center;
@@ -278,8 +285,10 @@
         font-size: 18px;
       }
       .copy {
+        position: sticky;
         top: 0;
         right: 0;
+        z-index: 4;
         width: 36px;
         height: 36px;
         display: flex;
@@ -290,9;9 +299,9 @@
         font-family: "iconfont";
         font-size: 20px;
         font-style: normal;
-        z-index: 1;
         color: var(--main-font-color);
         cursor: pointer;
+        margin-left: auto;
         &::after {
           content: "\e01c";
           transition: color 0.3s;
@@ -324,12;17 @@
         }
       }
       .line-numbers-wrapper {
+        grid-area: ln;
+        position: sticky;
+        left: 0;
+        z-index: 2;
         padding: 6px 10px;
         opacity: 0.6;
         text-align: center;
         user-select: none;
         color: var(--main-font-second-color);
         background-color: var(--main-card-second-background);
+        border-right: 1px solid var(--main-card-border);
         .line-number {
           display: flex;
           align-items: center;
@@ -342,12;13 @@
         }
       }
       pre {
+        grid-area: code;
         margin: 0;
         padding: 6px 10px;
         width: 100%;
-        overflow-y: auto;
+        overflow: visible;
         user-select: text;
-        border-left: 1px solid var(--main-card-border);
+        border-left: none;
         code {
           font-family: "Fira Code", var(--main-font-family), monospace;
           font-optical-sizing: auto;

3. 核心改进原理解析

3.1 容器网格化布局(CSS Grid)

将代码框的容器由 flex 弹性布局升级为 grid 网格布局。显式划分了以下三个区域:

  1. header(首行 36px 高):放置代码块语言标签(.lang)和复制按钮(.copy)。
  2. ln(行号区):左侧根据行号字宽自动占位。
  3. code(代码正文区):右侧自适应宽度。

3.2 粘性滑动定位(CSS Sticky)

通过 position: sticky 实现内容在滚动时的智能悬浮:

  • 首行 Header / 语言和复制按钮:在代码垂直滚动时,依然固定锁定在代码框顶部(top: 0),并利用 z-index 确保在代码图层之上。
  • 左侧行号(.line-numbers-wrapper:在代码水平宽幅滚动时,始终粘性固定在代码框左侧(left: 0),不会随着代码的向右横移而滑出视野,提供了极佳的阅读辅助定位。

3.3 消除嵌套滚动条(Pre Overflow)

  • 修改前:容器 overflow: hidden,而 pre 内核层定义了 overflow-y: auto。在大代码块下,会造成容器与 pre 双重滚动嵌套,影响滚动反馈与页面手势。
  • 修改后:将 pre 的溢出限制设为 overflow: visible,高度自适应,而将最外层代码容器 div[class*="language-"] 的限制设为 max-height: 450px 以及 overflow: auto。所有的横向、纵向滚动全部收归外层容器统一打理,杜绝了嵌套滚动条,使页面滚动流畅自然。