mac 风格代码块样式

一个简单的代码块样式,仅在预览模式生效

暗色模式

亮色模式

历史

  • 20260429:复制按钮细节调整
  • 20260430:优化 pdf 导出

代码块 css

/**
 * ============================================================================
 * 2026-04-29 lspzc
 * Obsidian 代码块美化样式
 * ============================================================================
 */

/* ==========================================================================
   全局 CSS 变量定义
   ========================================================================== */
.markdown-preview-view pre {
  /* ---- 布局尺寸变量 ---- */
  --cb-mac-bar-height: 36px;
  /* 顶部装饰条高度 */
  --cb-mac-dot-size: 12px;
  /* Mac 风格圆点直径 */
  --cb-button-height: 24px;
  /* 复制按钮高度 */
  --cb-code-padding: 1em;
  /* 代码内容内边距 */
  --cb-max-height: 400px;
  /* 代码块最大高度 */

  /* ---- 亮色模式颜色变量 ---- */
  --cb-bar-bg: #f5f5f5;
  /* 装饰条背景色 */
  --cb-bar-border: var(--background-modifier-border-hover);
  /* 装饰条底部分割线 */
  --cb-dot-red: #ff5f56;
  /* 关闭按钮 - 红色 */
  --cb-dot-yellow: #ffbd2e;
  /* 最小化按钮 - 黄色 */
  --cb-dot-green: #27c93f;
  /* 最大化按钮 - 绿色 */
  --cb-button-bg-hover: rgba(0, 0, 0, 0.06);
  /* 按钮悬停背景(Material ripple 风格) */
  --cb-button-bg-active: rgba(0, 0, 0, 0.1);
  /* 按钮按下背景 */
  --cb-scrollbar-thumb: var(--scrollbar-thumb-bg);
  /* 滚动条滑块 */
  --cb-scrollbar-track: var(--scrollbar-track-bg);
  /* 滚动条轨道 */

  /* ---- 阴影层级(Material Elevation)---- */
  --cb-shadow-resting: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
  --cb-shadow-hover: 0 4px 6px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.06);
}

/* ==========================================================================
   暗色模式变量覆盖
   ========================================================================== */
.theme-dark .markdown-preview-view pre {
  --cb-bar-bg: #2d2d30;
  /* 暗色装饰条背景 */
  --cb-bar-border: #1e1e22;
  /* 暗色分割线 */
  --cb-button-bg-hover: rgba(255, 255, 255, 0.1);
  /* 暗色按钮悬停背景 */
  --cb-button-bg-active: rgba(255, 255, 255, 0.15);
  /* 暗色按钮按下背景 */
  --cb-shadow-resting: 0 1px 3px rgba(0, 0, 0, 0.3), 0 1px 2px rgba(0, 0, 0, 0.4);
  --cb-shadow-hover: 0 4px 6px rgba(0, 0, 0, 0.25), 0 2px 4px rgba(0, 0, 0, 0.2);
}


/* ==========================================================================
   1. 代码块容器基础样式
   ========================================================================== */

/**
 * 代码块容器
 * - 使用 sticky 定位确保装饰条在滚动时保持固定
 * - 限制最大高度并启用滚动
 * - 应用 Material Design 阴影与圆角
 */
