【网站技术文档】网站布局与覆盖
本文迁移自信息站仓库的对应 wiki 页面。目前网站的样式已经完全重新设计,不再是覆写的成果;因此,此份文档目前仅可作一份网站设计的入门教程,而不能被视为当前本站技术架构的反映。
本文档将介绍:
- 为何要覆写由主题所定义的文件;
- 如何通过
_layouts/default.html
文件修改网页的通用布局; - 如何通过 Sass 代码覆写原有主题中的样式;
- 如何覆写 Javascript 脚本,并实现新的功能。
覆写文件
钱院学辅信息站使用 GitHub Pages 提供的 Leap Day 主题。这是一款很不错的主题,但也有许多问题,包括但不限于:
- 导航菜单功能有限,样式不够美观,且不支持中文;
- 在引用块中采用了斜体,而这对中文排版的内容是毁灭性的打击;
- 标题栏固定在页面顶部,将正文盖住,这使得同页面内的锚记必须向下偏移若干距离,给页内引用造成困扰;
- 样式不美观……
主题本来是解决「有无」问题的,不应肩负起「自定义」的使命。好在 Jekyll 允许用户「覆盖」主题所定义的布局、样式与脚本,它遵守这样的两条原则:
- Jekyll 会优先使用你的仓库中已有的文件。例如,你的仓库中有一份样式表,而主题的仓库中定义了同名、同路径的另一份样式表;这时,Jekyll 便会忽略远端(主题)的那份文件,而应用你的样式表。
- 如果 Jekyll 在你的仓库中没有找到所需的文件,则它将使用主题仓库中的文件。
这两条原则决定了你「覆盖」主题的方式:如果你希望继续沿用主题的某个部分,则你什么也不用做;如果你希望改动主题的某个部分——例如,页面生成的 HTML 模板,或者页面采用的 Javascript 脚本,则你应该检查主题仓库的结构,并在你的仓库中对应位置创建同名的文件,将主题的文件覆盖掉。
对于 CSS 样式表,则并不需要覆写主题所定义的文件:只需要定义自己的样式,再按照 CSS 的方式「层叠」即可。
以下将分别讨论布局、样式与脚本的覆写方法。
页面布局:HTML
在仓库与网站机制这一篇中,你已经知道:Jekyll 能将 Markdown 文档渲染为 HTML 文档。但如果对比文档仓库中的 Markdown 文档,以及由 GitHub Pages 最终发布的网页,你会发现:网页上的许多内容,并非由 Markdown 文档转化而来。例如,网站的标题、导航菜单、许可证信息……它们并未出现在你的 Markdown 文档中,但它们却出现在每一个页面上(如你所愿)。
事实上,这些内容是由仓库中的 HTML 模板所决定的。对于未加指定的 Markdown 文档,Jekyll 总是会以仓库中 _layouts
目录下的 default.html
模板来生成最终的网页;如果你在 Markdown 文档中指定了「分类」,则 Jekyll 还会在 _layouts
搜索与这个分类对应的模板。
在阅读以下内容之前,你需要确保自己对 HTML 文档(文件结构、标签)有基本的概念。
如果你缺少 HTML 的基本知识,可以先快速浏览这篇文章:菜鸟教程 - HTML 简介。
页面生成原理
以本站的页面模板为例,_layouts/default.html
的主要内容大致如下:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="/assets/css/style.css">
<script src="https://code.jquery.com/jquery-3.3.0.min.js"></script>
<script src="/assets/js/main.js"></script>
</head>
<body>
<header>
<h1>{{ site.title }}</h1>
<p>{{ site.description }}</p>
</header>
<div id="banner"><!-- 这里写了导航栏的内容 --></div>
<div class="wrapper">
<nav><ul></ul></nav>
<section>
<!-- 你的 Markdown 文档由此开始 -->
{{ content }}
<!-- 你的 Markdown 文档到此结束 -->
<hr><blockquote>
<p>本文发布于 {{ page.data }}。</p>
<p>{{ site.extra_info }}</p>
</blockquote>
</section>
<footer><p>本站由{{ site.user }}出品</p></footer>
</div>
</body>
</html>
以上这份 HTML 代码已经被大幅度删改,仅用于展示原理。
文档结构看似繁复,实际上仅是一个常见的单栏网页框架。
首先,在 <head>
标签中,模板引用了仓库中的 style.scss
样式表及 main.js
脚本,由此即可实现样式与功能的自定义。当然,在模板中也不限于引用本地文件,可以引入像 jQuery 这样的外部脚本。样式表使网页变得更加美观,而脚本则可以使「静态」的网页具有一定的「动态」特性。
其次,在 <body>
标签中,贮存着最终显示在网页上的所有内容。静态的标签,自然将在最终的网页上原样呈现;而真正使得这个 HTML 文档成为「模板」的,却是 Jekyll 所支持的 Liquid 标签,由 {{ variable }}
的形式标记出来。在最终生成网页时,Jekyll 会把这些标签「代入」为具体的信息、参数,由此实现模板的功能。在这里的模板中,有三种 Liquid 标签:
-
{{ site.variable }}
对应于站点的元数据信息,如这份模板中的{{ site.title }}
(站点标题)。它们通常由用户在根目录下的_config.yml
文件定义。 -
{{ page.variable }}
对应于本页面的元数据信息,如这份模板中的{{ page.data }}
(页面的发布或更新日期)。它们通常以头信息的方式定义在 Markdown 文档中。 - 没有前缀的
{{ variable }}
,一般是由 Jekyll 预定义、自动处理的数据,例如这份模板中最重要的{{ content }}
变量就代表着这一页面的具体内容(即由 Markdown 文档转换而来的 HTML 代码)。
由此可以看出,如果说 Markdown 文档经 Jekyll 转换后变成了网页的「内容」,则 default.html
便是容纳这「内容」的「容器」,可以有复杂的结构、「外壳」。至于 Liquid 标签,则是自动生成内容时所必须的工具——你可以将它理解为「时空传送门」或者「叮当猫的神奇口袋」,要什么给什么。
关于 Liquid 的详细讨论,可参考:Liquid 模板语言中文文档。
定义多个模板
那么,如何为不同分类的文档使用不同的模板?事实上,只需要完成以下两步:
- 在
_layouts
目录下新建一个模板文件,例如给「文章」专用的article.html
模板。 - 在需要按「文章」呈现的 Markdown 文档中,以如下形式标记其头信息:
---
layout: article
---
# 文章标题
这是一份文档
……
这样就能够实现多种模板了。
样式改进:CSS 或 Sass
HTML 模板仅决定了页面上的「布局」:它定义了页面上应当有标题、正文、底部说明,但没有定义它们的「样式」。这时,就需要 CSS 样式表了。
新机制:Sass
与传统的站点不同,Jekyll 采用 Sass 来生成最终的 CSS 样式表。Sass 可以被称为是一种「CSS 预处理器」,它使得 CSS 的编写过程变得系统、轻松;更好的是,Sass 最常用的语法被称为 SCSS(不要晕了),而这种语法与 CSS 完全兼容,这使得我们既可以尝试 Sass 的新功能,也可以仍然用传统的 CSS 来「堆叠」样式。
注意 Sass 与 CSS 的差异:Sass 的代码并非样式表,不能被直接使用,需要「处理」为 CSS 后才能生效。而上面所说的 SCSS 之「兼容」,本质上说的是:如果你在 Sass 的代码中粘贴了传统的 CSS 代码,则其按 SCSS 语法处理后将得到完全相同的 CSS 样式表,因此可以像使用 CSS 样式表那样编写 Sass 代码。
通常而言,站点的 Sass 代码被存放在 _sass
目录下。对于使用现成主题的站点(如本站)来说,_sass
目录存放在远端,一般不用「取」到自己的仓库之中——HTML 模板会自行从远端加载由主题所定义的样式。
如果你想了解 Sass 究竟怎样使编写 CSS 变得「系统、轻松」,可以参考这篇文章:SASS 用法指南 - 阮一峰的网络日志。
样式覆盖
众所周知,CSS 的最大特点就是「堆叠」:首先允许在不同的位置、以不同的方式多次定义样式,然后按一定的优先级、继承法则决定最终的样式。在这种情况下,采用已有主题定制的 Jekyll 站点就具有特别的优势:既可以保有他人精心定制的样式,也可以根据自己的需要进行样式的「覆盖」。
自定义样式的方法是:在仓库中创建名为 assets/css
的目录,新建名为 style.scss
的 Sass 代码;打开该文件后,先输入这样几行:
---
---
@import "jekyll-theme-primer";
其中,前面的两行「分割线」实际上是一个空的「头信息」,它告诉 Jekyll 这份文件需要「处理」,不能省略;否则,这份 Sass 代码不会被处理为 CSS 样式表。接下来是一个 Sass 命令,它将由主题所定义的那些 Sass 样式代码全部引入到现有的这份 style.scss
文件中,以供覆盖。
接下来,读者就可以在以上的这几行代码后,写上自己的 CSS 样式,例如让 <body>
标签内的所有段落(<p>
)用亮灰色显示:
body p {
color: lightgray;
}
以此类推。当然,如果你已经精通了 Sass 的 SCSS 语法,甚至可以写的更为简洁。
自定义样式表的位置,取决于 HTML 模板中的定义。这里所确定的目录,是由 GitHub Pages 的主题中所定义的;读者可以修改仓库中
_layouts/default.html
模板引用样式表的方式,进而自定义样式表的存放位置。
检查样式效果
定义 CSS 样式,最值得担心的问题是:在不同的浏览器、不同大小的屏幕上,显示效果是否始终如一?为了测试不同平台上的显示效果,你可以使用浏览器自带的「开发者工具」,检查样式的定义情况,切换窗口大小,甚至直接修改样式。
不同浏览器的「开发者工具」不尽相同,因此这里并不详细介绍。读者可参考这篇文章:MDN - 什么是浏览器开发者工具 。其是以 Firefox 为例介绍的,但同时也给出了其他浏览器的对应链接。
开发 Javascript 脚本
许多人可能对仅由 HTML 与 CSS 组织的「静态」页面不甚满意。例如,我们希望学辅信息站上能支持这些功能:
- 根据文章的各级标题,自动生成一个导航菜单/目录,点击其中的条目就能「平滑」地滚动到文章对应位置;
- 搜索页面上的一些特定对象,改变它们的样式(CSS 自有的选择器往往无能为力);
- 光标在页面上移动时,会伴随炫丽的幻影。
除了第三个功能没有意义外,剩余的几项功能都非常有必要实现。这时,可以用 Javascript 或相关的库(如 JQuery)写一些简单的脚本,实现这些带有「动态」属性的功能。Javascript 并非网页设计的必选项,你可以充分的依赖别人已有的成果;不过,即使是做一些简单的个性化调整,也需要你至少具有一定的 Javascript 基础。
如果你希望快速了解 Javascript 的语法与特性,可浏览这篇教程:菜鸟教程 - Javascript 简介。此外,我们的网站中常常使用到 jQuery,它是一个 Javascript 库,你可以浏览菜鸟教程 - jQuery 教程中的有关条目——它的语法非常简单,且功能强大,很容易上手。
脚本在哪里?
在我们所用的主题中,其仅使用了一份脚本:位于 assets/js
目录下的 main.js
。在原本的主题中,其定义了两项功能:
-
sectionHeight()
函数,用于计算网页的高度; - 导航栏的生成与运行脚本,定义了导航栏的生成方式(提取正文标题)、运行方式(点击链接后,会以动画的形式跳转到对应位置)。
其中,第二项功能的实现不甚完备,特别是对中文支持不佳。为了完善这些问题,首先在本地仓库的对应位置克隆了原有的 main.js
文件,然后再根据实际需求进行改动。
覆写实例:导航栏
导航栏的改动尚未完成,个别样式还需进一步优化。因此,这里暂不讨论改动的具体内容。
新建实例:shieldsManu.js
除了优化已有的功能,你也可以在自己的站点中尝试新的脚本。例如,在本站中,有一份名为 shieldsManu.js
的脚本,用来优化网站中 shields 标牌的样式与使用。它用 jQuery 写成,便于理解,也便于修改。
关于
shieldsManu
插件的功能与使用方法,请先跳转至这份技术文档:Markdown 文档规范。
这里对 shiledsManu.js
的实现方式作简单讨论。……