前言 温馨提示:本日记本只提供魔改参考,并不做通用处理,很多源码修改都需要根据自己博客做小小微调
另外在修改源码时注意做好备份处理。本帖只提供思路与方法,如果哪里炸了,请检查语法与缩进等,猹概不负责啦!
继白嫖店长 、冰老师 、小康 、小N 等大佬的魔改之后,猹终于不满于白嫖,开始想动手实操,把自己的博客调教成想要的样子,也以此来使猹学前端有实操的机会。
注 :这部分前言内容会在魔改日记本的每一篇都出现;另外这是一篇日记而非教程,文风可能不是那么友好(逃
本篇特别提示:这次的魔改修改了bf的主要结构,并对一些大的布局样式进行了flex弹性盒子的全面替换,不建议进行跟随魔改(我自己都不记得我改的一些细节)
魔改起因 事情要从小菜单的魔改说起。猹将文章页的目录模块藏在了小菜单里头,结果经过大量的反馈发现,“猹你博客没有目录吗”
az,好吧本来是为了保留作者卡片而设计的小菜单,既然目录没人看到,那小菜单显然也是没人点开看。本来的目的也就没有达到,想想还是把小菜单砍了,重构吧……
主要结构重构-左右双栏与菜单按钮 设计来源、灵感 重构的最主要目的还是原本容易被人忽略的目录模块。找到一个好的目录布局设计可不容易,bf原先的设计也的确不适合我。在zhheo 的推荐下,选用了少数派 的目录设计。
少数派的设计逻辑说实在很戳我的心,然后我脑子一抽决定给他加个当前标题居中显示。。。再然后折腾了几天就是现在这样了。
设计思路 但是折腾这个目录的关键在于,如何保证其自适应良好。采取与小菜单相同的浮动窗口肯定是不好用的,一不小心可能就会变成这个样子(拿同学在做的博客系统举个栗子(反正目录是我的设计))
如果要保证文章板块与目录间天然的自适应,最好的方式还是在左右侧各开辟一个 div 盒子,这样更可靠一点。原本 butterfly 主题的源码部分,是这样的:
<div id ="mainbody" > <main class ="layout hide-aside" id ="content-inner" > <div id ="post" > ...</div > </main > </div >
并且对main部分限定了最大宽度1000px,在双栏布局下双栏也被严格限制在这个大小里,属实是对魔改的发挥起到了一定的限制。故而更改其结构是十分必要的事。于是目标结构如下:
<div id="mainbody"> + <div id="content_leftside">...</div> <main class="layout hide-aside" id="content-inner"> <div id="post">...</div> </main> + <div id="content_rightside">...</div> </div>
此后,显然就可以直接在新开辟的content_rightside加点料。如果只是建立起类似样式的目录倒是小事,实现当前标题的恒定居中才是复杂的东西。
最后是一些功能按键。回到顶部 这个功能显然还是放在类似小彩单的位置合适,样式直接参考fluit主题的按钮即可。而原本的作者卡片我决定提取社交按钮以及一些功能按键,在左侧也形成一个居中对称的设计来进行视觉上的平衡,魔改思路就此完成。
布局调整-开辟左右双栏 将开辟双栏的思路翻译到 pug 源码文件[BlogSource]/themes/butterfly/layout/includes/layout.pug
#mainbody + block content_leftside main#content-inner.layout(class=hideAside) if body div!= body else block content if theme.aside.enable && page.aside !== false include widget/index.pug + block content_rightside
有了左右双栏,目录等的添加就好做了。
目录1-原生目录js再就业 content_rightside pug源码 block content_rightside - let tocNumber = page.toc_number !== undefined ? page.toc_number : theme.toc.number .toc-box if (page.encrypt == true) .toc-content.toc-div-class(style="display:none")!=toc(page.origin, {list_number: tocNumber}) else .toc-content!=toc(page.content, {list_number: tocNumber}) button i.fas.fa-arrow-up
为了方便自适应,按键也一并写在content_rightside
目录板块在小菜单的魔改中就已经写过了,问题在于active状态添加的js失效了。咱本来就不太懂js,自然不愿去再写一份js来对当前标题进行标记。最有可能的方式,自然是对原本的js进行改造再就业。
const tocFn = function () { - const $cardTocLayout = document.getElementById('card-toc') + const $cardTocLayout = document.getElementById('rightside-toc') const $cardToc = $cardTocLayout.getElementsByClassName('toc-content')[0] const $tocLink = $cardToc.querySelectorAll('.toc-link') const $article = document.getElementById('article-container')
但修改完对应类等发现,还是没办法令其生效。于是将目光转向了一些配置项中,最终发现是侧栏的关闭导致了js无法生效。修改文件[BlogSource]/themes/butterfly/layout/includes/head/config_site.pug
- var showToc = is_post() && theme.aside.enable && pageToc && (toc(page.content) !== '' || page.encrypt == true ) + var showToc = is_post() && pageToc && (toc(page.content) !== '' || page.encrypt == true )
active能够正常标记到目录标题中,就可以编写对应的样式。少数派中的胶囊颗粒采用的是在标题前使用div,所有标题也使用div盒子。胶囊与盒子本身不是绝对关联的情况下才有可能做到所有不处于active状态的标题隐藏而胶囊不隐藏的效果。
butterfly的设计下目录则采用有序表格的方式呈现。这也意味着在不改目录生成源码的情况下,我如果想单纯实现胶囊就只能使用before伪类,也没有办法做到一模一样的显隐逻辑,于是只能自己设计效果了。
这里不得不吐槽下不同长度胶囊颗粒的css实现(这写的好淦啊)
.toc-item transition : all 0.5s ease-in-out opacity : 0.5 &.toc-level-1 &:before content : " " margin : 0.65rem 0.4rem 0.65rem 0 width : 1rem height : 0.2rem border-radius : 0.1rem background : #000 &.toc-level-2 &:before content : " " margin : 0.65rem 0.7rem 0.65rem 0 width : 1rem height : 0.2rem border-radius : 0.1rem background : #000 &.toc-level-3 &:before content : " " margin : 0.65rem 1.2rem 0.65rem 0 width : 0.8rem height : 0.2rem border-radius : 0.1rem background : #000 &.toc-level-4 &.toc-level-5 &.toc-level-6 &:before content : " " margin : 0.65rem 1.7rem 0.65rem 0 width : 0.6rem height : 0.2rem border-radius : 0.1rem background : #000
目录2-当前标题居中轮转 居中的轮盘设计就类似于一些卡牌决斗盘抽卡,一些动效就很养眼。本来想使用swiper来实现,但我不知道怎么去控制其随着文章进度转换,于是作罢。
最终选用了十分暴力的 translate 大法,复用目录的标记js部分进行相应的 translate 计算即可动态偏移:
var offset = -currentIndex * 1.5 + 4.25 $cardToc.style.translate = "0 " + offset + "rem"
然后css对对应的标题高度进行限制(例如与上面对应的就是一行1.5rem),保证偏移后还是居中就行。
translate 大法也就有个反人类设计吧,没办法使用滚轮查看目录。
子菜单-回到顶部 回到顶部的按钮还是要做一点点调整的,现在的整体设计是向中间集中的,不适合在边角放小彩单。而放到偏靠中间的部分还是需要考虑位置自适应问题。
fluit主题的回到顶部按钮位置本身是靠js进行控制的。而我这里做了一点点的尝试,直接在content_rightside进行样式测试。
意外的是,fixed布局似乎不会被flex干扰,默认会靠在边上而不会串成串儿。于是直接采用绝对定位将其钉在了content_rightside的左下角。
相关的js逻辑直接复用小彩单,在此不提。
左侧功能区-文章阅读进度与糖果屋二维码 content_leftside pug源码 block content_leftside //- 联系方式 if (theme.social) .leftside-social !=fragment_cache('social' , function(){return partial('includes/header/social' )}) //- 阅读进度 .leftside-contents span //- 跳转评论 .leftside-comment a(href="#post-comment" title="要去留言吗?" ) i.fa-lg.fas.fa-comment .leftside-qq(title="来糖果屋聊天噻!" ) i.fa-lg.fas.fa-qrcode .leftside-rmb a(title="柿还在施工的捐赠页!不给看!" ) i.fa-lg.fas.fa-money-check-dollar .candy_qrcode img(src="./img/candy-qr.png" )
在原先的bf的目录中,有一串数字表示阅读进度(它采用的不是全网页百分比,在我看来逻辑上更合理一点),恰好可以进行复用。在左侧的功能区一群图标中,插入一个数字恰好可以看起来对称些。
然后是一些功能,分享按钮与跳转评论本身只是链接,赞助二维码还没画好(涩涩嘿嘿涩涩)
所以只有一个糖果屋群聊二维码需要加上。我去使用工具绘制了一下一个相对好看且对称的二维码:
然后以类似的方法添加上去。但是这玩意肯定不能常态显示,不然我倒数第二个图标就是摆设了啊。想想我决定动手写一个js。
本身我是没有js编写经验的(以前反正或抄或改,反正就是没有自己写过),好在写了类似hover的逻辑还算简单:
document .addEventListener('DOMContentLoaded' , function ( ) { const leftSideMenu = { qrcodeHover: () => { const left_menu = document .getElementById('left_menu' ) if (left_menu){ const leftside_qq = left_menu.getElementsByClassName('leftside-qq' )[0 ] const left_display = document .getElementById('left_display' ) const candy_qrcode = left_display.getElementsByClassName('candy_qrcode' )[0 ] leftside_qq.addEventListener('mouseover' , function ( ) { candy_qrcode.style.opacity = "1" }) leftside_qq.addEventListener('mouseout' , function ( ) { candy_qrcode.style.opacity = "0" }) } } } leftSideMenu.qrcodeHover(); })
整体显隐逻辑 左右栏还是需要相应的显示逻辑的。文章处于最顶部时不应该显示左右栏和回到最顶按钮,阅读结束后不应显示左右栏。于是这里选择复用原小菜单显隐逻辑代码,做进一步修改:
window .scrollCollect = () => { return btf.throttle(function (e ) { const currentTop = window .scrollY || document .documentElement.scrollTop const isDown = scrollDirection(currentTop) const currentBottom = currentTop + document .documentElement.clientHeight; if (currentTop > 56 ) { if (isDown) { if ($header.classList.contains('nav-visible' )) $header.classList.remove('nav-visible' ) if (isChatBtnShow && isChatShow === true ) { chatBtnHide() isChatShow = false } } else { if (!$header.classList.contains('nav-visible' )) $header.classList.add('nav-visible' ) if (isChatBtnHide && isChatShow === false ) { chatBtnShow() isChatShow = true } } $header.classList.add('nav-fixed' ) var eventlistner = document .getElementById('post' ); if (eventlistner){ var centerY = eventlistner.offsetTop+eventlistner.offsetHeight; if (centerY > currentBottom && currentTop > eventlistner.offsetTop+document .getElementById('post-info' ).offsetHeight){ if ($rightside_toc) $rightside_toc.style.cssText = 'opacity: 1; pointer-events: all' if ($leftside_menu) $leftside_menu.style.cssText = 'opacity: 1; pointer-events: all' } else { if ($rightside_toc) $rightside_toc.style.cssText = 'opacity: 0; pointer-events: none' if ($leftside_menu) $leftside_menu.style.cssText = 'opacity: 0; pointer-events: none' } } if ($rightside_button) $rightside_button.style.cssText = 'bottom: 1rem' } else { if (currentTop === 0 ) { $header.classList.remove('nav-fixed' , 'nav-visible' ) } if ($rightside_toc) $rightside_toc.style.cssText = 'opacity: 0; pointer-events: none' if ($leftside_menu) $leftside_menu.style.cssText = 'opacity: 0; pointer-events: none' if ($rightside_button) $rightside_button.style.cssText = 'bottom: -3rem' } if (document .body.scrollHeight <= innerHeight) { if ($rightside_toc) $rightside_toc.style.cssText = 'opacity: 0; pointer-events: none' if ($leftside_menu) $leftside_menu.style.cssText = 'opacity: 0; pointer-events: none' if ($rightside_button) $rightside_button.style.cssText = 'bottom: -3rem' } }, 200 )() }
显示范围这里选择直接检测文章主体。
css完整代码和gh提交记录 样式代码 #mainbody display : flex #post background : none box-shadow : none &:hover box-shadow : none #content_leftside flex : 1 width : fill-available width : -webkit-fill-available display : flex flex-direction : row-reverse #left_menu top : -1rem opacity : 0 pointer-events : none transition : all 0.3s ease-in-out position : fixed display : flex height : 100% width : 1.5rem padding : 0.5rem margin : 0 auto flex-direction : column justify-content : center align-items : center translate: -0.7rem 0 i color : #000 .leftside-social text-align : center opacity : 0.7 width : 1.5rem margin : 0.4rem transition : all 0.5s .fa-fw margin : 0.5rem 0 transition : all 0.3s transform : scale(1.3 ) &:hover opacity : 1 .leftside-contents .leftside-comment .leftside-qq .leftside-rmb text-align : center margin-bottom : 0.25rem opacity : 0.7 width : 1.5rem height : 1.5rem font-weight : bold transition : all 0.5s a font-weight : bolder .fas margin : 0.5rem 0 width : 1.25em .fas ::hover transform : scale(1.3 ) &:hover opacity : 1 .leftside-contents border-radius : 1rem box-shadow : 0 0 5px #000 margin-bottom : 0.5rem #left_display width : inherit height : 100% margin-right : 3rem display : flex align-items : center position : fixed top : -0.62rem flex-direction : row-reverse .candy_qrcode transition : all 0.3s ease-in-out opacity : 0 pointer-events : none max-width : 9rem width : 100% #content_rightside flex : 1 width : fill-available width : -webkit-fill-available display : flex flex-direction : row #rightside-toc top : -1rem opacity : 0 pointer-events : none transition : all 0.3s ease-in-out position : fixed display : flex height : 100% width : inherit padding : 0.5rem flex-direction : row align-items : center .item-headline font-size : 1rem font-weight : bold display : flex flex-direction : column span margin-left : 0.5rem span .toc-text color : #000 .toc-box height : 10rem width : 100% overflow : hidden .toc-content translate: 0 4.25rem transition : all 0.5s ol padding : 0 margin : 0 list-style-type : none li ::marker content : none li ::before float : left .toc font-weight : bold width : 100% height : inherit overflow-y : scroll overflow-x : hidden margin-top : 0.1rem list-style-type : none .toc-child list-style-type : none .toc ::-webkit-scrollbar width : 0 !important .toc-link line-height : 1.5rem max-height : 1.5rem white-space : nowrap display : block color : var(--btn-bg) transition : all 0.5s padding-left : 0.5rem span .toc-text text-overflow : ellipsis color : #000 &:hover span .toc-text color : #000 &.active transform : scale(1.3 ) transform-origin : 2.5rem 0.75rem font-weight : bolder .toc-item transition : all 0.5s ease-in-out opacity : 0.5 &.toc-level-1 &:before content : " " margin : 0.65rem 0.4rem 0.65rem 0 width : 1rem height : 0.2rem border-radius : 0.1rem background : #000 &.toc-level-2 &:before content : " " margin : 0.65rem 0.7rem 0.65rem 0 width : 1rem height : 0.2rem border-radius : 0.1rem background : #000 &.toc-level-3 &:before content : " " margin : 0.65rem 1.2rem 0.65rem 0 width : 0.8rem height : 0.2rem border-radius : 0.1rem background : #000 &.toc-level-4 &.toc-level-5 &.toc-level-6 &:before content : " " margin : 0.65rem 1.7rem 0.65rem 0 width : 0.6rem height : 0.2rem border-radius : 0.1rem background : #000 &.active transition : all 0.5s ease-in-out opacity : 1 .toc-child display : block &:hover opacity : 1 #rightside-button position : fixed z-index : 101 display : flex bottom : -3rem align-items : center justify-content : center flex-direction : column transition: all .5s button background : var(--card-bg) height : 2rem width : 2rem border-radius : 1rem font-size : 0.8rem box-shadow : 0 0 5px #000 margin : 0.25rem 0 [data-theme="dark" ] #mainbody #content_leftside a &:hover color : #a153ff #left_menu .leftside-contents box-shadow : 0 0 5px #fff i color : #fff .leftside-contents span color : #fff #left_display .candy_qrcode filter : invert(1 ) #content_rightside #rightside-toc span .toc-text color : #fff .toc-link color : var(--btn-bg) span .toc-text color : #fff &:hover span .toc-text color : #fff .toc-item &.toc-level-1 &:before background : #fff &.toc-level-2 &:before background : #fff &.toc-level-3 &:before background : #fff &.toc-level-4 &.toc-level-5 &.toc-level-6 &:before background : #fff #rightside-button button background : var(--card-bg) box-shadow : 0 0 5px #fff i color : #fff .start .end font-family : 'Noto Serif SC' , -apple-system, BlinkMacSystemFont, Roboto, Segoe UI, Helvetica, Arial, serif font-size : large font-weight : bolder opacity : 0.5 @media screen and (max-width : 1200px ) #content_leftside #left_menu display: none !important #content_rightside #rightside-toc display: none !important @media screen and (max-width : 1100px ) #mainbody display: block #content_leftside display: none !important #content_rightside display: none !important
github提交记录 微调-抛弃卡片结构和若干功能区 这部分包含了我很长时间的微调和想法,主要只针对整个文章块。
一是开头的标题部分:
我添加了彩色标签,并把一些数据做了重新排版。(西瓜做分割线真好用)
二是地下文章结束的部分:
我去除了版权卡片(以后大概还会想个设计补上)、上下篇和推荐(我觉得这玩意属实没什么用处,尽管我做了美化但也觉得很违和)
三是去除了文章板块的框框,整个与背景项贴合。整体看起来相对简单整洁一点。
结语 整个文章页魔改应该会告一段落。还剩下的一点坑是移动端的目录和回到顶部,这部分想还是用最传统的浮动小菜单来实现,就不瞎整了。
这部分的魔改太难以像前面的捋思路方式给源码修改参考,涉及的调整部分过多也不利于做教程。所以有能力的还是建议自己翻我博客源码来做更改,没能力的就爱莫能助了。