Contents

Blog 搭建

Beautiful landscape

Nature's Beauty

Explore the wonders of the world

推荐选择的版本

hugo 版本:hugo_extended_withdeploy_0.143.1_linux-amd64
LoveIt 主题版本:0.3.0

请注意 hugo 和主题版本的对应关系,一些主题停止维护了,可能与过高版本的 hugo 出现冲突导致无法正常启动

网络资源

自定义样式

在 assets/css 下面创建一个 _custom.scss,可以自定义 scss 进行美化

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
/* 1. 标题样式 */
.page.single h2 {
  color: rgba(102, 51, 153, 0.7);
  font-size: 1.6rem;
  font-weight: bold;
  line-height: 1.2;
  background-color: #eeeafe;

  // display: inline-block;
  // vertical-align: top; /* 设置垂直对齐,根据需求调整 */

  border-bottom: 1px solid;
  // border-left: 5px solid;
  padding: 5px 15px 5px 0px;
  margin: 14px 0px 14px 0px;
  overflow: hidden;
}

.page.single h3 {
  color: #41b0f4;
  font-size: 1.4rem;
  font-weight: bold;
  line-height: 1.1;
  background-color: #ddf0fe;

  border-bottom: 1px solid;
  // border-left: 5px solid;
  padding: 5px 15px 5px 0px;
  margin: 10px 0px 10px 5px;
  overflow: hidden;
}

.page.single h4 {
  color: #20b60b;
  font-size: 1.2rem;
  font-weight: bold;
  line-height: 1;
  background-color: #ebfde5;

  border-bottom: 1px solid;
  // border-left: 5px solid;
  padding: 5px 15px 5px 0px;
  margin: 10px 0px 10px 10px;
  overflow: hidden;
}

.page.single h2,
.page.single h3,
.page.single h4 {
  // display: table;
  width: fit-content;
}

/* 2. 分类页面样式 */
.archive .categories-card {
  margin-top: 1rem;

  .card-item {
    background: rgba(102, 51, 153, 0.1);
    margin-top: 1rem;
  }

  [theme='dark'] .card-item {
    background: rgb(58, 53, 53);
    margin-top: 1rem;
  }
}

/* 3. 代码块样式 */
@font-face {
  font-family: 'JetBrainsMono';
  src: url('/fonts/JetBrainsMono[wght].ttf') format('truetype');
  font-weight: normal;
  font-style: normal;
}

/* 行内代码块 */
code {
  margin: 0 0.2rem;
  font-size: 0.9rem;
  border: 1px solid #d6d6d6;
  border-radius: 0.2rem;
  line-height: 1rem;
}

/* 预格式代码块 */
pre code {
  margin: 0;
  font-size: 1rem !important;
  border: none;
  line-height: 1.3rem;
  font-family: 'JetBrainsMono', 'Microsoft YaHei', 'SimSun', 'SimHei', Consolas,
    sans-serif !important;
}

/* 标题内的代码块 */
.page.single .content > h2 code {
  color: rgb(247, 171, 1);
  background: transparent !important;
  border: none;
}

使用 fuse.js 给 hugo 添加模糊搜索功能

这里使用的是 LoveIt 主题

修改 hugo.toml

1
2
[outputs]
  home = ["HTML", "RSS", "JSON"]

创建 fastsearch.js

在 static/js 目录下创建 fastsearch.js

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
var fuse // holds our search engine
var fuseIndex
var searchVisible = false
var firstRun = true // allow us to delay loading json data unless search activated
var list = document.getElementById('searchResults') // targets the <ul>
var first = list.children[0] // first child of search list
var last = list.children[list.children.length - 1] // last child of search list
var maininput = document.getElementById('searchInput') // input box for search
var resultsAvailable = false // Did we get any search results?

