目錄

修改 Hugo 的 404.html 網頁

封面圖片是改版後的 404.html 網頁。

前言

Hugo 的 LoveIt 主題中原先的 404.html 其實就已經很簡單好看了。有天我突發奇想,既然原先的 404.html 可以每次重新載入都顯示不一樣的顏文字表情,那何不如在顏文字上方再加入一段隨機的話呢?說做就做!因此,就誕生了本文。

原先的 404.html

https://raw.githubusercontent.com/Josh-test-lab/website-assets-repository/refs/heads/main/posts/Modify%20Hugo's%20404.html%20page/old%20404%20page.png
LoveIt 主題預設的 `404.html` 網頁。

到網站根目錄的 /layouts/404.html 中,我們可以看到以下程式碼。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
{{- define "title" }}
    {{- T "pageNotFound" | printf "404 %v" }} - {{ .Site.Title -}}
{{- end -}}

{{- define "content" -}}
    <div class="page" id="content-404">
        <h1 id="error-emoji"></h1>
        <p class="error-text">
            {{- T "pageNotFoundText" -}} 
            <a href="javascript:void(0);" title="{{ T `back` }}" onclick="window.history.back();"><i class="far fa-hand-point-left fa-fw" aria-hidden="true"></i></a>
        </p>
    </div>
    <script type="text/javascript">
        (function() {
            var emojiArray = ['\\(o_o)/', '(˚Δ˚)b', '(^-^*)', '(≥o≤)', '(^_^)b', '(·_·)','(=\'X\'=)', '(>_<)', '(;-;)', '(T_T)'];
            document.getElementById('error-emoji').appendChild(document.createTextNode(emojiArray[Math.floor(Math.random() * emojiArray.length)]));
        })();
    </script>
{{- end -}}

這個程式碼夾雜了 Hugo 底層的 GO 語言模板語法以及 html 語法,我們也可以看到所有會出現的顏文字都寫在這裡。

修改 404.html

接下來我們將修改 404.html 網頁,透過添加文字讓網頁更加活潑生動。添加的文字將包含多語言版本,可以在多語言網站中使用。

建立文字文件

首先,於網站根目錄的 /static/ 目錄下建立資料夾,用於存放要顯示的文字與顏文字,此處我命名為 404 error text404 error emoji

接下來,在 /static/404 error text/ 資料夾內建立多語言的文字文件檔案;也在 /static/404 error emoji/ 資料夾內建立存放顏文字的文字文件檔案。

提示
因為顏文字不分語言都看得懂,因此放置顏文字的文字文件檔案就不需要建立多語言檔案了。

檔案目錄應該會如下所示。

1
2
3
4
5
6
7
8
9
/static/
│── 404 error text/       # 存放 404 錯誤訊息文字的資料夾
│   ├── index.zh-tw.md    # 繁體中文版 404 訊息
│   ├── index.en.md       # 英文版 404 訊息
│   └── ...               # 其他語言
│── 404 error emoji/      # 存放 404 錯誤的顏文字
│   └── index.md          # 顏文字訊息

我們可以在 /static/404 error text/index.語言代碼.md 中放入各種想要顯示的文字,這邊我使用 ChatGPT 協助生成以下文字。

  • index.zh-tw.md
1
2
3
4
5
你來到了未知的領域。
這裡什麼都沒有。
迷路的人最終會找到路。
這頁面可能被黑洞吞噬了。
...
  • index.en.md
1
2
3
4
5
You've entered an unknown territory.
There's nothing here.
Lost souls will eventually find their way.
This page might have been swallowed by a black hole.
...

同樣地,也可以在 /static/404 error emoji/index.md 填入顏文字。

  • index.md
1
2
3
4
5
(;-;)
(='X'=)
😁
😂
...

修改 404.html

接著,我們可以調整 404.html ,除了增加文字顯示的功能外,也修改顏文字的顯示方式,使修改 404.html 網頁的文字變得更加便利。

首先,加入文字顯示。在 <div class="page" id="content-404"> 中的 <h1 id="error-emoji"></h1> 元素上方加入 <h1 id="random-text" class="random-text" style="margin-top: 0;"></h1> 。這個用意是在顏文字上方加入一個標題階層為一、靠上對齊且 class 標籤為 random-text 的元素。

添加完後應該會如下所示。

