我要魔改一下博客的说说样式!

忘记了是什么时候兴起的这个想法。真正促使我去实现这个想法的,是夏洛蒂的角色演示视频。传送门:《原神》角色演示-「夏洛蒂:爆炸新闻!」

img

image-20231120195719940

她真的好可爱啊!这么活泼可爱的冰系角色,真的少见。

夏洛蒂的可爱是一方面,角色演示里面的蒸汽鸟报同样也令人在意。

image-20231120200041418

image-20231120200115886

image-20231120200148723

image-20231120200213846

image-20231120200242516

虽然里面的文字我看不懂,但是看看这排版,看看这色彩,真是令人愉悦,我很喜欢。

众所周知,写代码很容易,但是美学设计是一件非常考验艺术素养的工作。彼时的我正在为说说页面的样式设计烦恼,看到这个角色演示视频,发现了新的大陆,茅塞顿开!当即决定了说说页面的样式——我要抄袭《蒸汽鸟报》。

这没什么可丢人的,反而一种学习的过程,让你无限进步。

效果展示

桌面端、移动端自适应,点击下方链接查看Demo。

说说Demo

实现代码

基本上重写了整个页面结构,来保证效果实现。自定义设置方面,移除了说说模板说说提示箭头,剩下的还能用。

image-20231120201737107

样式方面,主要应用Flex布局来实现效果,能够自适应桌面端和移动端。

页面模板

<?php

/**
 * Template Name: 说说模版
 */

get_header();
?>