// ==========================================
// The main keyboard event listener running the show
//
document.addEventListener('keydown', function (event) {
  if (event.altKey && event.which === 191) {
    // Load json search index if first time invoking search
    // Means we don't load json unless searches are going to happen; keep user payload small unless needed
    doSearch(event)
  }

  // Allow ESC (27) to close search box
  if (event.keyCode == 27) {
    if (searchVisible) {
      document.getElementById('fastSearch').style.visibility = 'hidden'
      document.activeElement.blur()
      searchVisible = false
    }
  }

  // DOWN (40) arrow
  if (event.keyCode == 40) {
    if (searchVisible && resultsAvailable) {
      console.log('down')
      event.preventDefault() // stop window from scrolling
      if (document.activeElement == maininput) {
        first.focus()
      } // if the currently focused element is the main input --> focus the first <li>
      else if (document.activeElement == last) {
        last.focus()
      } // if we're at the bottom, stay there
      else {
        // console.log(document.activeElement.nextElementSibling)
        document.activeElement.nextElementSibling.focus()
      } // otherwise select the next search result
    }
  }

  // UP (38) arrow
  if (event.keyCode == 38) {
    if (searchVisible && resultsAvailable) {
      console.log('up')
      event.preventDefault() // stop window from scrolling
      if (document.activeElement == maininput) {
        maininput.focus()
      } // If we're in the input box, do nothing
      else if (document.activeElement == first) {
        maininput.focus()
      } // If we're at the first item, go to input box
      else {
        document.activeElement.previousElementSibling.focus()
      } // Otherwise, select the search result above the current active one
    }
  }

  // ENTER (13) key to trigger link click
  if (event.keyCode == 13) {
    if (searchVisible && resultsAvailable) {
      console.log('enter')
      // Check if the focused element is a link or inside a link
      let focusedElement = document.activeElement
      console.log(focusedElement)
      if (focusedElement.tagName === 'A') {
        focusedElement.click()
      } else if (
        focusedElement.children[0] &&
        focusedElement.children[0].tagName === 'A'
      ) {
        focusedElement.children[0].click()
      }
    }
  }
})

// ==========================================
// execute search as each character is typed
//
document.getElementById('searchInput').onkeyup = function (e) {
  executeSearch(this.value)
}

document.querySelector('body').onclick = function (e) {
  // console.log(e.target.className);
  if (
    ![
      'search-result-item',
      'title',
      'snippet',
      'meta',
      'tags',
      'categories',
    ].includes(e.target.className) &&
    e.target.tagName !== 'INPUT'
  ) {
    hideSearch()
  }
}

document.querySelector('#search-btn').onclick = function (e) {
  doSearch(e)
}

function doSearch(e) {
  e.stopPropagation()
  if (firstRun) {
    loadSearch() // loads our json data and builds fuse.js search index
    firstRun = false // let's never do this again
  }
  // Toggle visibility of search box
  if (!searchVisible) {
    showSearch() // search visible
  } else {
    hideSearch()
  }
}

function hideSearch() {
  document.getElementById('fastSearch').style.visibility = 'hidden' // hide search box
  document.activeElement.blur() // remove focus from search box
  searchVisible = false
}

function showSearch() {
  document.getElementById('fastSearch').style.visibility = 'visible' // show search box
  document.getElementById('searchInput').focus() // put focus in input box so you can just start typing
  searchVisible = true
}

// ==========================================
// fetch some json without jquery
//
function fetchJSONFile(path, callback) {
  var httpRequest = new XMLHttpRequest()
  httpRequest.onreadystatechange = function () {
    if (httpRequest.readyState === 4) {
      if (httpRequest.status === 200) {
        var data = JSON.parse(httpRequest.responseText)
        if (callback) callback(data)
      }
    }
  }
  httpRequest.open('GET', path)
  httpRequest.send()
}

// ==========================================
// load our search index, only executed once
// on first call of search box (CMD-/)
//
function loadSearch() {
  console.log('loadSearch()')
  fetchJSONFile('/index.json', function (data) {
    var options = {
      // fuse.js options; check fuse.js website for details
      isCaseSensitive: false, // 是否大小写敏感
      shouldSort: true, // 结果集是否按照匹配度排序
      includeMatches: true, // 可用于高亮显示匹配字符
      threshold: 0.1, // 匹配度阈值,越大越模糊
      location: 0,
      distance: 500,
      maxPatternLength: 30,
      minMatchCharLength: 1,
      keys: [
        { name: 'content', weight: 0.7 },
        // { name: "title", weight: 0.1 },
        // { name: "tags", weight: 0.1 },
        // { name: "categories", weight: 0.1 },
      ],
    }
    // Create the Fuse index
    fuseIndex = Fuse.createIndex(options.keys, data)
    fuse = new Fuse(data, options, fuseIndex) // build the index from the json file
  })
}

