diff --git a/_config.yml b/_config.yml
index 7fdd554..02e865b 100644
--- a/_config.yml
+++ b/_config.yml
@@ -176,6 +176,13 @@ rss:
enable: false
+# ---------------------------------------------------------------------------------------
+# lazyload image
+# ---------------------------------------------------------------------------------------
+lazyload:
+ enable: false
+
+
# ---------------------------------------------------------------------------------------
# CDN
# ---------------------------------------------------------------------------------------
diff --git a/layout/_partial/scripts.ejs b/layout/_partial/scripts.ejs
index 3306667..1c71a8f 100644
--- a/layout/_partial/scripts.ejs
+++ b/layout/_partial/scripts.ejs
@@ -14,6 +14,10 @@
<%- __js('js/code-copy.js') %>
<% } %>
+<% if (theme.lazyload.enable) { %>
+ <%- __js('js/lazyload.js') %>
+<% } %>
+
<% if (theme.toc.enable && is_post()) { %>
<%- __js([
diff --git a/scripts/filters/lazyload-handle.js b/scripts/filters/lazyload-handle.js
new file mode 100644
index 0000000..8e63e35
--- /dev/null
+++ b/scripts/filters/lazyload-handle.js
@@ -0,0 +1,24 @@
+'use strict'
+hexo.extend.filter.register(
+ 'after_post_render',
+ function (data) {
+ const theme = hexo.theme.config;
+ if (!theme.lazyload || !theme.lazyload.enable) return;
+ data.content = data.content.replace(
+ // Match 'img' tags width the src attribute.
+ /
]*)src="([^"]*)"([^>]*)>/gim,
+ function (match, attrBegin, src, attrEnd) {
+ // Exit if the src doesn't exists.
+ if (!src) return match;
+
+ return `
`
+ }
+ )
+ },
+ 1
+);
diff --git a/scripts/helpers/export-config.js b/scripts/helpers/export-config.js
index 63d641f..95eb017 100644
--- a/scripts/helpers/export-config.js
+++ b/scripts/helpers/export-config.js
@@ -14,7 +14,7 @@ hexo.extend.helper.register('export_config', function () {
let {config, theme} = this;
- // ------------ export language to js ------------
+ // ------------------------ export language to js ------------------------
const languageDir = path.join(__dirname, '../../languages');
let file = fs.readdirSync(languageDir).find(v => v === `${config.language}.yml`);
file = languageDir + '/' + (file ? file : 'en.yml');
@@ -24,7 +24,7 @@ hexo.extend.helper.register('export_config', function () {
} catch (e) {
console.log(e);
}
- // -----------------------------------------------
+ // -----------------------------------------------------------------------
let hexo_config = {
@@ -43,6 +43,7 @@ hexo.extend.helper.register('export_config', function () {
code_copy: theme.code_copy,
side_tools: theme.side_tools,
pjax: theme.pjax,
+ lazyload: theme.lazyload,
version: theme.version,
}
diff --git a/source/css/common/basic.styl b/source/css/common/basic.styl
index 66d5272..162aae2 100644
--- a/source/css/common/basic.styl
+++ b/source/css/common/basic.styl
@@ -3,9 +3,9 @@
@require 'keep-theme.styl'
-// ============================
+// ======================================================================
// html, body
-// ============================
+// ======================================================================
html, body {
margin: 0;
padding: 0;
@@ -29,9 +29,9 @@ html, body {
}
-// ============================
+// ======================================================================
// scrollbar
-// ============================
+// ======================================================================
* {
&::-webkit-scrollbar {
width: 6px;
@@ -48,18 +48,18 @@ html, body {
}
-// ============================
+// ======================================================================
// selection
-// ============================
+// ======================================================================
::selection {
background: var(--selection-color);
color: #fff;
}
-// ============================
+// ======================================================================
// ul, ol, li
-// ============================
+// ======================================================================
ul, ol, li {
padding: 0;
margin: 0;
@@ -67,9 +67,9 @@ ul, ol, li {
}
-// ============================
+// ======================================================================
// a
-// ============================
+// ======================================================================
a {
text-decoration: none;
color: var(--default-text-color);
@@ -82,9 +82,24 @@ a {
}
-// ============================
+// ======================================================================
+// img
+// ======================================================================
+img {
+ &[lazyload] {
+ padding: 20px;
+ cursor: not-allowed;
+ pointer-events: none;
+ margin: 20px auto !important;
+ background: var(--lazyload-background-color);
+ transition();
+ }
+}
+
+
+// ======================================================================
// button
-// ============================
+// ======================================================================
button {
padding: 0;
margin: 0;
@@ -113,9 +128,9 @@ button {
}
-// ============================
+// ======================================================================
// flex center
-// ============================
+// ======================================================================
.flex-center {
display: flex;
justify-content: center;
@@ -123,9 +138,9 @@ button {
}
-// ============================
+// ======================================================================
// clear float
-// ============================
+// ======================================================================
.clear {
clear: both;
}
diff --git a/source/css/common/markdown.styl b/source/css/common/markdown.styl
index 364ecb7..18a40e7 100644
--- a/source/css/common/markdown.styl
+++ b/source/css/common/markdown.styl
@@ -172,6 +172,7 @@
cursor: zoom-in;
display: block;
box-shadow: 0 0 2px var(--shadow-color);
+ transition();
if (hexo-config('style.article_img_align') == 'center') {
margin: 10px auto 2px;
diff --git a/source/css/common/variables.styl b/source/css/common/variables.styl
index 4291982..b642f83 100644
--- a/source/css/common/variables.styl
+++ b/source/css/common/variables.styl
@@ -6,24 +6,25 @@
// ========================================================================================
// layout
// ========================================================================================
-$header-height = 76px; // 头部默认高度
-$header-shrink-height = $header-height * 0.72; // 头部收缩高度
-$scroll-progress-bar-height = 2px; // 头部进度条高度
-$main-content-width = 80%; // 中间内容区域宽度(PC)
-$main-content-width-tablet = 85%; // 中间内容区域宽度(平板)
-$main-content-width-mobile = 90%; // 中间内容区域宽度(手机)
-$circle-button-width = 40px; // tools 圆形工具按钮宽度
-$tools-button-width = 32px; // tools 方形工具按钮宽度
-$component-interspace = 30px; // 组件/模块的间隔值(PC)
+$header-height = 76px; // header height
+$header-shrink-height = $header-height * 0.72; // header shrink height
+$scroll-progress-bar-height = 2px; // scroll progress bar height
+$main-content-width = 80%; // main content width (tablet)
+$main-content-width-tablet = 86%; // main content width (PC)
+$main-content-width-mobile = 90%; // main content width (mobile)
+$circle-button-width = 38px; // post tool button width
+$component-spacing-value = 30px; // component-spacing-value (PC)
+
+// main content max width
$temp-content-max-width = hexo-config('style.content_max_width');
$content-max-width = $temp-content-max-width ? convert($temp-content-max-width) : 1000px;
// ========================================================================================
-// 媒体查询
+// media query
// ========================================================================================
-$media-max-width = 780px; // 媒体查询最大宽度 (平板)
-$media-max-width-mobile = 500px; // 媒体查询最大宽度(手机)
+$media-max-width = 780px; // media query max width (tablet)
+$media-max-width-mobile = 500px; // media query max width (mobile)
keep-tablet()
@media (max-width: $media-max-width)
@@ -76,6 +77,7 @@ $link-color = darken($default-text-color, 10%);
$copyright-info-color = #CC0033;
$avatar-background-color = #0066CC;
$loading-progress-bar-color = #990000;
+$lazyload-background-color = rgba(200, 200, 200, 0.5);
// ========================================================================================
@@ -99,6 +101,7 @@ $dark-link-color = lighten($dark-default-text-color, 10%);
$dark-copyright-info-color = darken($copyright-info-color, 20%);
$dark-avatar-background-color = darken($avatar-background-color, 10%);
$dark-loading-progress-bar-color = lighten($loading-progress-bar-color, 50%);
+$dark-lazyload-background-color = rgba(50, 50, 50, 0.5);
// ========================================================================
@@ -131,7 +134,8 @@ root-color(mode) {
--link-color: mode == 'light' ? $link-color : $dark-link-color;
--copyright-info-color: mode == 'light' ? $copyright-info-color : $dark-copyright-info-color;
--avatar-background-color: mode == 'light' ? $avatar-background-color : $dark-avatar-background-color;
- --loading-progress-bar-color: mode == 'light' ? $loading-progress-bar-color : $dark-loading-progress-bar-color;
+ --loading-progress-bar-color : mode == 'light' ? $loading-progress-bar-color : $dark-loading-progress-bar-color;
+ --lazyload-background-color : mode == 'light' ? $lazyload-background-color : $dark-lazyload-background-color;
}
diff --git a/source/css/layout/_partial/archive-list.styl b/source/css/layout/_partial/archive-list.styl
index 530fd07..c52dfd2 100644
--- a/source/css/layout/_partial/archive-list.styl
+++ b/source/css/layout/_partial/archive-list.styl
@@ -6,7 +6,7 @@ $article-date-font-size = 1rem;
.archive-list-container {
.archive-item {
- margin-bottom: $component-interspace;
+ margin-bottom: $component-spacing-value;
&:last-child {
margin-bottom: 0;
diff --git a/source/css/layout/_partial/comment/comment.styl b/source/css/layout/_partial/comment/comment.styl
index ce87332..d577269 100644
--- a/source/css/layout/_partial/comment/comment.styl
+++ b/source/css/layout/_partial/comment/comment.styl
@@ -12,7 +12,7 @@ if (hexo-config('comment.valine.enable') && hexo-config('comment.gitalk.enable')
.comments-container {
display: inline-block;
- margin-top: $component-interspace;
+ margin-top: $component-spacing-value;
width: 100%;
#comment-anchor {
diff --git a/source/css/layout/article-content.styl b/source/css/layout/article-content.styl
index 7af6e2b..6acb42e 100644
--- a/source/css/layout/article-content.styl
+++ b/source/css/layout/article-content.styl
@@ -91,7 +91,7 @@ $article-title-font-size = 1.6rem;
.article-content {
- margin-top: $component-interspace;
+ margin-top: $component-spacing-value;
padding-bottom: 10px;
border-bottom: 1px solid var(--border-color);
word-wrap: break-word;
@@ -99,13 +99,13 @@ $article-title-font-size = 1.6rem;
}
.post-copyright-info {
- margin-top: $component-interspace;
+ margin-top: $component-spacing-value;
width: 100%;
}
.article-nav {
height: 40px;
- margin-top: $component-interspace;
+ margin-top: $component-spacing-value;
.article-prev, .article-next {
max-width: $post-nav-max-width;
diff --git a/source/css/layout/category-content.styl b/source/css/layout/category-content.styl
index 30e4b94..2556b6d 100644
--- a/source/css/layout/category-content.styl
+++ b/source/css/layout/category-content.styl
@@ -18,7 +18,7 @@ $category-name-font-size = 1.6rem;
font-weight: 600;
padding-bottom: 20px;
- margin-bottom: $component-interspace;
+ margin-bottom: $component-spacing-value;
border-bottom: 1px solid var(--border-color);
}
}
diff --git a/source/css/layout/page.styl b/source/css/layout/page.styl
index a3b17b6..0ed39ea 100644
--- a/source/css/layout/page.styl
+++ b/source/css/layout/page.styl
@@ -78,14 +78,14 @@ $page-aside-width = $temp-width ? convert($temp-width) : 260px;
width: 100%;
display: flex;
justify-content: center;
- padding: $component-interspace 0;
+ padding: $component-spacing-value 0;
+keep-tablet() {
- padding: $component-interspace * 0.8 0;
+ padding: $component-spacing-value * 0.8 0;
}
+keep-mobile() {
- padding: $component-interspace * 0.6 0;
+ padding: $component-spacing-value * 0.6 0;
}
.main-content {
@@ -137,25 +137,25 @@ $page-aside-width = $temp-width ? convert($temp-width) : 260px;
.post-tools {
position: fixed;
- top: $header-height + $component-interspace;
- right: $component-interspace;
+ top: $header-height + $component-spacing-value;
+ right: $component-spacing-value;
transition();
.header-shrink & {
- top: $header-shrink-height + $component-interspace;
+ top: $header-shrink-height + $component-spacing-value;
+keep-tablet() {
- top: $header-shrink-height * 0.9 + $component-interspace;
+ top: $header-shrink-height * 0.9 + $component-spacing-value;
}
+keep-mobile() {
- top: $header-shrink-height * 0.8 + $component-interspace;
+ top: $header-shrink-height * 0.8 + $component-spacing-value;
}
}
+keep-tablet() {
- top: $header-height * 0.9 + $component-interspace;
+ top: $header-height * 0.9 + $component-spacing-value;
right: 10px;
transform: scale(0.82);
transform-origin: right top;
@@ -163,7 +163,7 @@ $page-aside-width = $temp-width ? convert($temp-width) : 260px;
+keep-mobile() {
- top: $header-height * 0.8 + $component-interspace;
+ top: $header-height * 0.8 + $component-spacing-value;
right: 5px;
transform: scale(0.72);
}
diff --git a/source/css/layout/tag-content.styl b/source/css/layout/tag-content.styl
index e568312..9c608e6 100644
--- a/source/css/layout/tag-content.styl
+++ b/source/css/layout/tag-content.styl
@@ -18,7 +18,7 @@ $tag-name-font-size = 1.6rem;
font-weight: 600;
padding-bottom: 20px;
- margin-bottom: $component-interspace;
+ margin-bottom: $component-spacing-value;
border-bottom: 1px solid var(--border-color);
}
}
diff --git a/source/images/loading.svg b/source/images/loading.svg
new file mode 100644
index 0000000..004a356
--- /dev/null
+++ b/source/images/loading.svg
@@ -0,0 +1,17 @@
+
+
\ No newline at end of file
diff --git a/source/js/lazyload.js b/source/js/lazyload.js
new file mode 100644
index 0000000..40ead8e
--- /dev/null
+++ b/source/js/lazyload.js
@@ -0,0 +1,41 @@
+KEEP.initLazyLoad = () => {
+ const imgs = document.querySelectorAll('img');
+ let now = Date.now();
+ let needLoad = true;
+
+ function lazyload(imgs) {
+ now = Date.now();
+ needLoad = Array.from(imgs).some(i => i.hasAttribute('lazyload'));
+
+ const h = window.innerHeight;
+ const s = document.documentElement.scrollTop || document.body.scrollTop;
+
+ imgs.forEach(img => {
+ if (img.hasAttribute('lazyload') && !img.hasAttribute('loading')) {
+
+ if ((h + s) > img.offsetTop) {
+ img.setAttribute('loading', true);
+ const loadImageTimeout = setTimeout(() => {
+ const temp = new Image();
+ const src = img.getAttribute('data-src');
+ temp.src = src;
+ temp.onload = () => {
+ img.src = src;
+ img.removeAttribute('lazyload');
+ img.removeAttribute('loading');
+ clearTimeout(loadImageTimeout);
+ }
+ }, 1000);
+ }
+ }
+ });
+ }
+
+ lazyload(imgs);
+
+ window.onscroll = () => {
+ if (Date.now() - now > 100 && needLoad) {
+ lazyload(imgs);
+ }
+ }
+}
diff --git a/source/js/main.js b/source/js/main.js
index 6c42b24..9477663 100644
--- a/source/js/main.js
+++ b/source/js/main.js
@@ -20,6 +20,10 @@ window.addEventListener('DOMContentLoaded', () => {
if (KEEP.theme_config.code_copy.enable === true) {
KEEP.initCodeCopy();
}
+
+ if (KEEP.theme_config.lazyload.enable === true) {
+ KEEP.initLazyLoad();
+ }
}
KEEP.refresh();