点击查看更新记录

更新记录

2022-03-28:魔改方案实现

  1. 感谢@Ruby的反馈。
  2. 调整了部分易重名class的选择域,修复与highlightjs渲染的代码块的样式冲突问题。

2021-12-13:移除自适应

  1. 移除多宽度下的自适应内容,一律铺满
  2. 适配fixed_card_widget
  3. 联动教程: 基于Butterfly的手机端fixed定位侧栏布局魔改方案

2021-08-02:魔改方案实现

  1. 重构PUG文件。为了确保可移值性,弃用大部分原pug内的类名
  2. 精简冗余样式表。
  3. 新增夜间模式适配
  4. 将文章标签分类改为EXP\HP\MP的形式
  5. 重新排布元素布局
  6. 添加了不同分辨率下的样式修复补丁
  7. 不再更改card_author.pug,直接另写一个。确保可移值性

2021-07-30:UI实现

  1. 初步实现翻转功能
  2. 布局内容敲定
  3. 正面显示纯文本或图片元素,如头像、描述
  4. 背面显示可点击元素,如站点文章分类标签、自定义按钮、社交图标
点击查看参考教程
参考方向教程原贴
参考了翻转面板的纯CSS实现方法Parallax Flipping Cards
样式风格参考,图标、音效资源采集SAO Utils
CSS transform 属性CSS transform 属性

写在最前

店长的碎碎念

这是SAO UI PLAN 的第五弹了,效果没有我想的那么理想。在面积有限的作者卡片上做文章实在是有些捉襟见肘,除了可以在配色上动动脑筋以外,没啥可以放内容的地方。

然后就想到了翻转卡片。一下子就把面积增加了一倍。然后求助与万能的codepen,果然不负众望。让我找到了Parallax Flipping Cards这个项目。而且这个项目是纯css实现,且dom存在很明显的重复结构。很适合拿来写成外挂标签或者友链卡片。这部分内容就暂时待定了。啥时候等我找到合适的相册魔改原型再一起编写好了。

其实早在今年六月份的时候就想对侧栏动手了,但是工作忙,周末懒,一直没心思去开始。七月份外公因为窒息休克进了ICU,又因为疫情迟迟不能回去,心情一直处在紧绷状态。好在写这个项目的前一天,外公已经从ICU转普通病房了。

这次的作者卡片魔改依然是存在插件化可行性的。且因为是完全重写了结构。所以不再在原有pug上动刀。而是直接另写一个新pug。

这次我复用了card_author.pug中的所有变量。所以原本有的信息都会有。不用再加任何新的配置项。

魔改步骤

SAO UI PLAN 相关项目为本站原创项目,因此均为内测版,在样式适配上仅针对本站进行调整,因此在泛用性上存在缺漏。对于可能遇到的bug,欢迎在评论区进行讨论。