.markdown-preview-view pre {
  /* 定位与布局 */
  position: relative;
  overflow: hidden;
  /* 隐藏溢出,内部代码区域单独滚动 */

  /* 盒模型 */
  border-radius: 8px !important;
  padding: 0 !important;
  /* 内边距由内部 code 元素控制 */
  margin: 1em 0;

  /* 视觉样式 */
  background-color: var(--code-background);
  box-shadow: var(--cb-shadow-resting);
  transition: box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

/* 代码块悬停时提升阴影层级(Material Design Elevation) */
.markdown-preview-view pre:hover {
  box-shadow: var(--cb-shadow-hover);
}


/* ==========================================================================
   2. 代码内容区域样式
   ========================================================================== */

/**
 * 实际代码内容区域
 * - 限制最大高度,超出显示滚动条
 * - 顶部留出装饰条空间
 * - 禁止自动换行,保留原始格式
 */
.markdown-preview-view pre code {
  display: block;
  overflow: auto !important;
  /* 超出时显示滚动条 */
  max-height: var(--cb-max-height);
  /* 限制最大高度 */
  max-width: 100%;

  /* 内边距:顶部为装饰条高度 + 代码内边距 */
  padding: calc(var(--cb-mac-bar-height) + var(--cb-code-padding)) var(--cb-code-padding) var(--cb-code-padding) var(--cb-code-padding) !important;

  /* 文本处理 */
  white-space: pre;
  /* 禁止自动换行,保留原格式 */
  word-wrap: normal;
  /* 禁止单词换行 */
  tab-size: 4;
  /* Tab 字符宽度 */

  /* 字体样式 */
  font-family: var(--font-monospace);
  font-size: 0.9em;
  line-height: 1.6;

  /* 背景透明,由外层 pre 控制 */
  background-color: transparent !important;
}


/* ==========================================================================
   3. 顶部装饰条(Mac 风格标题栏)
   ========================================================================== */

/**
 * 装饰条基础样式
 * - 使用 sticky 定位确保在代码区域横向/纵向滚动时保持固定在顶部
 * - 覆盖整个代码块宽度
 */
.markdown-preview-view pre::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: var(--cb-mac-bar-height);

  /* 布局 */
  display: flex;
  align-items: center;
  justify-content: flex-start;
  padding-left: 16px;
  /* 圆点左侧间距 */

  /* 视觉样式 */
  background-color: var(--cb-bar-bg);
  border-bottom: 1px solid var(--cb-bar-border);
  border-radius: 8px 8px 0 0;
  /* 顶部圆角与容器一致 */

  /* 层级 */
  z-index: 10;

  /* 禁止选中 */
  pointer-events: none;
  user-select: none;
}

/**
 * Mac 风格三色圆点
 * - 使用单个伪元素配合 box-shadow 绘制三个圆点
 * - 位置固定在装饰条左侧
 */
.markdown-preview-view pre::after {
  content: "";
  position: absolute;
  top: calc((var(--cb-mac-bar-height) - var(--cb-mac-dot-size)) / 2);
  left: 16px;

  /* 圆点尺寸 */
  width: var(--cb-mac-dot-size);
  height: var(--cb-mac-dot-size);
  border-radius: 50%;

  /* 三个圆点:红色(关闭)+ 黄色(最小化)+ 绿色(最大化) */
  background: var(--cb-dot-red);
  box-shadow:
    20px 0 0 var(--cb-dot-yellow),
    40px 0 0 var(--cb-dot-green);

  /* 层级高于装饰条 */
  z-index: 11;

  /* 禁止选中 */
  pointer-events: none;
  user-select: none;

  /* 悬停时的过渡效果(仅视觉) */
  transition: transform 0.2s ease;
}


/* ==========================================================================
   4. 复制按钮样式
   ========================================================================== */

/**
 * 复制按钮基础样式
 * - 始终显示(opacity: 1),不依赖光标悬停
 * - 位于装饰条右侧
 * - 保留 Obsidian 原生图标和点击反馈
 */
.markdown-preview-view .copy-code-button {
  /* 定位:固定在装饰条右侧垂直居中 */
  position: absolute;
  top: 0 !important;
  right: 10px !important;

  /* 盒模型 */
  width: auto;
  height: var(--cb-mac-bar-height) !important;
  padding: 0 8px !important;
  margin: 0 !important;

  /* 布局 */
  display: inline-flex !important;
  align-items: center;
  justify-content: center;

  /* 视觉样式 */
  color: var(--text-muted) !important;
  background-color: transparent !important;
  border: none !important;
  border-radius: 4px !important;
  cursor: pointer;

  /* 始终显示 */
  opacity: 1 !important;
  visibility: visible !important;

  /* 层级高于装饰条 */
  z-index: 12;

  /* 过渡动画 */
  transition:
    background-color 0.2s cubic-bezier(0.4, 0, 0.2, 1),
    color 0.2s cubic-bezier(0.4, 0, 0.2, 1),
    transform 0.15s ease,
    box-shadow 0.2s ease;
}

/**
 * 复制按钮悬停效果
 */
