自己写一个博客主题的想法已经很久了,而且加上想在找工作的时候能有一些拿得出手而且能体现我个人特点的作品出来,能体现出来具有代码能力+一点设计能力。感觉博客主题就是一个很好的作品。刚好之前用了一下ejs,了解了一下模板引擎的内容,觉得技术上已经具备的差不多了,于是开始动手实现了。在这里要感谢一下我的第一个博客主题yilia的作者,和indigo主题的作者,经常有一些不知道如何写的地方,查看了它们的主题源码。

前期准备

首先确定技术栈:ejs+less+Jquery

基本的技术栈就是上面所说的内容了,hexo提供了很多方便的变量和辅助函数,更方便我们自己实现一个自己的博客内容。

项目结构

主要介绍一下themes里面的结构,外面需要注意的就是一个_config.yml的文件,这个文件放了一些配置内容,yml文件即YAML语言,是一种用来写配置文件的语言,比JSON要更加的方便。

  • languages //语言文件夹,可放置一些语言(比如英语、法语之类的)
  • layout //布局文件夹,用于存放主题的模板文件
    • _partial //放一些ejs和less的模板文件
    • archive.ejs //归档页面模板
    • index.ejs //主页页面模板
    • layout.ejs //整体模板,本目录下的其他的ejs会显示在body中
    • post.ejs //文章模板
    • tag.ejs //选中一个tag后的模板
    • tags.ejs //tags页面归档模板,这个是自己定义的
  • script //脚本文件夹,在启动时,Hexo 会载入此文件夹内的 JavaScript 文件
  • source //资源文件夹,例如 CSS、JavaScript 文件等
  • _config.yml //主题配置文件,有很多变量和辅助函数可方便博客内容的调用

设计主题

由于我个人其实还是挺喜欢艺术的,之前也学了不少美术之类的东西,所以想把博客主题设计的有一些涂鸦的气息,想给人一种就写博客就像一种涂鸦的感觉。整个主题也构思了大概三天吧,大概讲一下我的设计思路,虽然不是说非常满意最后的设计,但是也基本满意了。

设计思路

首先,是确定博客页面的整体结构,我看了很多博客。布局上主要分为两种,一种就是类似网站官网的那种直接从上到下的结构,还有一种就是类似yilia主题的这种左侧导航栏,右边是博客内容的这种。

这两种结构到底选择哪一种我也犹豫了好久,从艺术效果上考虑,我个人更倾向于第一种布局,因为这种布局给人发挥的空间很大,比如说banner部分可以提供一些炫酷的画面,留给我设计的空间很大。但是从功能上考虑,这次是要设计一个博客的主题,那么博客的作用是什么呢?方便查阅,方便阅读,文字优先,这些都是博客的功能。

作为一个博客,当然应该是功能优先,我在想,假如我是一个想查一些技术的用户,那么假设我打开第一种布局,可能我的第一印象是,哇这个网站好炫酷,好有感觉之类,但是多次进入之后可能就会觉得有点厌烦了,每次查东西都要往下拉,感觉很麻烦。假设我打开第二种布局,可能第一感觉并没有很惊艳的感觉,但是多次进入查阅技术的时候可能就会觉得很方便,每次进入都能很迅速的查到想查的内容。

然后就是确定整体基调了,有了上面的分析,那么基调也能很快确定下来了。简洁,涂鸦这两个词就是博客的主题。所以说留给我整体设计的可以说主要就是左侧的导航栏部分了,为了有涂鸦的感觉,当然就要找一些涂鸦的背景了,还有字体上要有感觉一些。还有一处,为了体现出来我的个性,我决定用鼠标画一个头像。

上面是从设计的内容考虑,但是作为一个技术人员,当然还要考虑实现了。设计完之后主要的问题就是两点。

  • 第一点就是由于我使用github pages(买不起服务器_(:3」∠❀)_)所以这个页面的加载速度就成了一个问题,使用过多的图片会造成加载速度上的一些问题,以至于好长时间加载不出来页面。
  • 第二个问题就是我在导航栏部分使用了网上下载的字体,倘若用户电脑里面没有(基本可以确定没有)用别的字体代替的话感觉会影响整体效果。那么解决方案目前想到两个,第一个就是使用font-face(还没用过),第二个就是使用图片了,但是第二个方案感觉最好还是不要使用了,加载速度太慢,而且导航栏部分是非常重要的内容,加载不出来的话很影响体验。

效果

整体效果(PS设计稿)

构建

脚手架

之前不是很了解什么是脚手架,现在懂了,脚手架可以简单理解为快速的生成某种结构,可以大大减少工作量。那么这次就使用了yo这个工具,并使用generator-hexo-theme来快速构建项目。

注意,这里我遇到了一个坑,使用git bash的话会在选择技术栈的时候会出现选择错误的问题,改用cmd才成功。

hexo工作

hexo提供了很多便利,在source文件夹下面写的css文件和js文件最终会编译到public文件夹的里面,然后在主题的config文件里面写上相应的public根目录下相应文件,然后在html中引入即可。然后ejs会自动编译,但是需要按照相应的名称命名。

gulp自动编译

在写less的时候又遇到了一个问题,就是引入的css文件位置在/public/css/里面,然而我如果写在source里面写less的话每次都要hexo g一下,来生成静态页面(less会自动编译到public/css/graffiti.css里面),这样就很麻烦了。

解决方法,使用gulp来自动编译,每次监听less文件改动,然后自动编译到public/css/graffiti.css这里,这样就能在hexo server服务器开启的情况下f5刷新了,方便了很多。