<div id="primary" class="content-area">
    <main class="site-main" role="main">
    <?php
        $shuoshuo_per_page = iro_opt('shuoshuo_per_page'); //每页显示的说说数量
        $paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
        $args = array(
            'post_type' => 'shuoshuo',
            'post_status' => 'publish',
            'posts_per_page' => $shuoshuo_per_page,
            'paged' => $paged
        );
        $shuoshuo_query = new WP_Query($args);
    ?>
    <div class="entry-content">
        <?php the_content( '', true ); ?>
    </div>            
    <div class="cbp_shuoshuo">
        <?php if ($shuoshuo_query->have_posts()) : ?>
            <ul id="main" class="cbp_tmtimeline">
                <?php while ($shuoshuo_query->have_posts()) : $shuoshuo_query->the_post(); ?>
                    <li id="shuoshuo_post">
                        <div class="shuoshuo-content">
                            <div class="shuoshuo-text">
                                <div class="shuoshuo-title">
                                    <?php the_title('<h2>', '</h2>') ?>
                                </div>
                                <div class="shuoshuo-body">
                                    <p><?php echo strip_tags(get_the_content()) ?></p>
                                </div>
                            </div>
                            <div class="shuoshuo-images">
                                <?php
                                    preg_match_all('/<a[^>]+><img[^>]+><\/a>|<img[^>]+\/>/i', get_the_content(), $shuoshuo_images);
                                    $shuoshuo_images_count = count($shuoshuo_images[0]);
                                    if (!empty($shuoshuo_images_count)) {
                                        switch($shuoshuo_images_count) {
                                            case 1:
                                                $image_html_list = '<span class="image-full">'.$shuoshuo_images[0][0].'</span>';
                                                break;
                                            case 2:
                                                $image_html_list = '<span class="image-two">'.$shuoshuo_images[0][0].'</span>';
                                                $image_html_list.= '<span class="image-two">'.$shuoshuo_images[0][1].'</span>';
                                                break;
                                            case 3:
                                                $image_html_list = '<span class="image-three">'.$shuoshuo_images[0][0].'</span>';
                                                $image_html_list .= '<span class="image-three">'.$shuoshuo_images[0][1].'</span>';
                                                $image_html_list .= '<span class="image-three">'.$shuoshuo_images[0][2].'</span>';
                                                break;
                                            default :
                                                $image_html_list = '<span class="image-four">'.$shuoshuo_images[0][0].'</span>';
                                                $image_html_list .= '<span class="image-four">'.$shuoshuo_images[0][1].'</span>';
                                                $image_html_list .= '<span class="image-four">'.$shuoshuo_images[0][2].'</span>';
                                                $image_html_list .= '<span class="image-four">'.$shuoshuo_images[0][3].'</span>';
                                                break;
                                        }

                                    } else {
                                        $image_html_list = '<span class="image-full"><img src="' . DEFAULT_FEATURE_IMAGE() . '"/></span>';       
                                    }
                                    remove_filter( 'the_content', 'wpautop' );
                                    $image_html_list = apply_filters( 'the_content', $image_html_list );
                                    echo $image_html_list;
                                ?>
                            </div>
                        </div>
                        <div class="shuoshuo-meta">
                            <div class="shuoshuo-author-image">
                                <?php echo get_avatar(get_the_author_meta('ID'), 96, '','shuoShuo author img', array()) ?>
                            </div>
                            <div class="shuoshuo-author-name">
                                <?php echo get_the_author_meta( 'display_name' ) ?>
                            </div>
                            <div class="shuoshuo-comment-count">
                                <i class="fa-regular fa-comments"></i> <?php comments_number('0', '1', '%') ?>
                            </div>
                            <div class="shuoshuo-date">
                                <i class="fa-regular fa-clock"></i> <?php the_time('Y-m-d H:i'); ?>
                            </div>
                            <div class="shuoshuo-more">
                                <a href="<?php the_permalink(); ?>">
                                    <i class="fa-solid fa-angles-right fa-beat"></i> <?php _e('View Idea','sakurairo') ?>
                                </a>
                            </div>
                        </div>
                        <div class="shuoshuo-feather">
                            <i class="fa-solid fa-feather fa-flip-horizontal fa-2xl"></i>
                        </div>
                    </li>
                <?php endwhile; ?>
                <?php wp_reset_postdata(); ?>
            </ul>
        <?php else : ?>
            <h3 style="text-align: center;">
                <?php _e('You have not posted a comment yet', 'sakurairo') ?>
            </h3>
            <p style="text-align: center;">
                <?php _e('Go and post your first comment now', 'sakurairo') ?>
            </p>
        <?php endif; ?>
    </div>  
    </main><!-- #main -->
    <?php if (iro_opt('pagenav_style') == 'ajax') { ?>
        <div id="pagination">
            <?php next_posts_link(__('Load More', 'sakurairo'), $shuoshuo_query->max_num_pages); ?>
        </div>
        <div id="add_post">
            <span id="add_post_time" style="visibility: hidden;" title="<?php echo iro_opt('page_auto_load', ''); ?>"></span>
        </div>
    <?php } else { ?>
        <nav class="navigator">
            <?php previous_posts_link('<i class="fa-solid fa-angle-left"></i>') ?>
            <?php next_posts_link('<i class="fa-solid fa-angle-right"></i>', $shuoshuo_query->max_num_pages) ?>
        </nav>
    <?php } ?>
</div>
<?php get_footer(); ?>
/*说说模板样式-起*/

#shuoshuo_post {
    display: flex;
    flex-direction: column;
    max-width: 100%;
    height: 400px;
    margin-bottom: 32px;
    padding: 20px;
    border: 3px solid var(--shuoshuo_background_color1);
    box-shadow: -4px 4px 0px 0px var(--shuoshuo_background_color2);
    background: linear-gradient(to bottom right, var(--shuoshuo_background_color1), var(--shuoshuo_background_color2));
    transition: all 0.5s ease-in-out;
} 

#shuoshuo_post:hover {
    box-shadow: 0 0 20px 2px var(--shuoshuo_background_color2);
    transition: all 0.5s ease-in-out;
}

#shuoshuo_post:nth-child(even) {
    border: 3px solid var(--shuoshuo_background_color2);
    box-shadow: -4px 4px 0px 0px var(--shuoshuo_background_color1);
    background: linear-gradient(to bottom right, var(--shuoshuo_background_color2), var(--shuoshuo_background_color1));
    transition: all 0.5s ease-in-out;
} 

#shuoshuo_post:nth-child(even):hover {
    box-shadow: 0 0 20px 2px var(--shuoshuo_background_color1);
    transition: all 0.5s ease-in-out;
}

.shuoshuo-content {
    display: flex;
    height: 355px;
}

#shuoshuo_post:nth-child(even) .shuoshuo-content {
    flex-direction: row-reverse;
}