// 处理高亮和对内嵌 html 进行转义
function replaceHighlightElements(html) {
  return html
    .replace(
      /&lt;self-defined-mark style=&quot;background: ([^&;]+);&quot;&gt;/g,
      '<self-defined-mark style="background: rgba(102,51,153,0.4); font-size: 14px; font-weight: bold; padding: 2px 5px; border-radius: 2px;">'
    )
    .replace(/&lt;\/self-defined-mark&gt;/g, '</self-defined-mark>')
}
function escapeHtml(unsafe) {
  return replaceHighlightElements(
    unsafe
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;')
      .replace(/'/g, '&#039;')
  )
}

// ==========================================
// using the index we loaded on CMD-/, run
// a search query (for "term") every time a letter is typed
// in the search box
//
function executeSearch(term) {
  let results = fuse.search(term) // the actual query being run using fuse.js
  let searchitems = '' // our results bucket

  // console.log(results);
  if (results.length === 0) {
    // no results based on what was typed into the input box
    resultsAvailable = false
    searchitems = ''
  } else {
    // build our html
    permalinks = []
    numLimit = 15
    for (let item in results) {
      // only show first 5 results
      if (permalinks.length > numLimit) {
        break
      }
      // if (permalinks.includes(results[item].item.permalink)) {
      //   continue;
      // }
      // console.log('item: %d, title: %s', item, results[item].item.title)
      // 高亮处理函数
      const highlightMatches = (text, matches) => {
        if (!matches || matches.length === 0) return text

        // 将所有匹配位置标记出来
        const indices = matches.flatMap((m) => m.indices)
        const marked = []
        let lastPos = 0

        // 按照索引顺序处理文本
        indices
          .sort((a, b) => a[0] - b[0])
          .forEach(([start, end]) => {
            // 添加未匹配部分
            if (start > lastPos) {
              marked.push(text.substring(lastPos, start))
            }
            // 添加高亮部分
            marked.push(
              `<self-defined-mark style="background: rgba(102,51,153,0.4);">${text.substring(
                start,
                end + 1
              )}</self-defined-mark>`
            )
            lastPos = end + 1
          })

        // 添加剩余文本
        if (lastPos < text.length) {
          marked.push(text.substring(lastPos))
        }

        return marked.join('')
      }

      // 处理内容高亮
      let highlightedContent = results[item].item.content
      const contentMatches = results[item].matches.filter(
        (m) => m.key === 'content'
      )
      if (contentMatches.length > 0) {
        highlightedContent = highlightMatches(
          highlightedContent,
          contentMatches
        )
      }

      // 处理标题高亮
      let highlightedTitle = results[item].item.title
      const titleMatches = results[item].matches.filter(
        (m) => m.key === 'title'
      )
      if (titleMatches.length > 0) {
        highlightedTitle = highlightMatches(highlightedTitle, titleMatches)
      }

      searchitems += `
        <li class="search-result-item" tabindex="-1">
          <a href="${escapeHtml(results[item].item.uri)}" tabindex="0">
            <span class="title">${escapeHtml(highlightedTitle)}</span>
            <div class="snippet">${escapeHtml(highlightedContent)}</div>
          </a>
          <div class="meta">
            <span class="tags">
              <i class="fa fa-tags" aria-hidden="true"></i>
              ${
                results[item].item.tags !== null
                  ? escapeHtml(results[item].item.tags.join('、'))
                  : ''
              }
            </span>
            <span class="categories">
              <i class="far fa-folder" aria-hidden="true"></i>
              ${
                results[item].item.categories !== null
                  ? escapeHtml(results[item].item.categories.join('、'))
                  : ''
              }
            </span>
          </div>
        </li>
      `
      // console.log(searchitems)
      permalinks.push(results[item].item.uri)
    }
    resultsAvailable = true
  }

  document.getElementById('searchResults').innerHTML = searchitems
  if (results.length > 0) {
    first = list.children[0] // first result container — used for checking against keyboard up/down location
    last = list.children[list.children.length - 1] // last result container — used for checking against keyboard up/down location
  }
}

下载 fuse.js

https://github.com/krisk/Fuse/releases,这里选择的是 6.4.6 版本的 fuse.js
下载好解压后,将 Fuse-6.4.6/dist/fuse.js 复制一份到与 fastsearch.js 同目录的 static/js/ 下

创建 index.json

在 layouts/_default 目录下创建 index.json
(但是好像没有效果,得到的索引内容还是根据主题下面的 themes/LoveIt/layouts/index.json 生成的?)

1
2
3
4
5
{{- $.Scratch.Add "index" slice -}}
{{- range .Site.RegularPages -}}
    {{- $.Scratch.Add "index" (dict "title" .Title "tags" .Params.tags "categories" .Params.categories "content" .Plain "permalink" .Permalink "date" .Date "section" .Section) -}}
{{- end -}}
{{- $.Scratch.Get "index" | jsonify -}}

创建 baseof.html

将 themes/LoveIt/layouts/_default/baseof.html 复制一份到 layouts/_default 目录下
然后在 body 中稍作修改,添加搜索区域的输入框和按钮等

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
{{- /* Load JavaScript scripts and CSS */ -}} {{- partial "assets.html" . -}}
<a id="search-btn" style="display: inline-block;" href="javascript:void(0);">
  <span
    class="fa fa-search"
    style="display: flex; justify-content: center; align-items: center;"
  ></span>
</a>

<div id="fastSearch">
  <input id="searchInput" tabindex="0" placeholder="搜索🔍(快捷键 Alt + /)" />
  <ul id="searchResults"></ul>
</div>
<link rel="stylesheet" href='{{ "css/search.css" | relURL }}' />
<script src='{{ "js/fuse.js" | relURL }}'></script>
<script src='{{ "js/fastsearch.js" | relURL }}'></script>

创建 search.css

在 static/css 目录下创建 search.css

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
/* ======================
   Search Button Styles
   ====================== */
#search-btn {
  /* Positioning */
  position: fixed;
  bottom: 5rem;
  right: 1.5rem;
  z-index: 100;

  /* Dimensions */
  width: 2.5rem;
  height: 2.5rem;
  box-sizing: border-box;
  padding: 0.6rem;

  /* Typography */
  font-size: 1rem;
  line-height: 1.3rem;
  color: #a9a9b3;

  /* Appearance */
  background: #f8f8f8;
  border-radius: 2rem;
  -webkit-border-radius: 2rem;
  -moz-border-radius: 2rem;

  /* Animation */
  transition: color 0.4s ease;
  -webkit-transition: color 0.4s ease;
  -moz-transition: color 0.4s ease;
  -o-transition: color 0.4s ease;
}

