改造自己的主题
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 这三种语言的用法,还得分析主题代码的逻辑,然后去修改对应位置的代码,个人还是更推荐通过引入自定义的前端代码去进行调整。
能说的就是大致的修改思路以及一些成功案例吧,内容待以后添加。。。