Hugo Stack主题代码块美化

为了让代码块更美观加上整理这篇文又熬夜了两天

本文基于Hugo版本0.150.0,Stack版本3.31.0,部分代码使用AI完成

预览图

12

代码字体修改

使用了Fira Code字体(链接

 1<style>
 2    @font-face {
 3        font-family: 'mkty';
 4        src: url({{ (resources.Get "font/mkty.ttf").Permalink }}) format('truetype');
 5    }
 6
 7    @font-face {
 8        font-family: 'Fira Code';
 9        src: 
10            url('/font/fira-code/FiraCode-Light.woff2') format('woff2'),
11            url('/font/fira-code/FiraCode-Light.woff') format('woff');
12    }
13
14    :root {
15        --base-font-family: 'mkty';
16        --code-font-family: 'Fira Code', 'mkty';
17    }
18</style>

其中mkty是我的主字体,我希望代码块里面的中文字体保持这个字体,于是:root{--code-font-family: 'Fira Code', 'mkty';}
Fira Code这个字体包下载完了有很多字体文件,网页用.woff.woff2就够了,根据你喜欢的字重挑选相应的文件放到项目根目录\assets\font\下面即可

同时修改了样式:

 1// 代码块字体样式
 2code,
 3pre,
 4.highlight {
 5    font-weight: 300 !important;
 6    // font-size: 1.6rem;
 7}
 8//行内代码
 9.article-content code {
10    border: none;
11    border-radius: 4px ;
12    font-size: 0.85em ;
13}

代码块折叠展开

参考莱特雷的博客
我用了stack主题目录里自带的assets\icons\top.svg,复制了一张改了方向作为图标
主要在原代码基础上添加了折叠功能并修改了样式,java部分deepseek写的,目前电脑和平板上运行没发现问题,不保证不出问题

  1<style>
  2    .highlight {
  3        /* 你可以根据需要调整这个高度 */
  4        max-height: 400px;
  5        overflow: hidden;
  6    }
  7
  8    .code-show {
  9        max-height: none !important;
 10    }
 11
 12    .code-more-box {
 13        width: 100%;
 14        padding-top: 78px;
 15        background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(255, 255, 255, 0)), to(var(--card-background)));
 16        position: absolute;
 17        left: 0;
 18        right: 0;
 19        bottom: 0;
 20        z-index: 1;
 21    }
 22
 23    .code-more-btn, .code-less-btn {
 24        display: block;
 25        margin: auto;
 26        width: 100%;
 27        height: 78px;
 28        background: none;
 29    }
 30
 31    .code-less-btn {
 32        position: absolute;
 33        bottom: 0px;
 34        left: 0px;
 35    }
 36
 37    .code-more-img, .code-less-img{
 38        display: block;
 39        margin: auto;
 40        padding-right: 1rem;
 41        width: 60px;
 42        position: absolute;
 43        right: 2.5rem;
 44        bottom: 30px;
 45    }
 46
 47    .code-less-img {
 48        bottom: 25px !important;
 49    }
 50</style>
 51
 52<!-- deepseek:代码折叠展开 -->
 53<script>
 54  function initCodeMoreBox() {
 55    // 新增代码开始
 56    // 检测是否为移动端
 57    const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
 58
 59    if (isMobile) {
 60        // 移动端直接移除所有高度限制
 61        document.querySelectorAll('.highlight').forEach(block => {
 62            block.style.maxHeight = 'none';
 63            block.style.overflow = 'auto';
 64        });
 65        return;
 66    }
 67    // 新增代码结束
 68
 69    let codeBlocks = document.querySelectorAll(".highlight");
 70    if (!codeBlocks || codeBlocks.length === 0) {
 71        return;
 72    }
 73    
 74    codeBlocks.forEach(codeBlock => {
 75        // 校验是否overflow
 76        if (codeBlock.scrollHeight <= codeBlock.clientHeight) {
 77            return;
 78        }
 79      
 80        // 保存初始位置
 81        const originalPosition = codeBlock.getBoundingClientRect().top + window.pageYOffset;
 82      
 83        // 创建 code-more-box
 84        let codeMoreBox = document.createElement('div');
 85        codeMoreBox.classList.add('code-more-box');
 86        
 87        // 创建 code-more-btn
 88        let codeMoreBtn = document.createElement('span');
 89        codeMoreBtn.classList.add('code-more-btn');
 90      
 91        // 创建 code-more-img
 92        let moreImg = document.createElement('img');
 93        moreImg.classList.add('code-more-img');
 94        moreImg.src = {{ (resources.Get "icons/bottom.svg").Permalink }};
 95        
 96        // 组装更多按钮
 97        codeMoreBtn.appendChild(moreImg);
 98        codeMoreBox.appendChild(codeMoreBtn);
 99        codeBlock.appendChild(codeMoreBox);
100      
101        // 点击更多按钮事件
102        codeMoreBox.addEventListener('click', function() {
103            // 隐藏更多按钮
104            codeMoreBox.style.display = 'none';
105            
106            // 展开代码块
107            codeBlock.classList.add('code-show');
108            
109            // 创建折叠按钮
110            let codeLessBox = document.createElement('div');
111            codeLessBox.classList.add('code-less-box');
112            
113            let codeLessBtn = document.createElement('span');
114            codeLessBtn.classList.add('code-less-btn');
115            
116            let lessImg = document.createElement('img');
117            lessImg.classList.add('code-less-img');
118            lessImg.src = {{ (resources.Get "icons/top-pre.svg").Permalink }};
119            
120            // 组装折叠按钮
121            codeLessBtn.appendChild(lessImg);
122            codeLessBox.appendChild(codeLessBtn);
123            codeBlock.appendChild(codeLessBox);
124            
125            // 点击折叠按钮事件
126            codeLessBox.addEventListener('click', function() {
127                // 移除折叠按钮
128                codeLessBox.remove();
129                
130                // 隐藏展开状态
131                codeBlock.classList.remove('code-show');
132                
133                // 显示更多按钮
134                codeMoreBox.style.display = 'block';
135                
136                // 只在初始位置不在视口内时才滚动
137                scrollToInitialPositionIfNeeded(originalPosition, codeBlock);
138                
139                // 触发resize事件
140                window.dispatchEvent(new Event('resize'));
141            });
142            
143            // 触发resize事件
144            window.dispatchEvent(new Event('resize'));
145        });
146    });
147}
148
149    function scrollToInitialPositionIfNeeded(originalPosition, codeBlock) {
150        // 获取当前视口信息
151        const viewportHeight = window.innerHeight;
152        const currentScroll = window.pageYOffset;
153        
154        // 计算初始位置是否在视口内
155        const isOriginalPositionInViewport = 
156        originalPosition >= currentScroll && 
157        originalPosition <= currentScroll + viewportHeight;
158        
159        // 计算代码块当前是否在视口内
160        const codeBlockRect = codeBlock.getBoundingClientRect();
161        const isCodeBlockInViewport = 
162        codeBlockRect.top >= 0 && 
163        codeBlockRect.top <= viewportHeight;
164        
165        // 只有当初始位置不在视口内,且代码块也不在视口内时才滚动
166        if (!isOriginalPositionInViewport && !isCodeBlockInViewport) {
167            const header = document.querySelector('header');
168            let headerOffset = 0;
169      
170        if (header) {
171            const headerHeight = window.getComputedStyle(header).getPropertyValue('height');
172            headerOffset = parseInt(headerHeight.replace('px', '')) || 0;
173        }
174      
175        // 计算最终滚动位置(考虑header高度和一点边距)
176        const targetPosition = originalPosition - headerOffset - 20;
177      
178        window.scrollTo({
179            top: targetPosition,
180            behavior: 'smooth'
181        });
182      
183        console.log('触发滚动:初始位置不在视口内');
184        } else {
185        console.log('不触发滚动:初始位置或代码块在视口内');
186        }
187    }
188  
189    // 初始化
190    document.addEventListener('DOMContentLoaded', function() {
191        initCodeMoreBox();
192    });
193</script>

