前言(小旦)
- 内容从简,修BUG的事,我就只在原文说明上少量修改,并把代码换了
- 9月26日:发现刷新网页不加载的问题
- 9月27日:发现再次进入首页时,
ProgressiveLoad
类重复声明避免重复定义,在定义ProgressiveLoad类前加判断(9月30日改动后废弃)
- 9月28日:发现跨页返回首页时,会重复创建
ProgressiveLoad
类并调用- 新增每次加载前先清除已有的
.pl-container
元素 - 一图流有人想抄
- 9月29日:首页图下方的有个奇怪的边界的情况,其中一个原因是模糊的小图藏在后面
- 新增监听动画移除小图元素
- 另一个原因是夜间阅读模式,给出解决方案
- 9月30日:Safari浏览器缓存机制导致之前
ProgressiveLoad
类前加判断时无法显示首页图- 使用立即执行函数表达式,给
ProgressiveLoad
创建一个单独作用域
样式预览
渐进式加载预览效果
- 原理是先加载小图文件并进行高斯模糊处理,在大图加载完成后再对大图进行加载。
操作步骤
0、效果二选一
- 选择
仅渐变式加载
或渐变式一图流
其中一种效果仅渐变式加载
是Kouseki的教程版渐变式一图流
是Kouseki的首页版
1、新建文件
- 新建文件
source/js/imgloaded.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
|
(function() { class ProgressiveLoad { constructor(smallSrc, largeSrc) { this.smallSrc = smallSrc; this.largeSrc = largeSrc; this.initTpl(); this.container.addEventListener('animationend', () => { this.smallStage.style.display = 'none'; }, {once: true}); }
initTpl() { this.container = document.createElement('div'); this.smallStage = document.createElement('div'); this.largeStage = document.createElement('div'); this.smallImg = new Image(); this.largeImg = new Image(); this.container.className = 'pl-container'; this.smallStage.className = 'pl-img pl-blur'; this.largeStage.className = 'pl-img'; this.container.appendChild(this.smallStage); this.container.appendChild(this.largeStage); this.smallImg.onload = this._onSmallLoaded.bind(this); this.largeImg.onload = this._onLargeLoaded.bind(this); }
progressiveLoad() { this.smallImg.src = this.smallSrc; this.largeImg.src = this.largeSrc; }
_onLargeLoaded() { this.largeStage.classList.add('pl-visible'); this.largeStage.style.backgroundImage = `url('${this.largeSrc}')`; }
_onSmallLoaded() { this.smallStage.classList.add('pl-visible'); this.smallStage.style.backgroundImage = `url('${this.smallSrc}')`; } }
const executeLoad = (config, target) => { console.log('执行渐进背景替换'); const isMobile = window.matchMedia('(max-width: 767px)').matches; const loader = new ProgressiveLoad( isMobile ? config.mobileSmallSrc : config.smallSrc, isMobile ? config.mobileLargeSrc : config.largeSrc ); if (target.children[0]) { target.insertBefore(loader.container, target.children[0]); } loader.progressiveLoad(); };
const config = { smallSrc: '/img/xiaotu.jpg', largeSrc: '/img/tu.jpg', mobileSmallSrc: '/img/sjxt.jpg', mobileLargeSrc: '/img/sjdt.jpg', enableRoutes: ['/'], };
function initProgressiveLoad(config) { const container = document.querySelector('.pl-container'); if (container) { container.remove(); } const target = document.getElementById('page-header'); if (target && target.classList.contains('full_page')) { executeLoad(config, target); } }
function onPJAXComplete(config) { const target = document.getElementById('page-header'); if (target && target.classList.contains('full_page')) { initProgressiveLoad(config); } }
document.addEventListener("DOMContentLoaded", function() { initProgressiveLoad(config); });
document.addEventListener("pjax:complete", function() { onPJAXComplete(config); });
})();
|
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
|
class ProgressiveLoad { constructor(smallSrc, largeSrc) { this.smallSrc = smallSrc; this.largeSrc = largeSrc; this.initScrollListener(), this.initTpl(); } initScrollListener() { window.addEventListener("scroll", (()=>{ var e = Math.min(window.scrollY / window.innerHeight, 1); this.container.style.setProperty("--process", e) } )) }
initTpl() { this.container = document.createElement('div'); this.smallStage = document.createElement('div'); this.largeStage = document.createElement('div'); this.video = document.createElement('div'); this.smallImg = new Image(); this.largeImg = new Image(); this.container.className = 'pl-container'; this.container.style.setProperty("--process", 0), this.smallStage.className = 'pl-img pl-blur'; this.largeStage.className = 'pl-img'; this.video.className = 'pl-video'; this.container.appendChild(this.smallStage); this.container.appendChild(this.largeStage); this.container.appendChild(this.video); this.smallImg.onload = this._onSmallLoaded.bind(this); this.largeImg.onload = this._onLargeLoaded.bind(this); }
progressiveLoad() { this.smallImg.src = this.smallSrc; this.largeImg.src = this.largeSrc; }
_onLargeLoaded() { this.largeStage.classList.add('pl-visible'); this.largeStage.style.backgroundImage = `url('${this.largeSrc}')`; }
_onSmallLoaded() { this.smallStage.classList.add('pl-visible'); this.smallStage.style.backgroundImage = `url('${this.smallSrc}')`; } }
const executeLoad = (config, target) => { console.log('执行渐进背景替换'); const isMobile = window.matchMedia('(max-width: 767px)').matches; const loader = new ProgressiveLoad( isMobile ? config.mobileSmallSrc : config.smallSrc, isMobile ? config.mobileLargeSrc : config.largeSrc ); if (target.children[0]) { target.insertBefore(loader.container, target.children[0]); } loader.progressiveLoad(); };
const config = { smallSrc: '/img/xiaotu.jpg', largeSrc: '/img/tu.jpg', mobileSmallSrc: '/img/sjxt.jpg', mobileLargeSrc: '/img/sjdt.jpg', enableRoutes: ['/'], };
function initProgressiveLoad(config) { const container = document.querySelector('.pl-container'); if (container) { container.remove(); } const target = document.getElementById('page-header'); if (target && target.classList.contains('full_page')) { executeLoad(config, target); } }
function onPJAXComplete(config) { const target = document.getElementById('page-header'); if (target && target.classList.contains('full_page')) { initProgressiveLoad(config); } }
document.addEventListener("DOMContentLoaded", function() { initProgressiveLoad(config); });
document.addEventListener("pjax:complete", function() { onPJAXComplete(config); });
|
- 新建文件
source/css/imgloaded.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
| .pl-container { width: 100%; height: 100%; position: relative; overflow: hidden; will-change: transform; animation: blur-to-clear 2s cubic-bezier(.62,.21,.25,1) 0s 1 normal backwards running, scale 1.5s cubic-bezier(.62,.21,.25,1) 0s 1 both; } .pl-img { width: 100%; height: 100%; position: absolute; background-position: center; background-size: cover; background-repeat: no-repeat; opacity: 0; transition: opacity 1s; } @keyframes blur-to-clear { 0% { filter: blur(50px); opacity: 1; } 100% { filter: blur(0); opacity: 1; } } @keyframes scale { 0% { transform: scale(1.5) translateZ(0); opacity: 0; } to { transform: scale(1) translateZ(0); opacity: 1; } } .pl-visible { opacity: 1; } .pl-blur { filter: blur(50px); }
|
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
| body[data-type=anzhiyu] #nav,body[data-type=anzhiyu] #scroll-down,body[data-type=anzhiyu] #site-info { -webkit-animation: scale 2.2s cubic-bezier(.6,.1,.25,1) .5s 1 backwards; animation: scale 2.2s cubic-bezier(.6,.1,.25,1) .5s 1 backwards }
@media screen and (max-width: 768px) { .pl-container { position:relative!important } }
@media screen and (min-width: 768px) { #page-header.full_page,.pl-container { height:100vh }
#page-header.full_page.expand-to-full,.pl-container.expand-to-full { height: 50vh!important } .pl-container { will-change: opacity,transform,filter; opacity: calc(1 - var(--process) * 1)!important; transform: scale(calc(1 + var(--process) * .1)); filter: blur(calc(var(--process) * 10px)); } }
.pl-container { width: 100%; height: 100%; position: fixed; z-index: -2; overflow: hidden; will-change: transform; animation: blur-to-clear 2.5s cubic-bezier(.6,.25,.25,1) 0s 1 backwards,scale 2.2s cubic-bezier(.6,.1,.25,1) .5s 1 backwards; }
.pl-img { width: 100%; height: 100%; position: absolute; background-position: center; background-size: cover; background-repeat: no-repeat; opacity: .1; transition: opacity 1s; will-change: transform,opacity } .pl-video.pl-visible { display: block } @keyframes blur-to-clear { 0% { filter: blur(50px); opacity: 1; } 100% { filter: blur(0); opacity: 1; } } @keyframes scale { 0% { transform: scale(1.5) translateZ(0); opacity: 0; } to { transform: scale(1) translateZ(0); opacity: 1; } } .pl-video { position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; z-index: 0; background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAKUlEQVQImU3IMREAIAgAwJfNkQCEsH8cijjpMf6vnXlQaIiJFx+omEBfmqIEZLe2jzcAAAAASUVORK5CYII=); }
.pl-visible { opacity: 1; } .pl-blur { filter: blur(50px); }
|
2、引入文件
- 在
_config.anzhiyu.yml
主题配置文件下inject
配置项中head
和bottom
处 - 分别引入
imgloaded.css
和imgloaded.js
文件1 2 3 4 5 6
| inject: head: - <link rel="stylesheet" href="/css/imgloaded.css?1"> bottom: - <script async data-pjax src="/js/imgloaded.js?1"></script>
|
3、配置图片
务必记得在主题配置文件中开启顶部图的功能,就像这样配置空链接。
1 2
| index_img: "background: url() top / cover no-repeat"
|
- 在
imgloaded.js
中的73到76行(或是83到86行)修改以下示例的部分 - 配置自己的图片,可以是图片直链也可以是本地路径
1 2 3 4 5 6 7
| const config = { smallSrc: '/img/xiaotu.jpg', largeSrc: '/img/tu.jpg', mobileSmallSrc: '/img/sjxt.jpg', mobileLargeSrc: '/img/sjdt.jpg', enableRoutes: ['/'], };
|
4、图片懒加载配置修改
在主题配置文件中找到# Lazyload
,将field
项改为post
,blur
维持true
1 2 3 4 5 6
| lazyload: enable: true field: post # site/post placeholder: blur: true progressive: true
|
5、大功告成
到这一步若你配置的图片文件没有问题,可以执行hexo三连查看效果啦!
6、常见问题
- 首页图下方的有个奇怪的边界的情况(还有一图流的时候,自行设计渐变)
- 如果大图的下边界有不透明度变化,模糊小图,小图会超出不透明度范围,露出小图
- 如果开了夜间模式,是因为由夜间模式的阅读模式叠加一层0.3的alpha,具体是
- blog\themes\anzhiyu\source\css_mode\darkmode.styl文件里的
background-color: alpha($dark-black, 0.3)
,改为
1 2 3 4 5 6
| background-image: linear-gradient( to bottom, rgba($dark-black, 0.1) 0%, rgba($dark-black, 0) 75%, rgba($dark-black, 0) 100% );
|