改造自己的主题
1 什么时候需要定制
考虑以下几种场景
- markdown 已经不能满足我了,我要用上更多的页面特效,比如嵌入在线视频、嵌入特定网站卡片等
- 博客主题不支持一些外部服务,比如说新的评论系统、搜索系统,但是主题作者那边不更新,咋办
- 博客主题在一些场景的使用下会有错误,但是主题作者那边迟迟不给修复,咋办
要实现这些效果,就涉及到代码层面上的调整了。虽然会耗费一些时间,但相信只要能打造出自己心仪的博客效果,这点成本不算什么的。
2 使用 shortcodes
hugo 是无法直接在博客中添加 HTML 代码的,我测试过,发现经过渲染后这些内容都会消失。取而代之的,hugo 提供了一种名为shortcodes 的功能,简单来说就是自己定义的 HTML 片段,并可在博客文章中选择性地插入这个片段。
hugo 官方已经内置了一些 shortcodes,比如嵌入 YouTube 视频、嵌入 tweet 等。当然了,DoIt 主题也提供了很多的 shortcodes,比如嵌入哔哩哔哩视频、横幅特效、ECharts 图、音乐播放器等。
那如果希望添加更多的功能,或是对内置的 shortcodes 效果不满意呢,根据 hugo 的说法,是可以自定义的。简单来说,主题shortcodes 相关的文件路径为 themes\DoIt\layouts\shortcodes
,用户的路径应该为 layouts\shortcodes
,添加同名文件就能覆盖主题提供的,不同名文件则算作用户新增的。hugo 官方文档也提到,如果要保证不重名,可以再加上一层路径,例如 layouts\shortcodes\custom
,之后在引用 shortcodes 也注意加上 custom\
即可。
就拿我博客中的友链来说吧,其实这个就是自定义了一个相关的 shortcodes,并在一篇博客中引用了这个片段而已,这个还得多感谢雨临Lewis博客中提供的代码。先在 custom 路径下添加 friend.html 文件,内容如下
{{ if .IsNamedParams }}
{{ $defaultImg := "https://sdn.geekzu.org/avatar/d41d8cd98f00b204e9800998ecf8427e?d=retro" }}
<a target="_blank" href={{ .Get "url" }} title={{ .Get "name" }}---{{ .Get "word" }} class="friend url">
<div class="friend block whole {{ .Get " primary-color" | default "default"}} {{ .Get "border-animation" | default "shadow"}}">
<div class="friend block left">
<img class="friend logo {{ .Get " img-animation" | default "rotate"}}" src={{ .Get "logo" }} onerror="this.src='{{ $defaultImg }}'" />
</div>
<div class="friend block right">
<div class="friend name">{{ .Get "name" }}</div>
<div class="friend info">"{{ .Get "word" }}"</div>
</div>
</div>
</a>
{{ end }}
然后需要添加样式代码,建立文件 assets/css/_custom.scss
,然后往其中加入 scss 代码,如下
.friend.url {
text-decoration: none !important;
color: black;
}
.friend.logo {
width: 56px !important;
height: 56px !important;
border-radius: 50%;
border: 1px solid #ddd;
padding: 2px;
margin-top: 14px !important;
margin-left: 14px !important;
background-color: #fff;
}
.friend.block.whole {
height: 92px;
margin-top: 8px;
margin-left: 4px;
width: 31%;
display: inline-flex !important;
border-radius: 5px;
background: rgba(14, 220, 220, 0.15);
&.shadow {
margin-right: 4px;
box-shadow: 4px 4px 2px 1px rgba(0, 0, 255, 0.2);
}
&.borderFlash {
border-width: 3.5px;
border-style: solid;
animation: borderFlash 2s infinite alternate;
}
&.led {
animation: led 3s infinite alternate;
}
&.bln {
animation: bln 3s infinite alternate;
}
}
.friend.block.whole {
&:hover {
color: white;
& .friend.info {
color: white;
}
}
&.default {
--primary-color: #215bb3bf;
&:hover {
background: rgba(33, 91, 179, 0.75);
}
}
&.red {
--primary-color: #e72638;
&:hover {
background: rgba(231, 38, 56, 0.75);
}
}
&.green {
--primary-color: #2ec58d;
&:hover {
background: rgba(21, 167, 33, 0.75);
}
}
&.blue {
--primary-color: #2575fc;
&:hover {
background: rgba(37, 117, 252, 0.75);
}
}
&.linear-red {
--primary-color: #e72638;
&:hover {
background: linear-gradient(to right, #f9cdcd 0, #e72638 35%);
}
}
&.linear-green {
--primary-color: #2ec58d;
&:hover {
background: linear-gradient(to right, #1d7544 0, #2ec58d 35%);
}
}
&.linear-blue {
--primary-color: #2575fc;
&:hover {
background: linear-gradient(to right, #6a11cb 0, #2575fc 35%);
}
}
}
.friend.block.whole .friend.block.left img {
&.auto_rotate_left {
animation: auto_rotate_left 3s linear infinite;
}
&.auto_rotate_right {
animation: auto_rotate_right 3s linear infinite;
}
}
.friend.block.whole:hover .friend.block.left img {
&.rotate {
transition: 0.9s !important;
-webkit-transition: 0.9s !important;
-moz-transition: 0.9s !important;
-o-transition: 0.9s !important;
-ms-transition: 0.9s !important;
transform: rotate(360deg) !important;
-webkit-transform: rotate(360deg) !important;
-moz-transform: rotate(360deg) !important;
-o-transform: rotate(360deg) !important;
-ms-transform: rotate(360deg) !important;
}
}
.friend.block.left {
width: 92px;
min-width: 92px;
float: left;
}
.friend.block.left {
margin-right: 2px;
}
.friend.block.right {
margin-top: 18px;
margin-right: 18px;
}
.friend.name {
overflow: hidden;
font-weight: bolder;
word-wrap:break-word;
word-break: break-all;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
}
.friend.info {
margin-top: 3px;
overflow: hidden;
word-wrap:break-word;
word-break: break-all;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
line-height: normal;
font-size: 0.8rem;
color: #7a7a7a;
}
@media screen and (max-width: 900px) {
.friend.info {
display: none;
}
.friend.block.whole {
width: 45%;
}
.friend.block.left {
width: 84px;
margin-left: 15px;
}
.friend.block.right {
height: 100%;
margin: auto;
display: flex;
align-items: center;
justify-content: center;
}
.friend.name {
font-size: 14px;
}
}
@keyframes bln {
0% {
box-shadow: 0 0 5px grey,inset 0 0 5px grey,0 1px 0 grey;
box-shadow: 0 0 5px var(--primary-color,grey),inset 0 0 5px var(--primary-color,grey),0 1px 0 var(--primary-color,grey)
}
to {
box-shadow: 0 0 16px grey,inset 0 0 8px grey,0 1px 0 grey;
box-shadow: 0 0 16px var(--primary-color,grey),inset 0 0 8px var(--primary-color,grey),0 1px 0 var(--primary-color,grey)
}
}
@keyframes led {
0% {
box-shadow: 0 0 4px #ca00ff
}
25% {
box-shadow: 0 0 16px #00b5e5
}
50% {
box-shadow: 0 0 4px #00f
}
75% {
box-shadow: 0 0 16px #b1da21
}
to {
box-shadow: 0 0 4px red
}
}
@keyframes borderFlash {
0% {
border-color: white;
}
to {
border-color: grey;
border-color: var(--primary-color,grey)
}
}
@keyframes auto_rotate_left {
0% {
transform: rotate(0)
}
to {
transform: rotate(-1turn)
}
}
@keyframes auto_rotate_right {
0% {
transform: rotate(0)
}
to {
transform: rotate(1turn)
}
}
使用时,只需要在博客文章中加入下列内容,如图所示
3 引入自定义的前端代码
上面只是在特定文章中选择性地添加某些页面效果,如果希望让所有页面都有某种效果呢?比如在底部添加一个即时计算网站运行时间的文本,这个效果 DoIt 主题是不支持的。
要实现这类效果的话,就需要引入自定义的前端代码。这里先补充下 hugo 覆盖主题文件的做法吧,稍后要用到。要明确的是,主题代码路径位于 themes\DoIt\
下,想覆盖主题代码,就得在博客根目录下新建同样的路径,并把主题代码文件复制过来,然后在这个新文件上进行修改。这样最后博客运行时,加载的会是自己修改过的主题代码。举个例子,主题菜单栏的代码文件路径是 themes/DoIt/layouts/partials/header.html
,那么要新建的文件路径应该为 layouts/partials/header.html
对于网站页面样式代码 CSS,这个 DoIt 主题已经提供了一种引入方式了,即在根路径下建立文件,路径为 assets/css/_custom.scss
,然后往里面写入代码即可。至于 JavaScript 代码和 HTML 代码,我这边暂时没找到官方提供的修改入口。
再次感谢雨临Lewis博客提供的思路,我终于明白了该如何引入各种前端代码。先说下思路吧,打开网页源代码检索<script type="text/javascript"
,发现大多集中在一个 <div class="assets">
的块中,所以猜想只要在块中最末尾引入自己需要的 JavaScript 文件即可。然后在项目中检索<div class="assets">
,发现位于 themes/DoIt/layouts/partials/assets.html
这个文件中,那么只需要去覆盖这个文件,然后往里面加入引入 JavaScript 代码文件的命令即可。这是 DoIt 主题的做法,对于其它主题,可参考这个思路,看看能不能找到框架的脚本文件引入入口。
说下做法吧,就是添加自己的 JavaScript 文件,路径是 static/js/custom.js
,然后在复制文件 assets.html
的 <div class="assets">
代码块末尾加入文件引入命令,代码如下
<div class="assets">
{{- range (.Scratch.Get "this").style -}}
{{- partial "plugin/style.html" . -}}
{{- end -}}
{{- range (.Scratch.Get "this").configScript -}}
{{- partial "plugin/script.html" . -}}
{{- end -}}
{{- range (.Scratch.Get "this").script -}}
{{- partial "plugin/script.html" . -}}
{{- end -}}
{{- partial "plugin/analytics.html" . -}}
{{- /* 自定义的js文件 */ -}}
<script type="text/javascript" src="/js/custom.js"></script>
</div>
同理,也可以引入自定义的 CSS 样式文件。另外,对于 HTML 代码,我发现在<div class="assets">
这个元素块直接添加就行,比如
<div id="mycustomelement"></div>
<div class="assets">
而且由于<div class="assets">
这个代码块是位于源代码底部的,所以里面引入文件的效果优先级是最高的。
这样一来,后续想引入任何新出的外部服务,应该都是能够做到了。
对了,其实也可以用这种方式修复主题存在的部分问题。比如之前在部署博客这篇文章里提到过,DoIt 主题对于 waline 评论系统的安全特性支持不够,导致 recaptchaV3 按照文档配置后依旧无法生效。之前是去覆盖主题评论部分代码来让 recaptchaV3 生效,既然知道了这种方式,就可以有另外一种更方便的修改方式了,即在自定义 JavaScript 文件中加入如下代码,以关闭表情包搜索为例(原主题也是不支持的),经过测试是通过的。
if (window.config && window.config.comment && window.config.comment.waline) {
window.config.comment.waline.search = false;
}
如果添加自定义前端代码文件后,发现刷新页面没效果,可以尝试清理网页缓存,步骤是
- 调出网页控制台,比如 chrome 是按 F12
- 右键网址输入框左边的刷新按钮,选择清空缓存并硬性重新加载
4 改造主题代码
这种方式其实是最麻烦的,不仅需要了解 HTML、CSS、JavaScript 这三种语言的用法,还得分析主题代码的逻辑,然后去修改对应位置的代码,个人还是更推荐通过引入自定义的前端代码去进行调整。
能说的就是大致的修改思路以及一些成功案例吧,内容待以后添加。。。