.blur #search-btn {
  filter: blur(1.5px);
  -webkit-filter: blur(1.5px);
}

/* Button States */
#search-btn:hover,
#search-btn:active {
  color: #161209;
  cursor: pointer;
}

#search-btn:active,
#search-btn:focus,
#search-btn:hover {
  outline: none;
}

/* Dark Theme */
[theme='dark'] #search-btn {
  color: #5d5d5f;
  background: #252627;
}

[theme='dark'] #search-btn:hover,
[theme='dark'] #search-btn:active {
  color: #a9a9b3;
}

/* ======================
   Fast Search Container
   ====================== */
#fastSearch {
  /* Positioning */
  position: fixed;
  z-index: 2;
  left: 50%;
  top: 60px;
  transform: translateX(-50%);

  /* Dimensions */
  max-width: 760px;
  width: calc(100vw - 40px);

  /* Appearance */
  background-color: rgba(255, 255, 255, 0.95);
  border: 1px solid rgba(0, 0, 0, 0.08);
  border-radius: 12px;
  box-shadow: 0 5px 25px rgba(0, 0, 0, 0.4), 0 5px 10px rgba(0, 0, 0, 0.05);
  backdrop-filter: blur(10px);

  /* Behavior */
  visibility: hidden;
  overflow: hidden;
}

/* Search Input */
#fastSearch #searchInput {
  /* Dimensions */
  width: 100%;
  padding: 10px 15px;

  /* Typography */
  font-size: 1.1rem;
  line-height: 1.5;
  color: #333;

  /* Appearance */
  border: none;
  outline: none;
  background-color: transparent;
  border-bottom: 1px solid rgba(0, 0, 0, 0.05);

  /* Animation */
  transition: border-color 0.3s ease;
}

#fastSearch #searchInput::placeholder {
  color: #999;
  opacity: 1;
}

#fastSearch #searchInput:focus {
  border-bottom-color: #4285f4;
}

/* Search Results Container */
#fastSearch #searchResults {
  /* Positioning */
  position: relative;
  z-index: 3;

  /* Dimensions */
  max-height: 70vh;
  padding: 10px 0;
  margin: 0;

  /* Behavior */
  visibility: inherit;
  overflow-y: auto;
  overscroll-behavior: contain;
  scroll-padding-top: 40px;
}

/* No Results Message */
#fastSearch #SearchResults .no-search-results {
  /* Layout */
  display: flex;
  align-items: center;
  justify-content: center;

  /* Dimensions */
  height: 60px;
  padding: 0 25px;

  /* Typography */
  font-size: 1rem;
  color: #666;
}