.shuoshuo-text {
    display: flex;
    flex-direction: column;
    width: 30%;
    height: 355px;
    margin-right: 15px;
    padding: 10px;
    border: 2px solid var(--shuoshuo_background_color1);
}

#shuoshuo_post:nth-child(even) .shuoshuo-text {
    margin: 0 0 0 15px;
    border: 2px solid var(--shuoshuo_background_color2);
}

.shuoshuo-title {
    flex-shrink: 0;
    font-size: 1rem;
    line-height: 2rem;
    text-align: center;
    margin-bottom: 12px;
    max-height: 150px;
    overflow: hidden;
}

.shuoshuo-title h2 {
    margin: 0;
}

.shuoshuo-title h2::before {
    display: none;
}

.shuoshuo-body::-webkit-scrollbar {
    width: 1px;
}

.shuoshuo-body::-webkit-scrollbar-thumb, #shuoshuo_post:nth-child(even) .shuoshuo-body::-webkit-scrollbar-track {
    background-color: var(--shuoshuo_background_color1);
}

.shuoshuo-body::-webkit-scrollbar-track, #shuoshuo_post:nth-child(even) .shuoshuo-body::-webkit-scrollbar-thumb {
    background-color: var(--shuoshuo_background_color2);
}

.shuoshuo-body {
    flex-grow: 1;
    overflow-y: auto;
    overflow-x: overlay;
}

.shuoshuo-body p {
    margin: 0 0 0.5rem;
    word-break: break-all;
}

.shuoshuo-images {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-around;
    align-items: center;
    width: 70%;
    height: 355px;
    padding: 0.6%;
    border: 2px solid var(--shuoshuo_background_color1);
    overflow: hidden;
}

#shuoshuo_post:nth-child(even) .shuoshuo-images {
    border: 2px solid var(--shuoshuo_background_color2);
}

.shuoshuo-images span {
    display: block;
    overflow: hidden;
}

.shuoshuo-images img {
    object-fit: cover;
    object-position: center;
    height: 100%;
    margin: 0;
    padding: 0;
    width: 100%;
    transition: all 0.3s ease-in-out;
}

.shuoshuo-images img:hover {
    transform: scale(1.1);
    transition: all 0.3s ease-in-out;
}

.shuoshuo-images .image-full {
    width: 100%;
    height: 100%;
}

.shuoshuo-images .image-four {
    width: 49.2%;
    height: 49.2%;
}

.shuoshuo-images .image-four:nth-child(1) {
    margin: 0 0.3% 0.3% 0;
}

.shuoshuo-images .image-four:nth-child(2) {
    margin: 0 0 0.3% 0.3%;
}

.shuoshuo-images .image-four:nth-child(3) {
    margin: 0.3% 0.3% 0 0;
}

.shuoshuo-images .image-four:nth-child(4) {
    margin: 0.3% 0 0 0.3%;
}

.shuoshuo-images .image-three {
    width: 49.2%;
    height: 55%;
}

.shuoshuo-images .image-three:last-child {
    width: 100%;
    height: 44%;
}

.shuoshuo-images .image-three:nth-child(1) {
    margin: 0 0.3% 0.3% 0;
}

.shuoshuo-images .image-three:nth-child(2) {
    margin: 0 0 0.3% 0.3%;
}

.shuoshuo-images .image-three:nth-child(3) {
    margin: 0.3% 0 0 0;
}

.shuoshuo-images .image-two {
    width: 49.2%;
    height: 100%
}

.shuoshuo-images .image-two:nth-child(1) {
    margin-right: 0.3%;
}

.shuoshuo-images .image-two:nth-child(2) {
    margin-left: 0.3%;
}

.shuoshuo-meta {
    display: flex;
    align-items: center;
    justify-content: right;
    font-size: 12px;
    padding: 0 0 0 30px;
}

#shuoshuo_post:nth-child(even) .shuoshuo-meta {
    justify-content: left;
    padding: 0px 30px 0 0;
}

.shuoshuo-author-image {
    height: 16px;
    width: 16px;
    margin-right: 5px;
}

.shuoshuo-author-name, .shuoshuo-comment-count, .shuoshuo-date {
    margin-right: 10px;
}

