1. 引言
【butterfly 官方文档】
当进入网页时,因为加载速度的问题,可能会导致 top_img 图片出现断层显示,或者网页加载不全而出现等待时间,开启 preloader 后,会显示加载动画,等页面加载完,加载动画会消失。
没有开启加载动画情况下,页面会由于部分资源加载不完全导致显示异常(比如封面图没出来的话会把背景底色露出来)。加载动画不光可以解决潜在的显示异常(省去很多测试时间),同时也能提高网页浏览的整体流畅度。
但是 butterfly 官方提供的默认动画比较单一(见下图),而且不匹配页面整体 UI 风格,便着手考虑修改此加载动画效果。
本文主要分两部分内容,第一部分的主要内容参考了
文章作者: 百里飞洋 Barry-Flynn 文章链接: https://blog.meta-code.top/2022/06/18/2022-73/
在 第一部分 中,本文将介绍涉及自定义动画的所有文件以及修改指导。在原文基础上,会额外给出每段修改代码的注释意见,方便理解。
而在 第二部分 中,本文将介绍利用 CodePen 网站 搜索并制作(修改)简单的 CSS 动画,有个人想法可以根据其底层逻辑进行个性化创作。
2. 基础配置 2.1 修改 pug 文件(HTML)
[!NOTE]
Pug 是一种简洁的 HTML 模板引擎,使用缩进表示 HTML 结构。它通常用于生成结构化的 HTML 文件, 适用于 Node.js 应用程序。
修改 \themes\butterfly\layout\includes\loading\fullpage-loading(loading.pug)
【修改前】
#loading-box # 帷幕元素 .loading-left-bg .loading-right-bg # 动画主体元素 .spinner-box .configure-border-1 .configure-core .configure-border-2 .configure-core .loading-word= _p('loading') script(). ...
Pug 代码创建了默认加载动画的 HTML 结构,但是默认情况下,渲染器会直接读取 loading.pug 中描述的动画结构,当我们存在不同的动画模板时,调整将变得困难。
这 里我们需要将每个动画固定的 HTML 代码打包成单独的文件,并在设置参数处设立选择参数。
【修改后】
if theme.preloader.enable case theme.preloader.load_style when 'circular' include ./load_style/circular.pug default include ./load_style/default.pug script(). ...
其中, circular.pug 是我创建的动画模板文件,自定义模板需放在同级目录下的 load_style 文件夹中 。(当然其他地方也可以,请自行调整代码中的引用位置)
Vscode 中 目录结构 如下,原文还添加了其他动画模板,这里不作为本文重点所以不进行添加。
在后续也有类似的处理,故也不再截图描述。
[!TIP]
在自定义动画运行时,可以会出现长时间无法退出加载动画的情况,这是因为加载动画的关闭与否是与网站加载状态的load的返回值决定的,而网站加载完成与否这个概念是很模糊的。
这里给到一个超时自动结束 的loaded方案,可以给加载动画设置一个settimeout()的函数来达到伪·加载完毕的效果,即超时了自动关闭加载动画,即使页面还在加载。得益于loading-js使用的是原生js,所以可以给script添加async属性实现异步加载,以免阻塞后续HTML渲染。仅仅需要给控制加载动画开关的loading-js.pug添加两行代码即可。
- script. + script(async). # 启动异步加载 var preloader = { endLoading: () => { document.body.style.overflow = 'auto'; document.getElementById('loading-box').classList.add("loaded") }, initLoading: () => { document.body.style.overflow = ''; document.getElementById('loading-box').classList.remove("loaded") } } window.addEventListener('load',()=> {preloader.endLoading()}) + setTimeout(function(){preloader.endLoading();}, 5000); # 5s超时则自动转入结束加载
2.2 修改 loading.styl(CSS)
[!NOTE]
Stylus 是一种 CSS 预处理器,允许使用更清晰和简洁的语法来生成 CSS。它支持嵌套、变量等高级功能。
修改 \themes\butterfly\source\css\_layout\loading.styl
【修改前】默认动画的样式代码
【修改后】
if hexo-config('preloader.enable ') if hexo-config('preloader.load_style ') == 'circular' @import './_load_style/circular' else @import './_load_style/default'
逻辑同上,也是将固定样式修改为自选样式,你要做的也是在同级目录下新建 _load_style 文件夹,并创建新的自定义动画样式文件(在这里是 circular.stly)
2.3 修改相关的配置文件 (1)修改 \themes\butterfly\layout\includes\layout.pug
此处控制加载动画的 HTML 文件对象选择 ,- 为删减代码,+ 为新增代码(下同)
body - if theme.preloader + if theme.preloader.enable !=partial('includes/loading/index', {}, {cache: true})
(2)修改 \themes\butterfly\source\css\var.styl
此处控制加载动画的 自定义背景色配置
// preloader - $preloader-bg = #37474f + $preloader-bg = hexo-config('preloader.enable ') && hexo-config('preloader.load_color ') ? convert(hexo-config('preloader.load_color ')) : #37474f $preloader-word-color = #fff
(3)修改 _config.butterfly.yml 的 preloader 配置项
此处重新设置 preloader 类的参数 ,以适配刚刚的修改
- preloader: true + preloader: + enable: true + load_color: '#000000' + load_style: circle + load_image:
3. 动画设计 以上工作完成后,我们的自定义动画修改逻辑就极度简单了,即:
[!IMPORTANT]
得到动画的 HTML 与 CSS 文件 - > 转换为适用于博客的 PUG 与 STLY 文件
如何创建动画并获取对应的代码内容呢?这里我们可以使用 CodePen 来实现。
这边就以我本站的小球动画为例,在 Trending (热门)界面搜索“ Loading ”,即可得到许多开源的加载动画
进入到项目的编辑页面,可以看到对应 HTML 与 CSS 代码,在此处做任何调整,下方的动画效果也将实时的调整,因而可以十分方便地设计与修改个性化动画。
3.1 HTML 转换 在这里,我将分别给出 HTML 与 CSS 代码的转换参考,他们的语法结构几乎是一模一样的,只是在表达上存在微调。
先以 HTML 为例:
.loader .circle .circle .circle .circle .circle
对应的 PUG 代码:
#loading-box div.loader div.circle div.circle div.circle div.circle div.circle
你要做的只是加上开头的 loading-box 和块级容器对象 div。
3.2 CSS 转换 .loader { --orbit-radius : 38px ; background : #000 ; position : fixed; z-index : 1000 ; width : 100vw ; height : 100vh ; overflow : hidden; text-align : center; .circle { position : absolute; width : 1px ; height : 1px ; opacity : 0 ; margin : auto; transform : rotate (225deg ); top : 50% ; left : 50% ; transform : translate (-50% , -50% ); animation-iteration-count : infinite; animation-name : orbit; animation-duration : 5.5s ; &:after { content : '' ; position : absolute; width : 5px ; height : 5px ; border-radius : 5px ; background : #fff ; } &:nth-child (2 ) { animation-delay : 240ms ; } &:nth-child (3 ) { animation-delay : 480ms ; } &:nth-child (4 ) { animation-delay : 720ms ; } &:nth-child (5 ) { animation-delay : 960ms ; } } } @keyframes orbit { 0% { transform :rotate (225deg )translateX (38px ); opacity : 1 ; animation-timing-function : ease-out; } 7% { transform :rotate (345deg )translateX (38px ); animation-timing-function : linear; } 30% { transform :rotate (455deg )translateX (38px ); animation-timing-function : ease-in-out; } 39% { transform :rotate (690deg )translateX (38px ); animation-timing-function : linear; } 70% { transform :rotate (815deg )translateX (38px ); opacity : 1 ; animation-timing-function : ease-out; } 75% { transform :rotate (945deg )translateX (38px ); animation-timing-function : ease-out; } 76% { transform :rotate (945deg )translateX (38px ); opacity : 0 ; } 100% { transform :rotate (945deg )translateX (38px ); opacity : 0 ; } }
对应的 styl 代码如下:
#loading-box{ --orbit-radius : 38px ; background : #000 ; position : fixed; z-index : 1000 ; width : 100vw ; height : 100vh ; overflow : hidden; text-align : center; &.loaded { z-index : -1000 ; display : none; } .loader { width : 400px ; height : 400px ; position : absolute; top : 50% ; left : 50% ; transform : translate (-50% , -50% ); background : #000 ; .circle { position : absolute; width : 1px ; height : 1px ; opacity : 0 ; margin : auto; transform : rotate (225deg ); top : 50% ; left : 50% ; transform : translate (-50% , -50% ); animation-iteration-count : infinite; animation-name : orbit; animation-duration : 5.5s ; &:after { content : '' ; position : absolute; width : 5px ; height : 5px ; border-radius : 5px ; background : #fff ; } &:nth-child (2 ) { animation-delay : 240ms ; } &:nth-child (3 ) { animation-delay : 480ms ; } &:nth-child (4 ) { animation-delay : 720ms ; } &:nth-child (5 ) { animation-delay : 960ms ; } } } } @keyframes orbit { 0% { transform :rotate (225deg ) translateX (var (--orbit-radius)); opacity : 1 ; animation-timing-function : ease-out; } 7% { transform :rotate (345deg ) translateX (var (--orbit-radius)); animation-timing-function : linear; } 30% { transform :rotate (455deg ) translateX (var (--orbit-radius)); animation-timing-function : ease-in-out; } 39% { transform :rotate (690deg ) translateX (var (--orbit-radius)); animation-timing-function : linear; } 70% { transform :rotate (815deg ) translateX (var (--orbit-radius)); opacity : 1 ; animation-timing-function : ease-out; } 75% { transform :rotate (945deg ) translateX (var (--orbit-radius)); animation-timing-function : ease-out; } 76% { transform :rotate (945deg ) translateX (var (--orbit-radius)); opacity : 0 ; } 100% { transform :rotate (945deg ) translateX (var (--orbit-radius)); opacity : 0 ; } }
可以注意到,二者语法逻辑是一模一样的,唯一较大不同是 styl 添加了 &.loaded
&.loaded {
z-index: -1000;
display: none;
}
这段代码定义了加载动画完成后的显示状态,功能是将 动画元素置于底层并不可见 。
修改完毕后,可以 hexo g && hexo s 在本地查看动画效果。