.markdown-preview-view .copy-code-button:hover {
  background-color: var(--cb-button-bg-hover) !important;
  color: var(--text-normal) !important;
  transform: scale(1.05);
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

/**
 * 复制按钮点击反馈(按下状态)
 */
.markdown-preview-view .copy-code-button:active {
  background-color: var(--cb-button-bg-active) !important;
  transform: scale(0.95);
  box-shadow: none;
}


/* ==========================================================================
   5. 自定义滚动条样式
   ========================================================================== */

/**
 * Firefox 滚动条样式
 * - 使用 scrollbar-width 和 scrollbar-color
 */
.markdown-preview-view pre code {
  scrollbar-width: thin;
  scrollbar-color: var(--cb-scrollbar-thumb) var(--cb-scrollbar-track);
}

/**
 * WebKit 浏览器滚动条样式(Chrome, Edge, Safari)
 * - 统一的滚动条尺寸与圆角
 * - 滑块与轨道颜色使用主题变量
 */
.markdown-preview-view pre code::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}

/* 滚动条滑块 */
.markdown-preview-view pre code::-webkit-scrollbar-thumb {
  background: var(--cb-scrollbar-thumb);
  border-radius: 4px;
  border: 2px solid var(--cb-scrollbar-track);
}

/* 滚动条滑块悬停 */
.markdown-preview-view pre code::-webkit-scrollbar-thumb:hover {
  background: var(--text-muted);
}

/* 滚动条轨道 */
.markdown-preview-view pre code::-webkit-scrollbar-track {
  background: var(--cb-scrollbar-track);
  border-radius: 4px;
}

/* 滚动条角落 */
.markdown-preview-view pre code::-webkit-scrollbar-corner {
  background: var(--cb-scrollbar-track);
}


/* ==========================================================================
   6. 阅读模式兼容(markdown-rendered)
   ========================================================================== */

/**
 * 同时支持 .markdown-rendered 类名的阅读模式
 * 保持与 .markdown-preview-view 一致的样式
 */
.markdown-rendered pre {
  /* 继承上述所有变量与样式 */
  --cb-mac-bar-height: 36px;
  --cb-mac-dot-size: 12px;
  --cb-button-height: 24px;
  --cb-code-padding: 1em;
  --cb-max-height: 400px;
  --cb-bar-bg: #f5f5f5;
  --cb-bar-border: var(--background-modifier-border-hover);
  --cb-dot-red: #ff5f56;
  --cb-dot-yellow: #ffbd2e;
  --cb-dot-green: #27c93f;
  --cb-button-bg-hover: rgba(0, 0, 0, 0.06);
  --cb-button-bg-active: rgba(0, 0, 0, 0.1);
  --cb-scrollbar-thumb: var(--scrollbar-thumb-bg);
  --cb-scrollbar-track: var(--scrollbar-track-bg);
  --cb-shadow-resting: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
  --cb-shadow-hover: 0 4px 6px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.06);

  position: relative;
  overflow: hidden;
  border-radius: 8px !important;
  padding: 0 !important;
  margin: 1em 0;
  background-color: var(--code-background);
  box-shadow: var(--cb-shadow-resting);
  transition: box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

.markdown-rendered pre:hover {
  box-shadow: var(--cb-shadow-hover);
}

.markdown-rendered pre code {
  display: block;
  overflow: auto !important;
  max-height: var(--cb-max-height);
  max-width: 100%;
  padding: calc(var(--cb-mac-bar-height) + var(--cb-code-padding)) var(--cb-code-padding) var(--cb-code-padding) var(--cb-code-padding) !important;
  white-space: pre;
  word-wrap: normal;
  tab-size: 4;
  font-family: var(--font-monospace);
  font-size: 0.9em;
  line-height: 1.6;
  background-color: transparent !important;
}

/* 阅读模式装饰条 */
.markdown-rendered pre::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: var(--cb-mac-bar-height);
  display: flex;
  align-items: center;
  justify-content: flex-start;
  padding-left: 16px;
  background-color: var(--cb-bar-bg);
  border-bottom: 1px solid var(--cb-bar-border);
  border-radius: 8px 8px 0 0;
  z-index: 10;
  pointer-events: none;
  user-select: none;
}

/* 阅读模式三色圆点 */
.markdown-rendered pre::after {
  content: "";
  position: absolute;
  top: calc((var(--cb-mac-bar-height) - var(--cb-mac-dot-size)) / 2);
  left: 16px;
  width: var(--cb-mac-dot-size);
  height: var(--cb-mac-dot-size);
  border-radius: 50%;
  background: var(--cb-dot-red);
  box-shadow:
    20px 0 0 var(--cb-dot-yellow),
    40px 0 0 var(--cb-dot-green);
  z-index: 11;
  pointer-events: none;
  user-select: none;
  transition: transform 0.2s ease;
}

