Hexo博客优化之Next主题美化

前言

有了前面几篇博客的介绍,我们就可以很容易的搭建我们的博客了,不过既然是属于自己的博客网站,自然也就想让其更加美观,更有意思,所以呢我下面介绍一下Hexo博客的主题美化操作。

Hexo博客支持很多主题风格,其中Next主题是Github上Star最多的主题,其一直在更新维护,支持非常多的外部插件和功能选项。我目前使用的是NexT.Gemini v7.1.1版本,下面我会介绍基于Next7主题的界面美化。

命名

在Hexo中有2份主要的配置文件,其名称都是_config.yml。 其中,一份位于博客根目录下,主要包含 Hexo 本身的配置;另一份位于themes/next/目录下,用于配置主题相关的选项。

  • 博客配置文件:博客根目录下_config.yml
  • 主题配置文件:themes/next/目录下_config.yml

基础设置

##设置站点名、作者昵称和站点描述等内容
打开博客配置文件,博客根目录下_config.yml

1
2
3
4
5
6
7
8
# Site
title: Vicの博客
subtitle: 测试攻城狮
description: 人生苦短,我学Python
keywords:
author: Vic
language: zh-CN
timezone: Asia/Shanghai

Next主题的安装配置

Next主题的安装方式很简单,只需要在博客根目录下执行:

1
git clone https://github.com/theme-next/hexo-theme-next themes/next

然后设置博客配置文件_config.yml:(博客根目录下的_config.yml)

1
theme: next

即可将我们的Hexo博客主题替换为Next主题。

主题配置

Next主题风格

打开themes/next/下的_config.yml,查找scheme,可以看到如下四种不同的风格方案:

1
2
3
4
#scheme: Muse
#scheme: Mist
#scheme: Pisces
scheme: Gemini

去掉#注释,即启用对应的scheme,博主采用Gemini主题。

设置菜单及对应页面

  • 打开themes/next/下的_config.yml,查找menu

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    menu:
    home: / || home
    about: /about/ || user
    tags: /tags/ || tags
    categories: /categories/ || th
    archives: /archives/ || archive
    #schedule: /schedule/ || calendar
    #sitemap: /sitemap.xml || sitemap
    #commonweal: /404/ || heartbeat
    favorite: /favorite/ || fa-star

    去掉#注释即可显示对应的菜单项,也可自定义新的菜单项。||之前的值是目标链接,之后的是分类页面的图标,图标名称来自于FontAwesome icon。若没有配置图标,默认会使用问号图标。
    例如上面添加:favorite: /favorite/ || fa-star

  • 新建一个页面,命名为 categories

    1
    hexo new page "favorite"

    此时在根目录的source文件夹下会生成一个favorite文件夹,文件中有一个index.md文件,文件内容修改增加 type 属性

    1
    2
    3
    4
    5
    ---
    title: Favorite
    date: 2019-05-20 19:11:41
    type: "favorite"
    ---
  • 新添加的菜单需要翻译对应的中文
    打开hexo/theme/next/languages/zh-CN.yml,在menu下自定义,如:

    1
    2
    menu:
    favorite: 收藏夹

