16.主题魔改:文章顶图根据封面图片自动配色

16.主题魔改:文章顶图根据封面图片自动配色

前言:功能介绍与【重要前提】

本指南将引导您实现一个高级功能:自动提取您每篇文章封面图的主色调,并将其作为文章页面顶部的背景色,从而实现图片与背景的完美融合,提升页面的沉浸感和设计感。同时,这个修改也会优化文章封面的SEO。

警告与重要前提:
这是一项“魔改”操作,并且有一个非常重要的**【硬性要求】:您的图片必须托管在支持“图片主色调提取API”的云存储服务上。
本教程提供的代码是为【七牛云】的 ?imageAve 接口量身定做的。
如果您使用其他图床(如GitHub、本地存储、普通CDN),这段代码将
无法工作**,除非您能找到并替换为您的图床提供的类似颜色提取API。


第一步:修改核心头图布局文件

这次修改的主要目的是将原来用作背景的图片,改为一个标准的 <img> 标签。这样做对SEO更友好,也方便我们的JS脚本获取图片地址来调用API。

  1. 找到目标文件
    themes/anzhiyu/layout/includes/header/index.pug

  2. 替换内容:将这个文件的全部内容,用下面提供的完整代码进行覆盖。

    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
    //- 替换为新的 header/index.pug 代码
    if !theme.disable_top_img && page.top_img !== false
    if is_post()
    - var top_img = page.top_img || page.cover
    else if is_page()
    - var top_img = page.top_img || theme.default_top_img
    else if is_home()
    - var top_img = theme.index_img === false ? false : theme.index_img || theme.default_top_img
    else
    - var top_img = page.top_img || theme.default_top_img
    if top_img !== false
    - var imgSource = top_img && top_img.indexOf('/') !== -1 ? url_for(top_img) : top_img
    - var site_title = page.title || page.tag || page.category || config.title
    - var isHomeClass = is_home() ? 'full_page' : 'not-home-page'
    - is_post() ? isHomeClass = 'post-bg' : isHomeClass
    else
    - var isHomeClass = 'not-top-img'
    else
    - var top_img = false
    - var isHomeClass = 'not-top-img'

    header#page-header(class=isHomeClass)
    //- 新增的 img 标签
    if top_img !== false && is_post()
    img#post-cover(src=url_for(top_img) alt='cover')

    !=partial('includes/header/nav', {}, {cache:theme.fragment_cache})
    if top_img !== false
    if is_post()
    include ./post-info.pug
    else if is_home()
    #site-info
    h1#site-title=site_title
    #site-subtitle
    span#subtitle
    if(theme.social)
    #site_social_icons
    !=fragment_cache('social', function(){return partial('includes/header/social')})
    #scroll-down
    i.fas.fa-angle-down.scroll-down-effects
    else
    #page-site-info(style=`background-image: url(${imgSource})`)
    h1#site-title=site_title

    (注:这是一个简化和兼容性调整后的版本,以确保核心功能实现)


第二步:添加自定义样式与脚本
  1. 创建CSS文件

    • themes/anzhiyu/source/css/ 目录下,新建一个文件,命名为 image-color.css
    • 将下面的CSS代码完整复制进去
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    /* 确保新的 post-cover 图片能作为背景正常显示 */
    .post-bg #post-cover {
    position: absolute; /* 添加绝对定位以作为背景 */
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    z-index: -1; /* 将其置于内容下方 */
    }

    /* page-header 的 ::before 伪元素将用来显示提取出的主色调背景 */
    #page-header::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: transparent; /* 默认透明 */
    z-index: -2; /* 在图片下方 */
    transition: background 0.5s;
    }
  2. 创建JS文件

    • themes/anzhiyu/source/js/ 目录下,新建一个文件,命名为 image-color.js
    • 将下面的JavaScript代码完整复制进去
    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
    function getCoverColor() {
    // 只在文章页面执行
    if (!document.getElementById("post-cover")) return;

    var path = document.getElementById("post-cover").src;

    // 【重要】请将这里的网址替换为您自己的域名,用于排除不想变色的页面(例如首页)
    if (path && path !== 'https://your-domain.com/null') {
    // 【重要】这里的 ?imageAve 是七牛云的API,如果您用其他服务,需要修改这里
    var httpRequest = new XMLHttpRequest();
    httpRequest.open('GET', path + '?imageAve', true);
    httpRequest.send();
    httpRequest.onreadystatechange = function () {
    if (httpRequest.readyState == 4 && httpRequest.status == 200) {
    var json = httpRequest.responseText;
    var obj = JSON.parse(json); // 使用 JSON.parse 代替 eval
    var value = "#" + obj.RGB.slice(2);

    // 通过注入CSS规则的方式来改变背景色
    try {
    document.styleSheets[0].insertRule('#page-header:before { background: ' + value + '!important; }', 0);
    } catch (e) {
    // 兼容性处理
    let style = document.createElement('style');
    style.innerHTML = '#page-header:before { background: ' + value + '!important; }';
    document.head.appendChild(style);
    }
    }
    };
    } else {
    // 如果没有封面图,确保背景是透明的
    try {
    document.styleSheets[0].insertRule('#page-header:before { background: none !important; }', 0);
    } catch (e) {
    let style = document.createElement('style');
    style.innerHTML = '#page-header:before { background: none !important; }';
    document.head.appendChild(style);
    }
    }
    }

    // 兼容Pjax
    document.addEventListener('DOMContentLoaded', getCoverColor);
    document.addEventListener('pjax:success', getCoverColor);

第三步:在主题配置中注入新文件
  1. 打开主题配置文件 (themes/anzhiyu/_config.yml)。
  2. 找到 inject: 配置项,添加对我们新建的CSS和JS文件的引用。
    1
    2
    3
    4
    5
    6
    7
    inject:
    head:
    # - 其他 head 内容
    - '<link rel="stylesheet" href="/css/image-color.css">'
    bottom:
    # - 其他 bottom 内容
    - '<script src="/js/image-color.js"></script>'

最后一步:验证
保存所有修改后,运行 hexo clean && hexo g && hexo s。现在,当您打开一篇设置了封面图 (cover) 的文章时,如果您的图片托管在支持此API的图床上,页面顶部的背景色应该会自动变为与图片主色调相匹配的颜色。