但是这里又遇到一个问题,那就是我在很多博客的package.json配置里面看到比如说webpack这个包,都写在了/themes/[主题名称]/package.json里面,然而如果在主题文件夹里面使用npm安装相应的npm包的话,在hexo server时候会报错,原因就是这个node_modules文件夹不能在主题文件夹里面,那么问题来了,我究竟该怎么做?

很明显,按道理讲webpack这个工具作为开发时候使用的,而在运行时并不需要,那就是说写在themes文件里面的devDependencies里面比较好。

gulpfile.js文件如下

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
var gulp = require('gulp');
var less = require('gulp-less');
var plumber = require('gulp-plumber'); //处理管道崩溃问题
var notify = require('gulp-notify'); //报错与不中断当前任务

//less编译
gulp.task('less',function(){
return gulp.src('source/css/graffiti.less') //找到需要编译的less文件
.pipe(plumber({errorHandler: notify.onError('Error:<%= error.message %>;')})) //如果less文件中有语法错误,用notify插件报错,用plumber保证任务不会停止
.pipe(less()) //如果没错误,就编译less
.pipe(gulp.dest('../../public/css/')) //把css文件放到hexo引用的css文件夹下
});


gulp.task('watchLess',function(){
//监听所有less文件,如果有变化,则执行less编译方法
gulp.watch(['source/css/graffiti.less'],['less']);
});


//新建一个任务列表,把监听任务与服务器任务都放在列表中

gulp.task('taskList', ['watchLess']);

//修改默认任务
gulp.task('default', function() {
gulp.start('taskList'); //执行任务列表
});

那么动手写主题的前期准备基本完成了,下面就开始写主题了

主题部分

整体左右两栏布局问题

左侧栏用了position:fixed定位,脱离了文档流,并且固定左侧。这时候,如果右侧不使用absolute定位的话,当设置margin-top属性的时候,上面会被分裂,具体原因暂时还没研究,之前就出现过这个问题,等下一定要研究一下。可以使用BFC来处理。

那么右侧也要脱离文档流了,这时候,按照我原来的思路使用margin-left把左侧撑开,然后右侧使用width:calc(100% - 300px)来把右边固定宽度(因为不固定宽度的话,宽度会由其内部元素决定,但是内部元素不够宽的话会撑不起来整个屏幕)。

但是calc(100% - 300px)竟然失效,计算的结果竟然是-200%,我也很是懵逼,我还特意写了个小demo来测试,测试结果是成功的,但是这里竟然失效。那么,我做一个大胆的猜测,应该是hexo内部的一些代码的问题。

上面的方案行不通,那就另一个方案,使用border-box模型,来使用padding-left把左侧撑开,并设置width: 100%,完美成功了。

1
2
3
4
5
6
7
8
.content-outer {
position: absolute;
// margin: 0 0 0 300px;
padding-left: 300px;
// width: calc(100% - 300px);
width: 100%;
z-index: -10;
}

侧边导航栏

导航栏的设计主要是一个大背景,然后从上到下分别是头像,昵称,导航菜单。然后会有一个选中效果。

悬停效果

由于我想让选中后出现涂鸦的效果,涂鸦必然会显示到其他的li标签部分,所以在li处设置background明显不可以。为了达成这个效果,要写一个和a标签的兄弟元素,这个部分设置成绝对定位,通过js控制选中后显示出来。

hover伪类并不能达成这个效果,因为我的结构是选中a标签时其兄弟元素div显示,但是hover要么控制自身,要么控制其子元素,对其他并不支持(其实当为兄弟元素时,可以使用+号来控制,但是父元素就不行了,尽量还是js控制简单一点)。

同时,为了控制背景显示的位置,可以把其父元素li标签设置成relative来定位。然后就是计算图像的大小写width和height了。

HTML

1
2
3
4
5
6
<% Object.keys(theme.menu).forEach(function(key) { %>
<li>
<div class="menu-hover <%-key%>-hover"></div>
<a id="<%=key%>" href="<%=theme.menu[key]%>"><%=key%></a>
</li>
<% }); %>

CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//其中的一部分
.Home-hover {
position: absolute;
width: 120px;
height: 132px;
left: 50%;
margin-left: -60px;
top: -30px;

display: none;
z-index: -5;
background: url('../img/hover-1.png') no-repeat;
background-size: 100%;
}

JS

1
2
3
4
5
6
7
8
9
//其中一部分
$("#Home").mouseenter(function() {
// $(".Home-hover").css("display","block");
$(".Home-hover").fadeIn(100);
});
$("#Home").mouseleave(function() {
// $(".Home-hover").css("display","none");
$(".Home-hover").fadeOut(100);
});

以上就能实现悬停效果

非web安全字体

这里我使用了一个网上下载的字体Yank,那么这个字体只是在我的电脑上能看见效果,在其它的电脑上就看不到了,那么如何解决这个问题呢。

在css3之前,那么程序员只能使用安全字体(就是说使用一连串的字体,其中一定有用户电脑自带的字体,比如说微软雅黑),这样字体就很局限,想用艺术的字体就只能用图片了。

那么现在css3有一个新的属性@font-face属性,这个属性能把字体放到服务器上,然后引入即可,例如:

在css中写上

1
2
3
4
@font-face {
font-family: navfont;
src: url('fonts/Yank.ttf');
}

那么想引入的时候font-family: navfont;即可,由于我使用的github pages + hexo,所以把字体放入合适的位置就行了。

除此之外,google还提供一个Google Font Api来提供这么一个效果,上这么网站,然后找一款好看的字体,引入即可,比如说我想用Do Hyeon这么一个字体,用link引入即可,后面可直接使用

1
<link href="https://fonts.googleapis.com/css?family=Do+Hyeon" rel="stylesheet">

动手写一个hexo主题(下)