一般配置

  • Next主题一般配置:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    override:false #表示是否将主题置为默认样式
    cache:
    enable:true #表示添加缓存功能,这样浏览器后续打开我们的博客网站会更快
    menu: #设置博客各个页面的相对路径,默认根路径是blog/source
    home: / || home
    about: /about/ || user
    tags: /tags/ || tags
    categories: /categories/ || th
    archives: /archives/ || archive
    #schedule: /schedule/ || calendar #日历
    #sitemap: /sitemap.xml || sitemap #站点地图,供搜索引擎爬取
    #commonweal: /404/ || heartbeat # 腾讯公益404

    # Enable/Disable menu icons / item badges.
    menu_settings:
    icons: true # 是否显示各个页面的图标
    badges: true # 是否显示分类/标签/归档页的内容量
    # Schemes
    scheme: Gemini
  • 站点配置MyBlog/_config.yml文件的基本配置为

    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
    # Hexo Configuration
    ## Docs: https://hexo.io/docs/configuration.html
    ## Source: https://github.com/hexojs/hexo/

    # Site
    title: Vicの博客 # 网站标题
    subtitle: 测试攻城狮 # 网站子标题
    description: 人生苦短,我学Python # 网站描述
    keywords:
    author: Vic # 网站作者,也就是您的名字
    language: zh-CN # 网站使用的语言
    timezone: Asia/Shanghai # 网站时区。Hexo 预设使用您电脑的时区。

    # URL
    ## If your site is put in a subdirectory, set url as 'http://yoursite.com/child' and root as '/child/'
    url: https://vic.kim
    root: /
    permalink: :year/:month/:day/:title/
    permalink_defaults:

    # Directory
    source_dir: source # 资源文件夹,这个文件夹用来存放内容,例如我们用markdown编写的博文
    public_dir: public # 公共文件夹,这个文件夹用于存放生成的静态博客文件。
    tag_dir: tags # 标签文件夹
    archive_dir: archives # 归档文件夹
    category_dir: categories # 分类文件夹
    code_dir: downloads/code # Include code 文件夹
    i18n_dir: :lang # 国际化(i18n)文件夹
    skip_render: # 跳过指定文件的渲染,您可使用 glob 来配置路径。

    # Search
    search:
    path: search.xml # 索引文件的路径,相对于站点根目录
    field: post # 搜索范围,默认是 post,还可以选择 page、all,设置成 all 表示搜索所有页面
    format: html
    limit: 10000 # 限制搜索的条目数

    # Writing
    new_post_name: :title.md # 默认的新博文名称
    default_layout: post # 默认布局
    titlecase: false # 把标题转换为 titlecase(titlecase指的是将每个单词首字母转换成大写)
    external_link: true # 在新标签中打开链接
    filename_case: 0 #把文件名称转换为 (1) 小写或 (2) 大写, 0表示不变
    render_drafts: false # 是否显示草稿
    post_asset_folder: true #是否启用资源文件夹(用来存放相对路径图片或文件)
    relative_link: false # 把链接改为与根目录的相对位址
    future: true
    highlight:
    enable: true #是否开启代码高亮
    line_number: false #是否增加代码行号
    auto_detect: false #自动判断代码语言
    tab_replace:

    # 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: 10 #每页博客数量上限
    order_by: -date #博客排序

    # Category & Tag
    default_category: uncategorized # 默认分类, uncategorized表示未分类
    category_map: # 分类别名
    tag_map: # 标签别名

    # Date / Time format
    ## Hexo uses Moment.js to parse and display date
    ## You can customize the date format as defined in
    ## http://momentjs.com/docs/#/displaying/format/
    date_format: YYYY-MM-DD #博客日期格式
    time_format: HH:mm:ss #博客时间格式

    # Pagination
    ## Set per_page to 0 to disable pagination
    per_page: 10 # 每页显示的文章量,如果设置值为0,则表示禁止分页
    pagination_dir: page # 分页目录

    # Extensions
    ## Plugins: https://hexo.io/plugins/
    ## Themes: https://hexo.io/themes/
    theme: next #选择博客主题,名字为themes中选择的主题文件夹名称

    # Deployment
    ## Docs: https://hexo.io/docs/deployment.html
    deploy:
    type: git
    repo: https://github.com/HappyVic/HappyVic.github.io
    branch: master

    # hexo-tag-cloud
    tag_cloud:
    textFont: Trebuchet MS, Helvetica
    textColor: '#333'
    textHeight: 25
    outlineColor: '#E2E1D1'
    maxSpeed: 0.1

美化

设置头像

找自己喜欢的图,放至themes/next/source/images/文件夹下
打开themes/next/下的_config.yml,查找Sidebar Avatar。修改url的值

1
2
3
4
# Sidebar Avatar
# in theme directory(source/images): /images/avatar.gif
# in site directory(source/uploads): /uploads/avatar.gif
url: /images/smile.jpg

url的值是图片的链接地址

网站图标设置

我们博客的默认图标是H,不过Next支持修改图标

  • 图标素材网站:easyiconiconfont
  • 下载16x16以及32x32大小的PNG格式图标,置于/themes/next/source/images/
  • 打开themes/next/下的_config.yml,查找favicon

    1
    2
    3
    4
    5
    6
    7
    favicon:
    small: /images/cat-16x16-next.png
    medium: /images/cat-32x32-next.png
    apple_touch_icon: /images/apple-touch-icon-next.png
    safari_pinned_tab: /images/logo.svg
    #android_manifest: /images/manifest.json
    #ms_browserconfig: /images/browserconfig.xml

    修改small和medium的路径为下载的图标路径