1
2
3
4
5
6
7
8
<div class="page" id="content-404">
    <h1 id="random-text" class="random-text" style="margin-top: 0;"></h1>
    <h1 id="error-emoji"></h1>
    <p class="error-text">
        {{- T "pageNotFoundText" -}} 
        <a href="javascript:void(0);" title="{{ T `back` }}" onclick="window.history.back();"><i class="far fa-hand-point-left fa-fw" aria-hidden="true"></i></a>
    </p>
</div>

接下來,修改 javascript 腳本,使得可以從先前#建立文字文件設定的檔案中隨機讀取一行,並配合多語言輸出。

 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
<script type="text/javascript">
    (function() {
      
        var lang = (document.documentElement.lang || 'en').toLowerCase(); // 取得目前網頁語言
        var textFilePath = `/404 error text/index.${lang}.txt`; // 若目前網頁語言不是網站主要語言,則顯示對應語言的文字檔案
        var fallbackTextPath = '/404 error text/index.en.txt'; // 預設的文字檔案
        var emojiFilePath = '/404 error emoji/index.txt'; // 顏文字檔案
        var fallbackEmojiPath = '/404 error emoji/index.txt'; // 預設的顏文字檔案

        function fetchRandomLine(filePath, fallbackPath, elementId) {
            fetch(filePath)
                .then(response => response.ok ? response.text() : fetch(fallbackPath).then(res => res.ok ? res.text() : Promise.reject()))
                .then(text => {
                    var lines = text.split('\n').filter(line => line.trim() !== '');
                    if (lines.length) {
                        document.getElementById(elementId).textContent = lines[Math.floor(Math.random() * lines.length)];
                    }
                })
                .catch(() => {
                    document.getElementById(`${elementId}`).textContent = `No content available for ${elementId}`; // 未找到檔案的訊息(於網頁中顯示)
                });
        }

        fetchRandomLine(textFilePath, fallbackTextPath, 'random-text');
        fetchRandomLine(emojiFilePath, fallbackEmojiPath, 'error-emoji');
    })();
</script>

因此,完整的 404.html 網頁原始碼應該如下。

 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
{{- define "title" }}
    {{- T "pageNotFound" | printf "404 %v" }} - {{ .Site.Title -}}
{{- end -}}

{{- define "content" -}}
    <div class="page" id="content-404">
        <h1 id="random-text" class="random-text" style="margin-top: 0;"></h1>
        <h1 id="error-emoji"></h1>
        <p class="error-text">
            {{- T "pageNotFoundText" -}} 
            <a href="javascript:void(0);" title="{{ T `back` }}" onclick="window.history.back();"><i class="far fa-hand-point-left fa-fw" aria-hidden="true"></i></a>
        </p>
    </div>
    <script type="text/javascript">
        (function() {
            /*
            var emojiArray = ['\\(o_o)/', '(˚Δ˚)b', '(^-^*)', '(≥o≤)', '(^_^)b', '(·_·)','(=\'X\'=)', '(>_<)', '(;-;)', '(T_T)'];
            document.getElementById('error-emoji').appendChild(document.createTextNode(emojiArray[Math.floor(Math.random() * emojiArray.length)]));
            */
          
            var lang = (document.documentElement.lang || 'en').toLowerCase();
            var textFilePath = `/404 error text/index.${lang}.txt`;
            var fallbackTextPath = '/404 error text/index.en.txt';
            var emojiFilePath = '/404 error emoji/index.txt';
            var fallbackEmojiPath = '/404 error emoji/index.txt';

            function fetchRandomLine(filePath, fallbackPath, elementId) {
                fetch(filePath)
                    .then(response => response.ok ? response.text() : fetch(fallbackPath).then(res => res.ok ? res.text() : Promise.reject()))
                    .then(text => {
                        var lines = text.split('\n').filter(line => line.trim() !== '');
                        if (lines.length) {
                            document.getElementById(elementId).textContent = lines[Math.floor(Math.random() * lines.length)];
                        }
                    })
                    .catch(() => {
                        document.getElementById(`${elementId}`).textContent = `No content available for ${elementId}`;
                    });
            }

            fetchRandomLine(textFilePath, fallbackTextPath, 'random-text');
            fetchRandomLine(emojiFilePath, fallbackEmojiPath, 'error-emoji');
        })();
    </script>
{{- end -}}

至此,我們就完成修改 404.html

結語

透過簡單的修改 404.html 網頁,讓每一位迷路的朋友都遇到不一樣的網頁金句。然後放鬆心情,前往正確的目的地。如果各位讀者朋友有任何的想法或建議,歡迎在留言區暢談。

運行環境

  • Hugo 0.144.2
  • LoveIt 主題(2025 年 2 月 21 日 Github 上的版本)