#fastSearch input:placeholder-shown ~ #SearchResults .no-search-results {
  visibility: hidden;
}

/* Search Result Items */
#fastSearch #SearchResults a {
  /* Layout */
  display: flex;
  align-items: center;

  /* Dimensions */
  width: 100%;
  min-height: 50px;
  padding: 12px 25px;

  /* Typography */
  text-decoration: none;
  color: #333;

  /* Appearance */
  background-color: transparent;
  border-left: 3px solid transparent;
  outline: 0;

  /* Animation */
  transition: all 0.2s ease;
}

#fastSearch #SearchResults a:hover {
  background-color: rgba(0, 0, 0, 0.03);
  border-left-color: #4285f4;
}

#fastSearch #SearchResults .selected-searched-link {
  background-color: rgba(66, 133, 244, 0.1);
}

/* Level 1 Results (Sticky Headers) */
#fastSearch #SearchResults > .search-result-level-1 > a.search-result-page {
  /* Positioning */
  position: sticky;
  top: 0;
  z-index: 2;

  /* Dimensions */
  padding-top: 15px;
  padding-bottom: 15px;

  /* Typography */
  font-weight: 600;
  color: #4285f4;

  /* Appearance */
  background-color: rgba(255, 255, 255, 0.95);
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
  transform: translateY(-1px);
  overflow: hidden;
}

/* Result Type Variations */
#fastSearch #SearchResults a.search-result-page {
  font-weight: 500;
}

#fastSearch #SearchResults a.search-result-heading {
  font-weight: 500;
  color: #222;
}

#fastSearch #SearchResults a.search-result-paragraph {
  font-size: 0.95rem;
  color: #555;
}

/* Image Results */
#fastSearch #SearchResults a.search-result-image img {
  width: 60%;
  border: 1px solid rgba(0, 0, 0, 0.1);
  border-radius: 6px;
  display: block;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}

/* Highlighted Text */
#fastSearch #searchResults mark {
  background-color: #ffeb3b;
  color: #000;
  padding: 0 2px;
  border-radius: 2px;
}

/* Search Result Item */
.search-result-item {
  /* margin-bottom: 1rem; */
  padding: 1rem;
  border-bottom: 1px solid #eee;
}

.search-result-item:hover {
  background: rgba(102, 51, 153, 0.2);
}

.search-result-item .title {
  font-size: 1.2rem;
  font-weight: 400;
}

.search-result-item .snippet {
  font-size: 0.8rem;
  color: #666;
  margin: 0.5rem 0;
  max-height: 3.6em;
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.search-result-item .meta {
  font-weight: 100;
}

.search-result-item .meta .categories {
  float: right;
}

/* ======================
   Responsive Adjustments
   ====================== */
@media (max-width: 900px) {
  #fastSearch #SearchResults a.search-result-page,
  #fastSearch #SearchResults a.search-result-heading,
  #fastSearch #SearchResults a.search-result-paragraph {
    font-size: 0.95rem;
  }

  #fastSearch #SearchResults a.search-result-image img {
    width: calc(100% - 6px);
  }
}

上述步骤完成后,重新在终端执行 hugo serve --disableFastRender
页面的右下角会出现 🔍 按钮

其他

  • markdown 文件头部信息示例

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    
    +++
    date = '2025-01-01T00:00:00+08:00'
    draft = false
    title = '文章标题'
    summary = "博客首页显示的文章内容摘要"
    
    # 分类和标签
    categories = ["类别"]
    tags = ["标签1", "标签2"]
    
    # 封面图
    description = "图片描述"
    featuredImage = "文章顶部图片url"
    +++
    
  • 常用命令
    初始化 hugo new site blog
    创建新文章 hugo new posts/first_post.md
    本地预览 hugo serve --disableFastRender
    构建 public hugo

图片资源

https://unsplash.com/
Unsplash 免费版(非 Unsplash+)的图片都是“免版权”且允许商用的
在个人项目(如博客配图、社交媒体)等地方可以使用,但是禁止直接转售图片(如打包出售)

如果博客大量使用图片,会导致加载缓慢。Chrome 对图片指出 3 点优化建议
图片格式尽量使用 JPEG 2000,JPEG XR 或者 WebP 替代 PNG 和 JPEG,这样图片大小更小
从服务器上拿到的图片尺寸最好是缩放后的尺寸,不要下载过大尺寸的图片
离屏渲染。屏幕以外的图片进行 lazy-load