/* 阅读模式复制按钮 */
.markdown-rendered .copy-code-button {
  position: absolute;
  top: 0 !important;
  right: 10px !important;
  width: auto;
  height: var(--cb-mac-bar-height) !important;
  padding: 0 8px !important;
  margin: 0 !important;
  display: inline-flex !important;
  align-items: center;
  justify-content: center;
  color: var(--text-muted) !important;
  background-color: transparent !important;
  border: none !important;
  border-radius: 4px !important;
  cursor: pointer;
  opacity: 1 !important;
  visibility: visible !important;
  z-index: 12;
  transition:
    background-color 0.2s cubic-bezier(0.4, 0, 0.2, 1),
    color 0.2s cubic-bezier(0.4, 0, 0.2, 1),
    transform 0.15s ease,
    box-shadow 0.2s ease;
}

.markdown-rendered .copy-code-button:hover {
  background-color: var(--cb-button-bg-hover) !important;
  color: var(--text-normal) !important;
  transform: scale(1.05);
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}

.markdown-rendered .copy-code-button:active {
  background-color: var(--cb-button-bg-active) !important;
  transform: scale(0.95);
  box-shadow: none;
}

/* 阅读模式滚动条 */
.markdown-rendered pre code {
  scrollbar-width: thin;
  scrollbar-color: var(--cb-scrollbar-thumb) var(--cb-scrollbar-track);
}

.markdown-rendered pre code::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}

.markdown-rendered pre code::-webkit-scrollbar-thumb {
  background: var(--cb-scrollbar-thumb);
  border-radius: 4px;
  border: 2px solid var(--cb-scrollbar-track);
}

.markdown-rendered pre code::-webkit-scrollbar-thumb:hover {
  background: var(--text-muted);
}

.markdown-rendered pre code::-webkit-scrollbar-track {
  background: var(--cb-scrollbar-track);
  border-radius: 4px;
}

.markdown-rendered pre code::-webkit-scrollbar-corner {
  background: var(--cb-scrollbar-track);
}

/* 阅读模式暗色主题 */
.theme-dark .markdown-rendered pre {
  --cb-bar-bg: #2d2d30;
  --cb-bar-border: #1e1e22;
  --cb-button-bg-hover: rgba(255, 255, 255, 0.1);
  --cb-button-bg-active: rgba(255, 255, 255, 0.15);
  --cb-shadow-resting: 0 1px 3px rgba(0, 0, 0, 0.3), 0 1px 2px rgba(0, 0, 0, 0.4);
  --cb-shadow-hover: 0 4px 6px rgba(0, 0, 0, 0.25), 0 2px 4px rgba(0, 0, 0, 0.2);
}


/* ==========================================================================
   7. 响应式与无障碍优化
   ========================================================================== */

/**
 * 减少动画偏好(无障碍)
 * 当用户系统设置偏好减少动画时,禁用过渡效果
 */
@media (prefers-reduced-motion: reduce) {

  .markdown-preview-view pre,
  .markdown-preview-view pre::after,
  .markdown-preview-view .copy-code-button,
  .markdown-rendered pre,
  .markdown-rendered pre::after,
  .markdown-rendered .copy-code-button {
    transition: none !important;
  }

  .markdown-preview-view .copy-code-button:hover,
  .markdown-rendered .copy-code-button:hover {
    transform: none !important;
  }
}

pdf 导出 css

/**
 * ============================================================================
 * 2026-04-30 lspzc
 * Obsidian pdf 导出样式
 * ============================================================================
 */

/**
 * PDF 导出代码块优化
 * 导出时移除高度限制,确保所有代码内容可见
 */
@media print {

    /* 移除代码块最大高度限制 */
    .markdown-preview-view pre code,
    .markdown-rendered pre code {
        max-height: none !important;
        overflow: visible !important;
    }

    /* 隐藏复制按钮 */
    .markdown-preview-view .copy-code-button,
    .markdown-rendered .copy-code-button {
        display: none !important;
    }

    /* 隐藏滚动条 */
    .markdown-preview-view pre code::-webkit-scrollbar,
    .markdown-rendered pre code::-webkit-scrollbar {
        display: none !important;
    }
}
1 个赞

效果很好。
另外有个问题,导出pdf的时候,代码块是不展开的,有没有办法处理?

确实是个问题,我看看怎么解决

好了,再试试这次效果

OK辣,老铁666 :+1: