魔改笔记三:文章三栏(店长+微调) 教程 本网站采用的是三栏+响应式布局的方案,也就是slidecard的方案,但是为了可拓展性,我还是把两种都搬了过来,方便大家阅读!
1、修改[BlogRoot]\themes\butterfly\layout\includes\mixins\post-ui.pug
,整个替换为下面的代码,注意,我这里用的是彩色的图标,每个//- i.fas
那里表示我注释了黑白的额图标并换上彩色图标,彩色图标引入的具体方法见之前的教程,这里只需要替换成你自己的图标名字
和调节相应的大小
即可:
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 mixin postUI(posts) each article , index in page.posts.data .recent-post-item - let link = article.link || article.path let title = article.title || _p('no_title') const position = theme.cover.position let leftOrRight = position === 'both' ? index%2 == 0 ? 'left' : 'right' : position === 'left' ? 'left' : 'right' let post_cover = article.cover let no_cover = article.cover === false || !theme.cover.index_enable ? 'no-cover' : '' - .recent-post-content(class=leftOrRight) .recent-post-cover img.article-cover(src=url_for(post_cover) onerror=`this.onerror=null;this.src='`+ url_for(theme.error_img.post_page) + `'` alt=title) .recent-post-info a.article-title(href=url_for(link) title=title) .article-title-link= title .recent-post-meta .article-meta-wrap if (is_home() && (article.top || article.sticky > 0)) span.article-meta //- i.fas.fa-thumbtack.sticky svg.meta_icon(style="width:16px;height:16px;position:relative;top:3px").post-ui-icon use(xlink:href='#icon-tuding') span.sticky= _p('sticky') span.article-meta-separator | if (theme.post_meta.page.date_type) span.post-meta-date if (theme.post_meta.page.date_type === 'both') //- i.far.fa-calendar-alt svg.meta_icon(style="width:21px;height:21px;position:relative;top:6px").post-ui-icon use(xlink:href='#icon-rili') span.article-meta-label=_p('post.created') time.post-meta-date-created(datetime=date_xml(article.date) title=_p('post.created') + ' ' + full_date(article.date))=date(article.date, config.date_format) span.article-meta-separator | //- i.fas.fa-history svg.meta_icon(style="width:13px;height:13px;position:relative;top:2px").post-ui-icon use(xlink:href='#icon-gengxin1') span.article-meta-label=_p('post.updated') + " " time.post-meta-date-updated(datetime=date_xml(article.updated) title=_p('post.updated') + ' ' + full_date(article.updated))=date(article.updated, config.date_format) else - let data_type_updated = theme.post_meta.page.date_type === 'updated' - let date_type = data_type_updated ? 'updated' : 'date' - let date_icon = data_type_updated ? 'fas fa-history' :'far fa-calendar-alt' - let date_title = data_type_updated ? _p('post.updated') : _p('post.created') i(class=date_icon) span.article-meta-label=date_title time(datetime=date_xml(article[date_type]) title=date_title + ' ' + full_date(article[date_type]))=date(article[date_type], config.date_format) if (theme.post_meta.page.categories && article.categories.data.length > 0) span.article-meta span.article-meta-separator | //- i.fas.fa-inbox svg.meta_icon(style="width:12px;height:12px;position:relative;top:1px").post-ui-icon use(xlink:href='#icon-fenlei') each item, index in article.categories.data a(href=url_for(item.path)).article-meta__categories #[=item.name] if (index < article.categories.data.length - 1) i.fas.fa-angle-right.article-meta-link if (theme.post_meta.page.tags && article.tags.data.length > 0) span.article-meta.tags span.article-meta-separator | //- i.fas.fa-tag svg.meta_icon(style="width:13px;height:13px;position:relative;top:2px").post-ui-icon use(xlink:href='#icon-biaoqian') each item, index in article.tags.data a(href=url_for(item.path)).article-meta__tags #[=item.name] if (index < article.tags.data.length - 1) span.article-meta-link #[=' • '] mixin countBlockInIndex - needLoadCountJs = true span.article-meta span.article-meta-separator | //- i.fas.fa-comments svg.meta_icon(style="width:13px;height:13px;position:relative;top:2px").post-ui-icon use(xlink:href='#icon-pinglun1') if block block span.article-meta-label= ' ' + _p('card_post_count') if theme.comments.card_post_count case theme.comments.use[0] when 'Disqus' +countBlockInIndex a(href=full_url_for(link) + '#disqus_thread') i.fa-solid.fa-spinner.fa-spin when 'Disqusjs' +countBlockInIndex a(href=full_url_for(link) + '#disqusjs') span.disqus-comment-count(data-disqus-url=full_url_for(link)) i.fa-solid.fa-spinner.fa-spin when 'Valine' +countBlockInIndex a(href=url_for(link) + '#post-comment') span.valine-comment-count(data-xid=url_for(link)) i.fa-solid.fa-spinner.fa-spin when 'Waline' +countBlockInIndex a(href=url_for(link) + '#post-comment') span.waline-comment-count(id=url_for(link)) i.fa-solid.fa-spinner.fa-spin when 'Twikoo' +countBlockInIndex a.twikoo-count(href=url_for(link) + '#post-comment') i.fa-solid.fa-spinner.fa-spin when 'Facebook Comments' +countBlockInIndex a(href=url_for(link) + '#post-comment') span.fb-comments-count(data-href=urlNoIndex(article.permalink)) when 'Remark42' +countBlockInIndex a(href=url_for(link) + '#post-comment') span.remark42__counter(data-url=urlNoIndex(article.permalink)) i.fa-solid.fa-spinner.fa-spin when 'Artalk' +countBlockInIndex a(href=url_for(link) + '#post-comment') span.artalk-count(data-page-key=url_for(link)) i.fa-solid.fa-spinner.fa-spin a.article-content(href=url_for(link) title=title) //- Display the article introduction on homepage case theme.index_post_content.method when false - break when 1 .article-content-text!= article.description when 2 if article.description .article-content-text!= article.description else - const content = strip_html(article.content) - let expert = content.substring(0, theme.index_post_content.length) - content.length > theme.index_post_content.length ? expert += ' ...' : '' .article-content-text!= expert default - const content = strip_html(article.content) - let expert = content.substring(0, theme.index_post_content.length) - content.length > theme.index_post_content.length ? expert += ' ...' : '' .article-content-text!= expert .recent-post-arrow if theme.ad && theme.ad.index if (index + 1) % 3 == 0 .recent-post-item.ads-wrap!=theme.ad.index
2、样式方案提供两种:
样式一:电脑端宽屏采用滑动卡片,平板宽度采用双栏布局,手机宽度采用单栏卡片 样式二:移除滑动卡片,按屏幕宽度依次应用三栏、双栏、单栏 新建目录[BlogRoot]\themes\butterfly\source\css\_index_card_style\
,并在下面新建对应的文件slidecard.styl
和multicard.styl
并分别填入以下内容,第一个滑动卡片的是店长原版的,我微调一下第二个的样式,大家可以根据自己的选择进行修改:
样式1:slidecard 样式2:multicard 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 //default color: :root --recent-post-bgcolor: rgba(255, 255, 255, 0.9) //默认背景 --article-content-bgcolor: --recent-post-arrow: --recent-post-cover-shadow: --recent-post-transition: all 0.5s cubic-bezier(0.59, 0.01, 0.48, 1.17) //动画效果。不了解的不要改动 [data-theme="dark" ] --recent-post-bgcolor: rgba(35,35,35,0.5) --article-content-bgcolor: --recent-post-arrow: --recent-post-cover-shadow: // 默认的首页卡片容器布局 .recent-posts padding 0 15px 0 15px height fit-content .recent-post-item margin-bottom 15px width 100% background var(--recent-post-bgcolor) overflow hidden border-radius 15px .recent-post-content display flex background var(--recent-post-bgcolor) position relative .recent-post-cover display flex background transparent .recent-post-info display flex background transparent flex-direction column justify-content center align-items center .article-title height 50% display: flex text-align: center align-items: center justify-content: flex-end flex-direction: column .article-title-link color: var(--text-highlight-color) transition: all .2s ease-in-out display: -webkit-box; -webkit-box-orient: vertical; overflow: hidden; &:hover color: $text -hover .recent-post-meta height 50% display: flex text-align: center align-items: center justify-content: flex-start flex-direction: column .article-meta-wrap color display: -webkit-box; -webkit-box-orient: vertical; overflow: hidden; a color: var(--text-highlight-color) transition: all .2s ease-in-out color &:hover color: $text -hover .article-content display flex text-align: center flex-direction row align-items center justify-content center .article-content-text display -webkit-box -webkit-box-orient vertical text-overflow: ellipsis overflow hidden color text-shadow 1px 2px 3px &::before content "❝" font-size 20px &::after content "❞" font-size 20px &.ads-wrap display: block !important height: auto !important // PC端滑动卡片样式 @media screen and (min-width:1069px) .recent-posts padding 0 15px 0 15px .recent-post-item .recent-post-content position relative height 200px width 100% transition var(--recent-post-transition) &:hover .recent-post-cover-shadow width 10.1% transition var(--recent-post-transition) .recent-post-cover width 10% transition var(--recent-post-transition) .article-content width calc(30% + 80px) transition var(--recent-post-transition) .article-content-text opacity 1 .recent-post-arrow transition var(--recent-post-transition) .recent-post-cover-shadow z-index: 1 transition var(--recent-post-transition) position: absolute height 200px width 40% .recent-post-cover height 200px width 40% transition var(--recent-post-transition) img height 100% width 100% object-fit cover .recent-post-info height 200px width calc(60% - 80px) .article-title margin: 0px 40px font-size 24px .article-title-link -webkit-line-clamp: 2; .recent-post-meta margin: 0px 20px .article-meta-wrap font-size 12px -webkit-line-clamp: 3; .article-content height 200px width 90px background var(--article-content-bgcolor) transition var(--recent-post-transition) .article-content-text -webkit-line-clamp 4 transition: var(--recent-post-transition) opacity 0 .recent-post-arrow transition var(--recent-post-transition) display block position absolute height 20px width 8px background var(--recent-post-arrow) &.both, &.right .recent-post-cover-shadow left 0 background linear-gradient(to left, var(--recent-post-cover-shadow), transparent) .recent-post-cover order: 1 .recent-post-info order: 2 .article-content order: 3 clip-path polygon(0 50%, 80px 0, 100% 0, 100% 100%, 80px 100%) .article-content-text margin 20px 40px 20px 80px .recent-post-arrow order: 4 left calc(100% - 80px) top calc(50% - 10px) clip-path polygon(0 10px, 8px 0, 8px 20px) &:hover .recent-post-arrow left calc(100% - 40px) &.left .recent-post-cover-shadow right 0 background linear-gradient(to right, var(--recent-post-cover-shadow), transparent) .recent-post-cover order: 4 .recent-post-info order: 3 .article-content order: 2 clip-path polygon(100% 50%,calc(100% - 80px) 100%,0 100%,0 0,calc(100% - 80px) 0) .article-content-text margin 20px 80px 20px 40px .recent-post-arrow order: 1 left 72px top calc(50% - 10px) clip-path polygon(0 0, 8px 10px, 0 20px) &:hover .recent-post-arrow left 32px // 双栏布局卡片自适应适配 @media screen and (min-width:572px) and (max-width:1068px) .recent-posts padding 0 15px 0 15px display flex flex-direction row flex-wrap wrap .recent-post-item border-radius 15px overflow hidden width 47% margin 0px 3% 20px 0px nav width: 100% // 手机端单栏布局自适应适配 @media screen and (max-width:572px) .recent-posts padding 0 15px 0 15px .recent-post-item border-radius 15px overflow hidden // 手机端及双栏卡片样式 @media screen and (max-width:1068px) .recent-posts .recent-post-item .recent-post-content flex-direction column flex-wrap nowrap align-items center max-height 350px height: auto width 100% .recent-post-cover width 100% height 200px clip-path polygon(0 130px,0 0,100% 0,100% 130px,50% 100%) img height 200px width 100% object-fit cover .recent-post-info height 150px width 100% padding 0px 25px 5px 25px .article-title margin: 0px 40px font-size 18px .article-title-link -webkit-line-clamp: 2; .recent-post-meta margin: 0px 20px .article-meta-wrap font-size 12px -webkit-line-clamp: 3; .article-content position absolute height 200px width 100% background rgba(25,25,25,0.5) clip-path polygon(0 130px,0 0,100% 0,100% 130px,50% 100%) .article-content-text -webkit-line-clamp 3 font-size 16px margin 0px 25px 30px 25px .recent-post-arrow display block background var(--article-content-bgcolor) position absolute height 10px width 20px clip-path polygon(0 0,100% 0,50% 100%) top 20px
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 :root --theme-color:rgb(57, 197, 187) --text-bg-hover:rgba(57, 197, 187, 0.7) .recent-posts padding 0 5px 0 5px height fit-content .recent-post-item margin-bottom 15px overflow hidden border-radius 15px .recent-post-content display flex position relative .recent-post-cover display flex background transparent .recent-post-info display flex background transparent flex-direction column justify-content center align-items center .article-title height 50% display: flex text-align: center align-items: center justify-content: flex-end flex-direction: column .article-title-link color: var(--text-highlight-color) transition: all .2s ease-in-out display: -webkit-box; -webkit-box-orient: vertical; overflow: hidden; &:hover color: var(--theme-color) .recent-post-meta height 50% display: flex text-align: center align-items: center justify-content: flex-start flex-direction: column .article-meta-wrap color display: -webkit-box; -webkit-box-orient: vertical; overflow: hidden; a color: var(--text-highlight-color) transition: all .2s ease-in-out color &:hover color: var(--theme-color) .article-content display flex text-align: center flex-direction row align-items center justify-content center .article-content-text display -webkit-box -webkit-box-orient vertical text-overflow: ellipsis overflow hidden color text-shadow 1px 2px 3px transition transform 0.6s; &:hover transform: scale(1.1); &.ads-wrap display: block !important height: auto !important nav width: 100% // 卡片单元布局样式 .recent-posts padding 0 5px 0 5px display flex flex-direction row flex-wrap wrap .recent-post-item border-radius 15px overflow hidden .recent-post-content flex-direction column flex-wrap nowrap align-items center max-height 350px height: auto width 100% .recent-post-cover width 100% height 200px clip-path polygon(0 130px,0 0,100% 0,100% 130px,50% 100%) img height 200px width 100% object-fit cover .recent-post-info height 145px width 100% padding 0px 25px 5px 25px .article-title margin: 0px 40px font-size 19px .article-title-link -webkit-line-clamp: 2; .recent-post-meta margin: 0px 20px .article-meta-wrap font-size 13px -webkit-line-clamp: 3; .article-content position absolute height 200px width 100% background rgba(25,25,25,0.4) clip-path polygon(0 130px,0 0,100% 0,100% 130px,50% 100%) .article-content-text -webkit-line-clamp 3 font-size 16px margin 0px 25px 30px 25px &::before content "「" font-size 20px &::after content "」" font-size 20px .recent-post-arrow display block background var(--text-bg-hover) position absolute height 10px width 20px clip-path polygon(0 0,100% 0,50% 100%) // 三栏布局滑动卡片样式 @media screen and (min-width:1069px) .recent-posts .recent-post-item width 32.3% margin 0px 1% 20px 0px .recent-post-content .recent-post-info .article-title margin: 0px 5px .article-title-link -webkit-line-clamp: 1; .recent-post-meta margin: 0px 5px .article-meta-wrap -webkit-line-clamp: 2; // 双栏布局卡片自适应适配 @media screen and (min-width:572px) and (max-width:1068px) .recent-posts .recent-post-item width 47% margin 0px 3% 20px 0px // 单栏布局卡片自适应适配 @media screen and (max-width:572px) .recent-posts .recent-post-item width 100%
3、修改[BlogRoot]\themes\butterfly\source\css\_page\homepage.styl
,将整文件内容替换为以下代码:
1 2 3 4 if hexo-config('index_card_style') == 'slidecard' @import './_index_card_style/slidecard' else if hexo-config('index_card_style') == 'multicard' @import './_index_card_style/multicard'
4、然后在主题配置文件[BlogRoot]\_config.butterfly.yml
里新增配置项,这样我们就可以通过配置项自由切换使用哪款了:
1 2 3 # 主页卡片样式 # Docs: https://akilar.top/posts/d6b69c49/ index_card_style: multicard # slidecard | multicard
5、考虑到不管是样式一还是样式二都存在一个布局突变的情况。为了不至于让首页的文章出现空缺,建议将首页生成的文章数量控制为1,2,3的公倍数。修改站点配置文件[BlogRoot]\_config.yml
。找到以下配置项进行调整,注意这是站点配置文件本就有的配置项,不是新增配置项。建议是调整为12篇。如果你的侧边栏魔改内容特别多,那么建议改成18、24、30。务必确保文章卡片栏比侧栏完全展开要长,这样展示效果最好
1 2 3 4 5 6 7 8 # Home page setting # path: Root path for your blogs index page. (default = '') # per_page: Posts displayed per page. (0 = disable pagination) # order_by: Posts order. (Order by date descending by default) index_generator: path: '' per_page: 12 order_by: -date
6、本教程讨论的卡片都是考虑有封面和有描述的。所以需要保证你已经开启了相应的配置,查看主题配置文件[BlogRoot]\_config.butterfly.yml
,找到配置项开启描述栏,建议选择2模式
1 2 3 4 5 6 7 8 # Display the article introduction on homepage # 1: description # 2: both (if the description exists, it will show description, or show the auto_excerpt) # 3: auto_excerpt (default) # false: do not show the article introduction index_post_content: method: 2 length: 500 # if you set method to 2 or 3, the length need to config
参考: https://www.fomal.cc/posts/d739261b.html
https://akilar.top/posts/d6b69c49/