用上述代码手机端会有不显示折叠展开功能相关按钮和样式的问题,用了比较极端的方法解决,即限制手机端禁用这个功能,改用限制代码块高度+滑动查看

 1/* 移动端禁用折叠,启用滚动并限制高度 */
 2@media (max-width: 768px) {
 3    .highlight {
 4        overflow: auto !important;
 5        pre {
 6            max-height: 17em !important;
 7            &::-webkit-scrollbar {
 8                display: flex;
 9            }
10        }
11    }
12
13    .code-more-box,
14    .code-less-box {
15        display: none !important;
16    }
17}

此外如果自定义了鼠标光标样式,也要记得改,
我自定义鼠标光标样式的代码抄的莱特雷
由于添加的img属于.article-content这个类,要记得排除

 1// 【Stack主题鼠标样式写法】
 2// default光标图片
 3body,
 4html,
 5.article-content img:not(.code-less-img):not(.code-more-img),  // 这里
 6.waline-container,
 7.wl-header label {
 8    cursor: url(../mouse/default.png),
 9        auto !important;
10}
11
12// pointer光标图片
13a:hover,
14button:hover,
15.copyCodeButton:hover,
16#dark-mode-toggle,
17.wl-actions label,
18.wl-actions a,
19.wl-emoji-popup .wl-tab-wrapper button,
20.wl-gif-popup img,
21.wl-sort li,
22.code-more-img,  // 这里
23.code-less-img { // 这里
24    cursor: url(../mouse/pointer.png),
25        auto !important;
26}