.shuoshuo-more a {
    color: currentColor;
}

.shuoshuo-author-image img {
    height: 100%;
    width: auto;
}

.shuoshuo-feather {
    display: flex;
    position: relative;
    left: -18px;
    top: -25px;
    font-size: 24px;
}

.shuoshuo-feather i {
    color: var(--shuoshuo_background_color1)
}

#shuoshuo_post:nth-child(even) .shuoshuo-feather {
    flex-direction: row-reverse;
    left: auto;
    right: -18px;
}

#shuoshuo_post:nth-child(even) .shuoshuo-feather i {
    transform: scaleY(1);
    color: var(--shuoshuo_background_color2)
}

body.dark #shuoshuo_post {
    color: #505050;
}

@media (max-width: 700px) {
    #shuoshuo_post {
        padding-bottom: 0;
        height: auto;
    }

    .shuoshuo-content,#shuoshuo_post:nth-child(even) .shuoshuo-content {
        flex-direction: column;
        height: auto;
    }

    .shuoshuo-text, #shuoshuo_post:nth-child(even) .shuoshuo-text {
        width: 100%;
        height: auto;
        margin: 0 0 15px 0;
        border: none;
    }

    .shuoshuo-images, #shuoshuo_post:nth-child(even) .shuoshuo-images {
        aspect-ratio: 4/3;
        width: 100%;
        height: auto;
    }

    .shuoshuo-meta {
        justify-content: left;
        padding: 0 30px 0 0;
        flex-wrap: wrap;
    }

    .shuoshuo-feather {
        flex-direction: row-reverse;
        left: auto;
        right: -18px;
    }

    .shuoshuo-feather i {
        transform: scaleY(1);
    }
}

/*说说模板样式-止*/

代码解析

说说标题

<div class="shuoshuo-title">
    <?php the_title('<h2>', '</h2>') ?>
</div>

the_title('<h2>', '</h2>')函数会获取每篇说说的标题,并自动添加二级标题标签。从SEO优化的角度上来看,一个页面最好只有一个一级标题,所以这里选择了应用二级标题。

说说内容

值得一提的是,在设计上,说说的内容分为两个部分:文本内容、图片。换句话说,只支持输出纯文本内容和图片。鉴于视频播放的各种千奇百怪实现方式,把它们输出到说说页面上,需要做的适配性工作太多了,故一刀切,只显示文本和图片。

输出文本

<div class="shuoshuo-body">
    <p><?php echo strip_tags(get_the_content()) ?></p>
</div>

上面的代码,是输出说说内容之一的文本内容,说说里面任何HTML标签都会被移除。有一个需要注意的地方是,get_the_content()函数不会应用the_content过滤器,这意味着你挂载在the_content钩子上的任何函数都不会生效,会导致一些诸如纯文本替换、表情实现等通过后端实现的功能失效。

如果你有上诉需求,可以修改为下面的代码,以应用the_content过滤器。

<div class="shuoshuo-body">
    <?php 
        $shuoshuo_content = apply_filters( 'the_content', get_the_content() );
        echo strip_tags($shuoshuo_content) 
    ?>
</div>

输出图片

preg_match_all('/<img[^>]+\/>/i', get_the_content(), $shuoshuo_images);
$shuoshuo_images_count = count($shuoshuo_images[0]);

使用preg_match_all函数提取说说内容里面的所有图片,存储在数组中,并获取图片总数量。正则表达式/<img[^>]+\/>/i会匹配说说内容里的所有<img>标签。

switch($shuoshuo_images_count) {
    case 1:
        $image_html_list = '<span class="image-full">'.$shuoshuo_images[0][0].'</span>';
        break;
    case 2:
        $image_html_list = '<span class="image-two">'.$shuoshuo_images[0][0].'</span>';
        $image_html_list.= '<span class="image-two">'.$shuoshuo_images[0][1].'</span>';
        break;
    case 3:
        $image_html_list = '<span class="image-three">'.$shuoshuo_images[0][0].'</span>';
        $image_html_list .= '<span class="image-three">'.$shuoshuo_images[0][1].'</span>';
        $image_html_list .= '<span class="image-three">'.$shuoshuo_images[0][2].'</span>';
        break;
    default :
        $image_html_list = '<span class="image-four">'.$shuoshuo_images[0][0].'</span>';
        $image_html_list .= '<span class="image-four">'.$shuoshuo_images[0][1].'</span>';
        $image_html_list .= '<span class="image-four">'.$shuoshuo_images[0][2].'</span>';
        $image_html_list .= '<span class="image-four">'.$shuoshuo_images[0][3].'</span>';
        break;
}