鼠标点击特效

  • 鼠标点击红心特效
    /themes/next/source/js/src下新建文件 clicklove.js,接着把下面的代码拷贝粘贴到clicklove.js文件中:

    1
    !function(e,t,a){function n(){c(".heart{width: 10px;height: 10px;position: fixed;background: #f00;transform: rotate(45deg);-webkit-transform: rotate(45deg);-moz-transform: rotate(45deg);}.heart:after,.heart:before{content: '';width: inherit;height: inherit;background: inherit;border-radius: 50%;-webkit-border-radius: 50%;-moz-border-radius: 50%;position: fixed;}.heart:after{top: -5px;}.heart:before{left: -5px;}"),o(),r()}function r(){for(var e=0;e<d.length;e++)d[e].alpha<=0?(t.body.removeChild(d[e].el),d.splice(e,1)):(d[e].y--,d[e].scale+=.004,d[e].alpha-=.013,d[e].el.style.cssText="left:"+d[e].x+"px;top:"+d[e].y+"px;opacity:"+d[e].alpha+";transform:scale("+d[e].scale+","+d[e].scale+") rotate(45deg);background:"+d[e].color+";z-index:99999");requestAnimationFrame(r)}function o(){var t="function"==typeof e.onclick&&e.onclick;e.onclick=function(e){t&&t(),i(e)}}function i(e){var a=t.createElement("div");a.className="heart",d.push({el:a,x:e.clientX-5,y:e.clientY-5,scale:1,alpha:1,color:s()}),t.body.appendChild(a)}function c(e){var a=t.createElement("style");a.type="text/css";try{a.appendChild(t.createTextNode(e))}catch(t){a.styleSheet.cssText=e}t.getElementsByTagName("head")[0].appendChild(a)}function s(){return"rgb("+~~(255*Math.random())+","+~~(255*Math.random())+","+~~(255*Math.random())+")"}var d=[];e.requestAnimationFrame=function(){return e.requestAnimationFrame||e.webkitRequestAnimationFrame||e.mozRequestAnimationFrame||e.oRequestAnimationFrame||e.msRequestAnimationFrame||function(e){setTimeout(e,1e3/60)}}(),n()}(window,document);

    \themes\next\layout\_layout.swig文件末尾添加:

    1
    2
    <!-- 页面点击小红心 -->
    <script type="text/javascript" src="/js/src/clicklove.js"></script>
  • 爆炸红心特效(比较花里胡哨不推荐)
    themes/next/source/js/src里面建一个fireworks.js的文件,接着把下面的代码拷贝粘贴到fireworks.js文件中:

    1
    "use strict";function updateCoords(e){pointerX=(e.clientX||e.touches[0].clientX)-canvasEl.getBoundingClientRect().left,pointerY=e.clientY||e.touches[0].clientY-canvasEl.getBoundingClientRect().top}function setParticuleDirection(e){var t=anime.random(0,360)*Math.PI/180,a=anime.random(50,180),n=[-1,1][anime.random(0,1)]*a;return{x:e.x+n*Math.cos(t),y:e.y+n*Math.sin(t)}}function createParticule(e,t){var a={};return a.x=e,a.y=t,a.color=colors[anime.random(0,colors.length-1)],a.radius=anime.random(16,32),a.endPos=setParticuleDirection(a),a.draw=function(){ctx.beginPath(),ctx.arc(a.x,a.y,a.radius,0,2*Math.PI,!0),ctx.fillStyle=a.color,ctx.fill()},a}function createCircle(e,t){var a={};return a.x=e,a.y=t,a.color="#F00",a.radius=0.1,a.alpha=0.5,a.lineWidth=6,a.draw=function(){ctx.globalAlpha=a.alpha,ctx.beginPath(),ctx.arc(a.x,a.y,a.radius,0,2*Math.PI,!0),ctx.lineWidth=a.lineWidth,ctx.strokeStyle=a.color,ctx.stroke(),ctx.globalAlpha=1},a}function renderParticule(e){for(var t=0;t<e.animatables.length;t++){e.animatables[t].target.draw()}}function animateParticules(e,t){for(var a=createCircle(e,t),n=[],i=0;i<numberOfParticules;i++){n.push(createParticule(e,t))}anime.timeline().add({targets:n,x:function(e){return e.endPos.x},y:function(e){return e.endPos.y},radius:0.1,duration:anime.random(1200,1800),easing:"easeOutExpo",update:renderParticule}).add({targets:a,radius:anime.random(80,160),lineWidth:0,alpha:{value:0,easing:"linear",duration:anime.random(600,800)},duration:anime.random(1200,1800),easing:"easeOutExpo",update:renderParticule,offset:0})}function debounce(e,t){var a;return function(){var n=this,i=arguments;clearTimeout(a),a=setTimeout(function(){e.apply(n,i)},t)}}var canvasEl=document.querySelector(".fireworks");if(canvasEl){var ctx=canvasEl.getContext("2d"),numberOfParticules=30,pointerX=0,pointerY=0,tap="mousedown",colors=["#FF1461","#18FF92","#5A87FF","#FBF38C"],setCanvasSize=debounce(function(){canvasEl.width=2*window.innerWidth,canvasEl.height=2*window.innerHeight,canvasEl.style.width=window.innerWidth+"px",canvasEl.style.height=window.innerHeight+"px",canvasEl.getContext("2d").scale(2,2)},500),render=anime({duration:1/0,update:function(){ctx.clearRect(0,0,canvasEl.width,canvasEl.height)}});document.addEventListener(tap,function(e){"sidebar"!==e.target.id&&"toggle-sidebar"!==e.target.id&&"A"!==e.target.nodeName&&"IMG"!==e.target.nodeName&&(render.play(),updateCoords(e),animateParticules(pointerX,pointerY))},!1),setCanvasSize(),window.addEventListener("resize",setCanvasSize,!1)}"use strict";function updateCoords(e){pointerX=(e.clientX||e.touches[0].clientX)-canvasEl.getBoundingClientRect().left,pointerY=e.clientY||e.touches[0].clientY-canvasEl.getBoundingClientRect().top}function setParticuleDirection(e){var t=anime.random(0,360)*Math.PI/180,a=anime.random(50,180),n=[-1,1][anime.random(0,1)]*a;return{x:e.x+n*Math.cos(t),y:e.y+n*Math.sin(t)}}function createParticule(e,t){var a={};return a.x=e,a.y=t,a.color=colors[anime.random(0,colors.length-1)],a.radius=anime.random(16,32),a.endPos=setParticuleDirection(a),a.draw=function(){ctx.beginPath(),ctx.arc(a.x,a.y,a.radius,0,2*Math.PI,!0),ctx.fillStyle=a.color,ctx.fill()},a}function createCircle(e,t){var a={};return a.x=e,a.y=t,a.color="#F00",a.radius=0.1,a.alpha=0.5,a.lineWidth=6,a.draw=function(){ctx.globalAlpha=a.alpha,ctx.beginPath(),ctx.arc(a.x,a.y,a.radius,0,2*Math.PI,!0),ctx.lineWidth=a.lineWidth,ctx.strokeStyle=a.color,ctx.stroke(),ctx.globalAlpha=1},a}function renderParticule(e){for(var t=0;t<e.animatables.length;t++){e.animatables[t].target.draw()}}function animateParticules(e,t){for(var a=createCircle(e,t),n=[],i=0;i<numberOfParticules;i++){n.push(createParticule(e,t))}anime.timeline().add({targets:n,x:function(e){return e.endPos.x},y:function(e){return e.endPos.y},radius:0.1,duration:anime.random(1200,1800),easing:"easeOutExpo",update:renderParticule}).add({targets:a,radius:anime.random(80,160),lineWidth:0,alpha:{value:0,easing:"linear",duration:anime.random(600,800)},duration:anime.random(1200,1800),easing:"easeOutExpo",update:renderParticule,offset:0})}function debounce(e,t){var a;return function(){var n=this,i=arguments;clearTimeout(a),a=setTimeout(function(){e.apply(n,i)},t)}}var canvasEl=document.querySelector(".fireworks");if(canvasEl){var ctx=canvasEl.getContext("2d"),numberOfParticules=30,pointerX=0,pointerY=0,tap="mousedown",colors=["#FF1461","#18FF92","#5A87FF","#FBF38C"],setCanvasSize=debounce(function(){canvasEl.width=2*window.innerWidth,canvasEl.height=2*window.innerHeight,canvasEl.style.width=window.innerWidth+"px",canvasEl.style.height=window.innerHeight+"px",canvasEl.getContext("2d").scale(2,2)},500),render=anime({duration:1/0,update:function(){ctx.clearRect(0,0,canvasEl.width,canvasEl.height)}});document.addEventListener(tap,function(e){"sidebar"!==e.target.id&&"toggle-sidebar"!==e.target.id&&"A"!==e.target.nodeName&&"IMG"!==e.target.nodeName&&(render.play(),updateCoords(e),animateParticules(pointerX,pointerY))},!1),setCanvasSize(),window.addEventListener("resize",setCanvasSize,!1)};

    打开themes/next/layout/_layout.swig,在</body>上面写下如下代码:(注意和上面的对其)

    1
    2
    3
    4
    5
    {% if theme.fireworks %}
    <canvas class="fireworks" style="position: fixed;left: 0;top: 0;z-index: 1; pointer-events: none;" ></canvas>
    <script type="text/javascript" src="//cdn.bootcss.com/animejs/2.2.0/anime.min.js"></script>
    <script type="text/javascript" src="/js/src/fireworks.js"></script>
    {% endif %}

    打开主题配置文件,在文件末尾添加:(themes/next/下的_config.yml

    1
    2
    # Fireworks
    fireworks: true

背景动画(只能选一个)

Canvas-nest风格、JavaScript 3D library风格 动画只能选一个

  • Canvas-nest风格
    进入theme/next目录,执行以下命令

    1
    git clone https://github.com/theme-next/theme-next-canvas-nest source/lib/canvas-nest

    打开themes/next/下的_config.yml文件,搜索Canvas-nest,将canvas_nest的中enable值改为true即可

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # Canvas-nest
    # Dependencies: https://github.com/theme-next/theme-next-canvas-nest
    canvas_nest:
    enable: true
    onmobile: true # display on mobile or not
    color: "0,0,255" # RGB values, use ',' to separate
    opacity: 0.5 # the opacity of line: 0~1
    zIndex: -1 # z-index property of the background
    count: 99 # the number of lines
  • JavaScript 3D library风格
    进入theme/next目录,执行以下命令

    1
    git clone https://github.com/theme-next/theme-next-three source/lib/three

    打开themes/next/下的_config.yml文件,搜索theme-next-three,将想要的效果改为true即可:

    1
    2
    3
    4
    5
    6
    # three_waves
    three_waves: false
    # canvas_lines
    canvas_lines: true
    # canvas_sphere
    canvas_sphere: false

设置侧栏在左侧/右侧

打开themes/next/下的_config.yml,查找sidebar

  • Pisces或Gemini方案
    打开themes/next/下的_config.yml,查找sidebar,将想要的方案打开

    1
    2
    3
    sidebar:
    position: left
    #position: right
  • Mist或Muse方案
    打开next/source/js/src/motion.js,查找paddingRight,把所有(2个)PaddingRight更改为paddingLeft即可。
    打开next/source/css/_custom/custom.styl,添加如下内容:

    1
    2
    3
    4
    5
    6
    7
    8
    //侧边栏置于左侧
    .sidebar {
    left: 0;
    }
    //侧栏开关置于左侧
    .sidebar-toggle {
    left: $b2t-position-right;
    }

    打开next/source/css/_common/components/back-to-top.styl,将right: $b2t-position-right;改为left: $b2t-position-right;

显示侧边栏的时机

打开themes/next/下的_config.yml,查找sidebar

1
2
3
4
5
6
# Sidebar Display, available values (only for Muse | Mist):
# - post expand on posts automatically. Default.
# - always expand for all pages automatically.
# - hide expand only when click on the sidebar toggle icon.
# - remove totally remove sidebar including sidebar toggle.
display: post

文章末尾添加版权声明

打开themes/next/下的_config.yml,查找creative_commons

1
2
3
4
5
creative_commons:
license: by-nc-sa
sidebar: false
post: true # 将false改为true即可显示版权信息
language:

添加本地搜索功能

参考文章Hexo Next 主题中添加本地搜索功能

建立标签云及效果展示

参考文章Hexo博客建立标签云及效果展示

文章添加阴影、透明效果

打开theme/next/source/css/_custom/custom.styl,添加以下代码

1
2
3
4
5
6
7
8
9
// 主页文章添加阴影效果
.post {
margin-top: 60px;
margin-bottom: 60px;
padding: 25px;
background:rgba(255,255,255,0.9) none repeat scroll !important;
-webkit-box-shadow: 0 0 5px rgba(202, 203, 203, .5);
-moz-box-shadow: 0 0 5px rgba(202, 203, 204, .5);
}

设置代码块样式

在博客配置文件中,搜索highlight:

1
2
3
4
5
highlight:
enable: true #是否开启代码高亮
line_number: false #是否增加代码行号
auto_detect: true #自动判断代码语言
tab_replace:

代码块背景。打开themes/next/下的_config.yml,查找highlight_theme

1
2
3
4
# Code Highlight theme
# Available values: normal | night | night eighties | night blue | night bright
# https://github.com/chriskempson/tomorrow-theme
highlight_theme: night eighties

代码块复制功能

参考文章Hexo NexT 代码块复制功能

显示当前浏览进度

打开themes/next/下的_config.yml,查找back2top

1
2
3
4
5
6
back2top:
enable: true
# Back to top in sidebar.
sidebar: true
# Scroll percent label in b2t button.
scrollpercent: true

在右上角或者左上角实现fork me on github