在进行本帖的魔改前,请务必做好备份以便回退。

  1. 新建[Blogroot]\themes\butterfly\layout\includes\custom\SAO_card_player.pug,以后的教程中,如非必要,pug文件将不会再沿用_layout之类的主题逻辑分类。全部魔改文件和路径都会放在新建的带custom字样的文件夹中如果没有这个文件夹,可以自己新建。同时,我也建议各位能够自主的将过去的一些魔改路径梳理至custom目录下 。此处为了便于后续npm插件化,没有另写辅助函数来处理血条计算。而是直接在pug中计算。
    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
    if theme.aside.card_author.enable
    .card-widget.card-info
    .cols
    .col
    .container
    .front.avatarPanel
    .inner
    .player-title= 'Attributes'
    .player-avatar
    img(src=url_for(theme.avatar.img) onerror=`this.onerror=null;this.src='` + url_for(theme.error_img.flink) + `'` alt="avatar")
    .back.attributesPanel
    .inner
    - var playerLV = Math.ceil(Number( site.posts.length) / 10)
    .player-lv= 'LV.' +playerLV
    .player-name= config.author
    .attributes-value
    if site.posts.length
    .attributes-value-item
    a(href=url_for(config.archive_dir) + '/')
    .attributes= _p('aside.articles')
    .value-bar
    - var fillMAX = Math.ceil(Number( site.posts.length) / 100) * 100
    - var fillNow = Number(site.posts.length)
    - var valueFill = ( fillNow / fillMAX * 100 ).toFixed(2) + '%'
    .value-bar-fill(style=`width:`+ valueFill)
    .value-bar-fill-in(style='background: rgba(89, 230, 54,0.6)')
    span= fillNow +'/'+ fillMAX

    if site.tags.length
    .attributes-value-item
    a(href=url_for(config.tag_dir) + '/')
    .attributes= _p('aside.tags')
    .value-bar
    - var fillMAX = Math.ceil(Number( site.tags.length) / 100) * 100
    - var fillNow = Number(site.tags.length)
    - var valueFill = ( fillNow / fillMAX * 100 ).toFixed(2) + '%'
    .value-bar-fill(style=`width:`+ valueFill)
    .value-bar-fill-in(style='background: rgba(224, 20, 20, 0.6)')
    span= fillNow +'/'+ fillMAX

    if site.categories.length
    .attributes-value-item
    a(href=url_for(config.category_dir) + '/')
    .attributes= _p('aside.categories')
    .value-bar
    - var fillMAX = Math.ceil(Number( site.categories.length) / 100) * 100
    - var fillNow = Number(site.categories.length)
    - var valueFill = ( fillNow / fillMAX * 100 ).toFixed(2) + '%'
    .value-bar-fill(style=`width:`+ valueFill)
    .value-bar-fill-in(style='background: rgba(30, 97, 226, 0.6)')
    span= fillNow +'/'+ fillMAX
    .col
    .container
    .front.descriptionPanel
    .inner
    .player_description!= theme.aside.card_author.description || config.description
    .play-bottom
    .back.buttonPanel
    .inner
    if theme.aside.card_author.button.enable
    a#card-info-btn.button--animated(href=theme.aside.card_author.button.link)
    i(class=theme.aside.card_author.button.icon)
    span=theme.aside.card_author.button.text
    if(theme.social)
    .card-info-social-icons.is-center
    !=fragment_cache('social', function(){return partial('includes/header/social')})
    .play-bottom
  2. 新建[Blogroot]\themes\butterfly\source\css\_layout\SAO_card_player.styl
    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
    @font-face
    font-family: 'SAOUI'
    src: url('https://npm.elemecdn.com/测试-candyassets/fonts/SAOUI.ttf')
    font-display: swap
    a.social-icon
    svg.icon
    width: 27px
    height: 27px
    .card-widget.card-info
    padding: 0!important
    margin-bottom: 20px;
    font-family: 'SAOUI','ZhuZiAYuanJWD'
    .player_description
    font-size: 20px;
    .card-info-social-icons.is-center
    // 样式错位修复关键帧
    height: 50%;
    .social-icon
    font-size: 18px!important;
    #card-info-btn
    width 90% !important
    font-size 20px !important
    margin 10px 5% !important
    .player-avatar
    display: inline-block;
    width: 150px
    height: 150px
    img
    max-width: 100%
    .play-bottom
    font-size: 20px;
    background: rgba(240, 240, 238,0.9);
    // 样式错位修复关键帧
    height: 40px;
    color rgba(60, 60, 61,0.7)
    text-shadow 1px 1px 1px #888888
    box-shadow: 2px -2px 10px #888888
    .player-lv,
    .player-title
    font-size: 20px;
    background: rgba(240, 240, 238,0.9);
    height: 40px;
    color rgba(60, 60, 61,0.7)
    text-shadow 1px 1px 1px #888888
    box-shadow: 2px 2px 10px #888888
    .player-name
    font-size: 30px
    height: 30px
    color rgba(60, 60, 61,0.7)
    text-shadow 1px 1px 1px #888888
    .attributes-value
    display: block;
    font-size: 20px
    height: auto
    text-align: left
    // 样式错位修复关键帧
    margin: 5% 5%
    a
    color rgba(60, 60, 61,0.7)
    text-shadow 1px 1px 1px #888888
    &:hover
    color: rgba(237, 166, 12,0.8)
    .attributes-value-item
    display: block
    height: 27px
    .attributes
    display: inline-block
    width: 20%
    .value-bar
    display: inline-block
    width: 50%
    background: rgba(255, 255, 255, 0.8);
    height: 12px
    margin: 0 3%
    border-radius: 5px
    box-shadow 2px 2px 3px #fff
    border 1px solid rgba(255,255,255,0.5)
    overflow: hidden
    .value-bar-fill
    height: 10px
    margin: 1px 0;
    .value-bar-fill-in
    height: 12px
    span
    font-size: 14px
    .container
    -webkit-transform-style preserve-3d
    transform-style preserve-3d
    -webkit-perspective 1000px
    perspective 1000px
    min-height 200px
    width 100%
    height 50%
    .back
    -webkit-transform rotateY(180deg)
    transform rotateY(180deg)
    -webkit-transform-style preserve-3d
    transform-style preserve-3d
    .front
    -webkit-transform rotateY(0deg)
    transform rotateY(0deg)
    -webkit-transform-style preserve-3d
    transform-style preserve-3d
    &:hover
    .back
    -webkit-transform rotateY(0deg)
    transform rotateY(0deg)
    -webkit-transform-style preserve-3d
    transform-style preserve-3d
    .front
    -webkit-transform rotateY(-180deg)
    transform rotateY(-180deg)
    -webkit-transform-style preserve-3d
    transform-style preserve-3d

    .front,
    .back
    -webkit-transition -webkit-transform .7s cubic-bezier(0.4, 0.2, 0.2, 1)
    transition -webkit-transform .7s cubic-bezier(0.4, 0.2, 0.2, 1)
    -o-transition transform .7s cubic-bezier(0.4, 0.2, 0.2, 1)
    transition transform .7s cubic-bezier(0.4, 0.2, 0.2, 1)
    transition transform .7s cubic-bezier(0.4, 0.2, 0.2, 1), -webkit-transform .7s cubic-bezier(0.4, 0.2, 0.2, 1)
    -webkit-backface-visibility hidden
    backface-visibility hidden
    text-align center
    min-height 200px
    width 100%
    height 50%
    font-size 1.5rem

    .back

    position absolute
    top 0
    left 0
    width 100%

    .front
    &:after
    min-height 200px
    width 100%
    height 50%
    position absolute
    top 0
    left 0
    z-index 1
    width 100%
    height 100%
    content ''
    display block
    opacity .6
    -webkit-backface-visibility hidden
    backface-visibility hidden
    .container:hover .front,
    .container:hover .back
    min-height 200px
    width 100%
    height 50%
    -webkit-transition -webkit-transform .7s cubic-bezier(0.4, 0.2, 0.2, 1)
    transition -webkit-transform .7s cubic-bezier(0.4, 0.2, 0.2, 1)
    -o-transition transform .7s cubic-bezier(0.4, 0.2, 0.2, 1)
    transition transform .7s cubic-bezier(0.4, 0.2, 0.2, 1)
    transition transform .7s cubic-bezier(0.4, 0.2, 0.2, 1), -webkit-transform .7s cubic-bezier(0.4, 0.2, 0.2, 1)

    .inner
    background: rgb(220, 220, 221)
    min-height 200px
    height 50%
    -webkit-transform translateY(-50%) translateZ(60px) scale(0.94)
    transform translateY(-50%) translateZ(60px) scale(0.94)
    top 50%
    position absolute
    left 0
    width 100%
    padding 0
    -webkit-box-sizing border-box
    box-sizing border-box
    outline 1px solid transparent
    -webkit-perspective inherit
    perspective inherit
    z-index 2
    .col
    width 100%
    // 夜间模式适配
    [data-theme="dark"]
    .card-widget.card-info
    .play-bottom
    background: rgba(25, 25, 21,0.9);
    color rgba(215, 215, 215,0.7)
    text-shadow 1px 1px 1px rgba(38, 230, 242, 0.5)
    box-shadow: 2px -2px 10px rgba(38, 230, 242, 0.5)
    .player-lv,
    .player-title
    background: rgba(25, 25, 21,0.9);
    color rgba(215, 215, 215,0.7)
    text-shadow 1px 1px 1px rgba(38, 230, 242, 0.5)
    box-shadow: 2px 2px 10px rgba(38, 230, 242, 0.5)
    .player-name
    color rgba(215, 215, 215,0.7)
    text-shadow 1px 1px 1px rgba(38, 230, 242, 0.5)
    .attributes-value
    a
    color rgba(215, 215, 215,0.7)
    text-shadow 1px 1px 1px rgba(38, 230, 242, 0.5)
    &:hover
    color: rgb(237, 166, 12)
    .attributes-value-item
    .value-bar
    background: rgba(25, 25, 21,0.9);
    box-shadow 2px 2px 3px rgba(38, 230, 242, 0.5)
    border 1px solid rgba(25, 25, 21,0.9)
    .inner
    background: rgba(25, 25, 21,0.9)

  3. 因为这次不是对card_author.pug动刀子,所以要再改下路径。以后若是插件化的话,会直接挂载,那时候就是到配置文件中关闭card_author了。修改[Blogroot]\themes\butterfly\layout\includes\widget\index.pug,视主题版本不同,index.pug的格式也不尽相同。好在这次我们只是需要改文件路径。不论是什么版本的主题,都只需在文件中搜索widget/card_author,将其替换为custom/SAO_card_player即可。

    可能出现的bug

    因为这次正反面是用的伪类实现。我实在是不知道怎么用flex布局来调整它。所以还是很没出息的用的盒子布局。所以在描述、按钮、社交图标的内容不同时,会出现很多的自适应问题。
    已经在stylus文件中注释了样式修复的几处关键帧,若出现错位,可以自己调整参数。

    TO DO

    重写作者卡片UI,改成游戏角色属性面板

    常规显示头像,鼠标悬停翻转显示人物属性卡片

    常规显示站点描述,鼠标悬停翻转显示social icon

    点击头像,持续显示站点描述(废案)