从样式美观的角度上考虑,同时也为了减少工作量,这里设计了最多显示4张图片。如果说说内容里的图片大于4张。则只会显示前4张图片。

else {
    $image_html_list = '<span class="image-full"><img src="' . DEFAULT_FEATURE_IMAGE() . '"/></span>';       
}

如果说说内容里没有图片,为了保证样式的同一,会从与首页封面图片相同的来源加载一张图片用作装饰。

function DEFAULT_FEATURE_IMAGE(string $size='source'):string
{
    if (iro_opt('post_cover_options') == 'type_2') {
        return get_random_url(iro_opt('post_cover'));
    }
    if (iro_opt('random_graphs_options') == 'external_api'){
        return get_random_url(iro_opt('random_graphs_link'));
    }
    $_api_url = rest_url('sakura/v1/image/feature');
    $rand = rand(1, 100);
    # 拼接符
    $splice = strpos($_api_url, 'index.php?') !== false ? '&' : '?';
    $_api_url = "{$_api_url}{$splice}size={$size}&$rand";
    return $_api_url;
}

关于DEFAULT_FEATURE_IMAGE()函数的更多内容,可以看看上边的函数原型。

remove_filter( 'the_content', 'wpautop' );
$image_html_list = apply_filters( 'the_content', $image_html_list );
echo $image_html_list;

最后是对构建好的图片内容使用the_content过滤器,主要用于图片灯箱的支持。别忘了在应用the_content过滤器之前移除wpautop函数,它会在内容中自动添加<p>标签,这会造成样式错误。

说说元数据

包括:作者头像、作者名称、评论数量、发布时间和“查看说说”超链接,采用fontawesome 图标装饰。

<div class="shuoshuo-meta">
    <div class="shuoshuo-author-image">
        <?php echo get_avatar(get_the_author_meta('ID'), 96, '','shuoShuo author img', array()) ?>
    </div>
    <div class="shuoshuo-author-name">
        <?php echo get_the_author_meta( 'display_name' ) ?>
    </div>
    <div class="shuoshuo-comment-count">
        <i class="fa-regular fa-comments"></i> <?php comments_number('0', '1', '%') ?>
    </div>
    <div class="shuoshuo-date">
        <i class="fa-regular fa-clock"></i> <?php the_time('Y-m-d H:i'); ?>
    </div>
    <div class="shuoshuo-more">
        <a href="<?php the_permalink(); ?>">
            <i class="fa-solid fa-angles-right fa-beat"></i> <?php _e('View Idea','sakurairo') ?>
        </a>
    </div>
</div>

一个装饰品

image-20231120200148723

《蒸汽鸟报》页面中采用了一个相机作为饰品,我搜寻好久,没有找到合适的相机样式。几经辗转,找到了一个看起来还可以的,但是SVG格式需要付费下载,我付不起。没有SVG格式的图片,不好进行颜色自适应更改,遂放弃。

看电影的时候突然找到了灵感:一支羽毛制成的笔,意为记录时间。

使用方法

不知道这个样式是否会被主题采纳,现阶段你可以通过以下方法应用它。

  1. 将主题page-word.php文件里的代码全部替换为前述的页面模板代码

  2. 在主题style.css文件里的末尾加入前述的CSS代码

  3. 删除style.css文件里下面内容:

    .cbp_tmtimeline:before {
       content: '';
       position: absolute;
       top: 0;
       bottom: 0;
       width: 4px;
       background: RGBA(0, 0, 0, 0.02);
       left: 80px;
       margin-left: 10px;
    }

从节省网络资源的角度上考虑,你应该还需删除旧的说说页面样式,具体的删除内容,请参考我的github推送

この素晴らしい世界に祝福を!
最后更新于 2023-11-28