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 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
| --- title: 关于本站 date: 2022-01-01 00:00 tags: [HEXO] cover: https://r2-assets.thelynan.com/u/easter-eggs-banner-xzczVz.svg ogImage: "https://r2-assets.thelynan.com/uPic/ester eggs.jpg" hide: recent: true translations: ["en"] appendRawMarkdown: true ---
## 构建与托管
本站使用 [HEXO](https://hexo.io/index.html) 构建生成静态网站文件,~~托管在云服务器创建的 [Plesk](https://www.plesk.com/) 面板中。~~
~~在 [Plesk](https://www.plesk.com/) 中配置了 Webhook,当我提交变更到我的 Github 私有仓库以后,触发 Actions 构建网站,变更的内容将自动同步到 [Plesk](https://www.plesk.com/) 网站文件夹进行更新。~~
<div class="new-updates"> 2024-02-06 因为虚拟主机宿主机多次被 DDoS 攻击 <span style="display: inline-block; width: 14px; height: 14px; background-image: url('https://r2-assets.thelynan.com/uPic/3zffxN_1700142351761.png'); background-size: cover;"></span>,所以我把网站托管换到了 CloudFlare Pages。 </div>
### 为什么用 HEXO?
很多年前当我还是一个大学生的时候,捣鼓 VPS、建站是一件很酷的事情。当时我用的是 [BandWagon Host](https://bwh1.net/),使用 NGinx、PHP、MySQL 等配套软件安装 [WordPress](https://wordpress.com/) 建立了自己的个人博客。当时还经历过数据库被勒索,丢失了我写的几篇文章(其实也没有什么,很初级的内容)。
重点在于,像 WordPress 这样依赖数据库的博客**非常需要维护**,对比之下,静态生成的博客如 HEXO、HUGO 只需关心自己的博客文章文件即可,同时 Markdown 格式又允许使用不同的设备随时编写、记录,没有什么迁移负担。
换到 HEXO 以后,整个博客站点托管在 [GitHub](https://github.com/),可以很方便地通过它的 Actions 自动生成新的网站文件,也不用担心丢失。
## 个性化
### 主题
~~使用 [Icarus](https://github.com/ppoffice/hexo-theme-icarus) 主题。~~
<div class="new-updates"> 2025-01-18 换上了自己写的主题。 </div>
大屏设备可以获得最佳阅读体验。谢谢有读者喜欢我的主题,因为是从头开始搓,所以陆陆续续一直在优化/修 bug。估摸着跑个一年到时候开源的话应该是比较 ok 的状态了。
想做的主题:
- **小而美** 审美嘛因人而异,主要是想要用尽可能少的资源来做,目前的主题风格是参考 [The Medium Blog](https://medium.com/blog) - **可访问性好** 希望在各种设备都可访问,例如:禁用 JavaScript,RSS 阅读器,老旧设备,小屏设备(我的一代 iPhone SE)
### 封面图片
有的来自 [Unsplash](https://unsplash.com/),有的是我自己拍的,有的则是我自己用 [Figma](https://www.figma.com/) 绘制并导出的 SVG 文件。矢量图形清晰度非常完美,体积也极小。使用 Figma 后,整理素材更简单了。
### 字体
本站共计使用两种开源/免费字体:
1. **[Source Serif](https://github.com/adobe-fonts/source-serif)** <span style="font-family: 'source-serif';">The quick brown fox jumps over the lazy dog</span> 2. **[Source Han Serif CN](https://fonts.adobe.com/fonts/source-han-serif-simplified-chinese-subset)** <span style="font-family: 'source han serif cn';">敏捷的棕色狐狸跳过了懒狗</span>
以及系统字体:
```css font-family font-family: SF Pro Text, SF Pro Icons, Helvetica Neue, Helvetica, Arial, sans-serif; ```
字体文件由脚本收集所有用到字符简化而成,提高加载速度。
```javascript generate-font-files.js folded const fs = require("fs"); const _ = require("lodash"); const Fontmin = require("fontmin");
const directory = "source/_posts"; const scriptDirectory = "custom-scripts/font"; const fontFileDirectory = `${scriptDirectory}/files`;
const files = fs.readdirSync(directory).filter((item) => item !== ".DS_Store"); const fonts = fs .readdirSync(fontFileDirectory) .filter((item) => item !== "index.js");
const getLetters = () => { const letterMap = {};
_.forEach(files, (file) => { const fileContent = fs.readFileSync(`${directory}/${file}`, "utf8"); const letters = _.toArray(fileContent); _.forEach(letters, (letter) => { if (!letterMap[letter]) { letterMap[letter] = 1; } }); }); return Object.keys(letterMap).join(""); };
const currentLetters = getLetters();
const lettersText = fs.existsSync(`${scriptDirectory}/letters.txt`) ? fs.readFileSync(`${scriptDirectory}/letters.txt`, "utf8") : "";
if (currentLetters === lettersText) { return; }
fs.writeFileSync(`${scriptDirectory}/letters.txt`, getLetters());
const generateFontFile = (letters) => { _.forEach(fonts, (font) => { const task = new Fontmin() .src(`${fontFileDirectory}/${font}`) .dest("themes/icarus/source/fonts") .use( Fontmin.glyph({ text: letters, hinting: false, }) ) .use(Fontmin.ttf2woff2());
task.run(function (err, files) { if (err) { throw err; } }); }); };
generateFontFile(currentLetters); ```
## 插件
### 懒加载
使用了 [hexo-lazyload-element](https://github.com/LynanBreeze/hexo-lazyload-element) 处理图片、视频、iframe 资源的懒加载,提升页面性能的同时避免消耗不必要的流量。
### WebP 图片
~~部分图片是上传到七牛云并使用 `?imageMogr2/format/webp` 参数加载 WebP 图片格式资源。但是对于一些设备(iOS13 以下,MacOS Mojave 以下)需要做兼容。~~
2024/02/22 更新:更换了图床,全站都没有再使用七牛云的资源了。
```javascript checkwebp.js folded /*! modernizr 3.6.0 (Custom Build) | MIT * * https://modernizr.com/download/?-webp-setclasses !*/ !(function (e, n, A) { function o(e) { var n = u.className, A = Modernizr._config.classPrefix || ""; if ((c && (n = n.baseVal), Modernizr._config.enableJSClass)) { var o = new RegExp("(^|\\s)" + A + "no-js(\\s|$)"); n = n.replace(o, "$1" + A + "js$2"); } Modernizr._config.enableClasses && ((n += " " + A + e.join(" " + A)), c ? (u.className.baseVal = n) : (u.className = n)); } function t(e, n) { return typeof e === n; } function a() { var e, n, A, o, a, i, l; for (var f in r) if (r.hasOwnProperty(f)) { if ( ((e = []), (n = r[f]), n.name && (e.push(n.name.toLowerCase()), n.options && n.options.aliases && n.options.aliases.length)) ) for (A = 0; A < n.options.aliases.length; A++) e.push(n.options.aliases[A].toLowerCase()); for (o = t(n.fn, "function") ? n.fn() : n.fn, a = 0; a < e.length; a++) (i = e[a]), (l = i.split(".")), 1 === l.length ? (Modernizr[l[0]] = o) : (!Modernizr[l[0]] || Modernizr[l[0]] instanceof Boolean || (Modernizr[l[0]] = new Boolean(Modernizr[l[0]])), (Modernizr[l[0]][l[1]] = o)), s.push((o ? "" : "no-") + l.join("-")); } } function i(e, n) { if ("object" == typeof e) for (var A in e) f(e, A) && i(A, e[A]); else { e = e.toLowerCase(); var t = e.split("."), a = Modernizr[t[0]]; if ((2 == t.length && (a = a[t[1]]), "undefined" != typeof a)) return Modernizr; (n = "function" == typeof n ? n() : n), 1 == t.length ? (Modernizr[t[0]] = n) : (!Modernizr[t[0]] || Modernizr[t[0]] instanceof Boolean || (Modernizr[t[0]] = new Boolean(Modernizr[t[0]])), (Modernizr[t[0]][t[1]] = n)), o([(n && 0 != n ? "" : "no-") + t.join("-")]), Modernizr._trigger(e, n); } return Modernizr; } var s = [], r = [], l = { _version: "3.6.0", _config: { classPrefix: "", enableClasses: !0, enableJSClass: !0, usePrefixes: !0, }, _q: [], on: function (e, n) { var A = this; setTimeout(function () { n(A[e]); }, 0); }, addTest: function (e, n, A) { r.push({ name: e, fn: n, options: A }); }, addAsyncTest: function (e) { r.push({ name: null, fn: e }); }, }, Modernizr = function () {}; (Modernizr.prototype = l), (Modernizr = new Modernizr()); var f, u = n.documentElement, c = "svg" === u.nodeName.toLowerCase(); !(function () { var e = {}.hasOwnProperty; f = t(e, "undefined") || t(e.call, "undefined") ? function (e, n) { return n in e && t(e.constructor.prototype[n], "undefined"); } : function (n, A) { return e.call(n, A); }; })(), (l._l = {}), (l.on = function (e, n) { this._l[e] || (this._l[e] = []), this._l[e].push(n), Modernizr.hasOwnProperty(e) && setTimeout(function () { Modernizr._trigger(e, Modernizr[e]); }, 0); }), (l._trigger = function (e, n) { if (this._l[e]) { var A = this._l[e]; setTimeout(function () { var e, o; for (e = 0; e < A.length; e++) (o = A[e])(n); }, 0), delete this._l[e]; } }), Modernizr._q.push(function () { l.addTest = i; }), Modernizr.addAsyncTest(function () { function e(e, n, A) { function o(n) { var o = n && "load" === n.type ? 1 == t.width : !1, a = "webp" === e; i(e, a && o ? new Boolean(o) : o), A && A(n); } var t = new Image(); (t.onerror = o), (t.onload = o), (t.src = n); } var n = [ { uri: "data:image/webp;base64,UklGRiQAAABXRUJQVlA4IBgAAAAwAQCdASoBAAEAAwA0JaQAA3AA/vuUAAA=", name: "webp", }, { uri: "data:image/webp;base64,UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAABBxAR/Q9ERP8DAABWUDggGAAAADABAJ0BKgEAAQADADQlpAADcAD++/1QAA==", name: "webp.alpha", }, { uri: "data:image/webp;base64,UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA", name: "webp.animation", }, { uri: "data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiOh/AAA=", name: "webp.lossless", }, ], A = n.shift(); e(A.name, A.uri, function (A) { if (A && "load" === A.type) for (var o = 0; o < n.length; o++) e(n[o].name, n[o].uri); }); }), a(), o(s), delete l.addTest, delete l.addAsyncTest; for (var p = 0; p < Modernizr._q.length; p++) Modernizr._q[p](); e.Modernizr = Modernizr; })(window, document);
Modernizr.on("webp", function (result) { if (result) { // supported } else { // not-supported const webpImages = document.querySelectorAll("img"); Array.prototype.filter .call( webpImages, (item) => item.getAttribute("src") && item.getAttribute("src").includes("") ) .forEach((img) => { const currentSrc = img.getAttribute("src"); img.src = currentSrc.replace("?imageMogr2/format/webp", ""); });
const galleryItems = document.querySelectorAll(".gallery-item"); Array.prototype.filter .call( galleryItems, (item) => item.getAttribute("href") && item.getAttribute("href").includes("") ) .forEach((img) => { const currentSrc = img.getAttribute("href"); img.href = currentSrc.replace("?imageMogr2/format/webp", ""); });
const lazyloadItems = document.querySelectorAll(".lazyload-wrap"); Array.prototype.filter .call( lazyloadItems, (item) => item.dataset && item.dataset.content.includes("%3FimageMogr2%2Fformat%2Fwebp") ) .forEach((item) => { const currentSrc = item.dataset.content; item.dataset.content = currentSrc.replace( "?%3FimageMogr2%2Fformat%2Fwebp", "" ); }); } }); ```
### RSS
使用 [hexo-generator-feed](https://github.com/hexojs/hexo-generator-feed) 生成 `/feed.xml` 便于 RSS 阅读器订阅。
你可以使用以下地址订阅内容。
```html RSS https://cn.thelynan.com/feed.xml ```
### 评论区
使用 [Gitalk](https://github.com/gitalk/gitalk)。
### 广告
~~使用 [Google AdSense](https://www.google.com/adsense),在边栏 Widget 内(小屏设备则在文章最底部),对阅读影响比较小。如果它能覆盖我的 OSS 费用就好啦。~~
有时候会弹全屏广告,体验不好,关了关了。
## 彩蛋
### CSS 动画
例如
<span style="display: inline-block;animation: tilt-shaking ease infinite 0.3s;"><span style="margin-top: 3px; font-size: 18px; font-weight: bold; transform: rotate(30deg);display: inline-block;">过</span><span style="margin-top: -2px; font-size: 14px; font-weight: bold; transform: rotate(-17deg); display: inline-block;">山</span><span style="margin-top: 3px; font-weight: bold; font-size: 19px;transform: rotate(25deg); display: inline-block;">车</span></span><span style="font-size: 24px; margin-left: -13px">🎢</span>
### iframe 交互
页面和 iframe 之间使用了 [postMessage](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) 方式进行通信,丰富静态页面的功能。
<iframe src="/static/image-comparison/index.html?src1=https://r2-assets.thelynan.com/u/65546b9bc458853aefcd0334.jpg&src2=https://r2-assets.thelynan.com/u/65546bb0c458853aefcd392e.jpg" scrolling="no" border="0" frameborder="no" framespacing="0" style="width: 100%; height: 100%; aspect-ratio: 1.3333333333" referrerpolicy="" data-placeholderimg="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/4gHYSUNDX1BST0ZJTEUAAQEAAAHIAAAAAAQwAABtbnRyUkdCIFhZWiAH4AABAAEAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAACRyWFlaAAABFAAAABRnWFlaAAABKAAAABRiWFlaAAABPAAAABR3dHB0AAABUAAAABRyVFJDAAABZAAAAChnVFJDAAABZAAAAChiVFJDAAABZAAAAChjcHJ0AAABjAAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAAgAAAAcAHMAUgBHAEJYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9YWVogAAAAAAAA9tYAAQAAAADTLXBhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAACAAAAAcAEcAbwBvAGcAbABlACAASQBuAGMALgAgADIAMAAxADb/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAASABgDASIAAhEBAxEB/8QAGAABAAMBAAAAAAAAAAAAAAAAAAQGBwj/xAAmEAABBAEDAQkAAAAAAAAAAAACAAEDBAUGBxFhEhMUITFBUXGC/8QAFwEBAAMAAAAAAAAAAAAAAAAABAECA//EABoRAAIDAQEAAAAAAAAAAAAAAAABAgMxIUH/2gAMAwEAAhEDEQA/AIm2W/tyEY4rExEzce62Oxv7BYxRhBNwbN8rjnB4DI4mJ5O5Ly6Kz6eguzmQzG7MRenKmF8nxlHWl02SG/Y1Zd8XYMiFy5ZFM0vWiqY0GjZu2zIkLDJlJyEUTUJnaIG/LKlUDMb3Ak7fToiAtFeGraPkkIhYjJ26uiImwwO9P//Z"></iframe>

### 单独设置的文章背景
例如[关西旅行](/journey-to-japan-2023/)的枫叶背景。
暂时是这些,未来可能会有一些新的想法加入进来。
详细更新内容可见:[**新特性**](/new-features/)
<link rel='stylesheet' href="/css/animations.css" />
|