代码块显示标题

参考loyayz:Hugo 代码块显示标题
用ai改了一下,少创建一个类,自己写了css

 1{{- $lang := .Type | default "text" }}
 2{{- $title := .Attributes.title | default "" -}}
 3
 4{{- if $title }}
 5<div class="highlight-with-title" data-title="{{ $title }}">
 6    {{- end }}
 7
 8    {{ highlight .Inner $lang .Options }}
 9
10    {{- if $title }}
11</div>
12{{- end }}
 1// 代码块标题样式
 2.highlight-with-title {
 3    position: relative;
 4    margin: 1rem 0;
 5    border-radius: 20px;
 6    overflow: hidden;
 7}
 8.highlight-with-title .highlight {
 9    padding-top: 4rem;
10}
11.highlight-with-title .copyCodeButton {
12    top: calc(var(--card-padding) + 1.5rem);
13}
14.highlight-with-title::before {
15    content: attr(data-title);
16    position: absolute;
17    left: 0;
18    right: 0;
19    color: var(--accent-color-text);
20    opacity: 0.5;
21    padding: 0 calc(2.5rem + 3em);
22    background-color: var(--accent-color);
23    font-size: 0.7em;
24    font-family: 'Fira code', 'mkty';
25    z-index: 1;
26}
1```语法名 {title="标题内容"}
2# code here

其他样式更改

参照莱特雷的样式改了代码块圆角

1// 代码块基础样式修改
2.highlight {
3    max-width: 100% !important;
4    border-radius: 20px;
5    margin: 0 !important;
6    &:hover {
7        box-shadow: var(--shadow-l1) !important;
8    }
9}

禁用了滚动条

 1.article-content {
 2    .highlight {
 3        pre {
 4            scrollbar-width: none;
 5            /* Firefox */
 6            &::-webkit-scrollbar {
 7                display: none;
 8                /* Chrome Safari */
 9            }
10        }
11    }
12}

复制按钮圆角

1// 代码块复制按钮
2.article-content .copyCodeButton {
3    border-radius: 4px;
4}

一些代码块相关注意事项

行号不跟代码一起滚动的问题

做代码块折叠的话用不到,但如果希望限制代码块高度滚动查看代码的话,要想让行号跟着代码块一起滚动,记得改项目根目录\hugo.yaml(也可能是config.yaml 我记不清- -

1markup:
2    highlight:
3        noClasses: false
4        codeFences: true
5        guessSyntax: true
6        lineNoStart: 1
7        lineNos: true
8        lineNumbersInTable: false
9        tabWidth: 4

代码缩进长度不一致的问题

写博客的时候如果发现代码块里面缩进长度不一致的问题,可能是用了制表符Tab缩进导致的,解决办法:

  1. 在VS Code里把缩进改成使用空格缩进,把默认tab长度改成和yaml文件里面写的tabWidth一致,我写的是4所以VS Code里我也改成4。这样改了之后按tab直接等于4个空格
1VS Code里按 Ctrl+, 打开设置
2搜索 "editor.insert spaces"
3勾选 "Editor: Insert Spaces"
4搜索 "editor.detect indentation"
5勾选 "Editor: Detect Indentation"(自动检测)
6或者设置 "Editor: Tab Size" 为 4
7搜索 "editor.format on paste"
8勾选 "Editor: Format On Paste"
  1. 有时候遇到从别的文件粘贴过来的代码,粘贴到.md文件里还保留了制表符,需要全选并按Ctrl + KCtrl + F,可以把里面的制表符格式化成4个空格
  2. 注意你的.md文件里面所有缩进都得是4个空格(或者是你设置的其他数字)才能保持缩进长度一致,如果还是发现有不一致的问题就手动改一下

参考资料

  1. 莱特雷:【Hugo】Stack主题自定义修改
  2. loyayz:Hugo 代码块显示标题
本博客已稳定运行
发表了7篇文章 · 总计25.93k字
使用 Hugo 构建
主题 StackJimmy 设计