--- title: 【网站技术文档】网站布局与覆盖 author: '`能动少C71尤佳睿`' --- > 本文迁移自信息站仓库的对应 wiki 页面。目前网站的样式已经完全重新设计,不再是覆写的成果;因此,此份文档目前仅可作一份网站设计的入门教程,而不能被视为当前本站技术架构的反映。 本文档将介绍: - 为何要覆写由主题所定义的文件; - 如何通过 `_layouts/default.html` 文件修改网页的通用布局; - 如何通过 Sass 代码覆写原有主题中的样式; - 如何覆写 Javascript 脚本,并实现新的功能。 ## 覆写文件 钱院学辅信息站使用 GitHub Pages 提供的 Leap Day 主题。这是一款很不错的主题,但也有许多问题,包括但不限于: - 导航菜单功能有限,样式不够美观,且不支持中文; - 在引用块中采用了斜体,而这对中文排版的内容是毁灭性的打击; - 标题栏固定在页面顶部,将正文盖住,这使得同页面内的锚记必须向下偏移若干距离,给页内引用造成困扰; - 样式不美观…… 主题本来是解决「有无」问题的,不应肩负起「自定义」的使命。好在 Jekyll 允许用户「覆盖」主题所定义的布局、样式与脚本,它遵守这样的两条原则: 1. Jekyll 会优先使用你的仓库中已有的文件。例如,你的仓库中有一份样式表,而主题的仓库中定义了同名、同路径的另一份样式表;这时,Jekyll 便会忽略远端(主题)的那份文件,而应用你的样式表。 2. 如果 Jekyll 在你的仓库中没有找到所需的文件,则它将使用主题仓库中的文件。 这两条原则决定了你「覆盖」主题的方式:如果你希望继续沿用主题的某个部分,则你什么也不用做;如果你希望改动主题的某个部分——例如,页面生成的 HTML 模板,或者页面采用的 Javascript 脚本,则你应该检查主题仓库的结构,并在你的仓库中对应位置创建同名的文件,将主题的文件覆盖掉。 > :warning: 对于 CSS 样式表,则并不需要覆写主题所定义的文件:只需要定义自己的样式,再按照 CSS 的方式「层叠」即可。 以下将分别讨论布局、样式与脚本的覆写方法。 ## 页面布局:HTML 在[仓库与网站机制](仓库与网站机制)这一篇中,你已经知道:Jekyll 能将 Markdown 文档渲染为 HTML 文档。但如果对比文档仓库中的 Markdown 文档,以及由 GitHub Pages 最终发布的网页,你会发现:网页上的许多内容,并非由 Markdown 文档转化而来。例如,网站的标题、导航菜单、许可证信息……它们并未出现在你的 Markdown 文档中,但它们却出现在每一个页面上(如你所愿)。 事实上,这些内容是由仓库中的 HTML 模板所决定的。对于未加指定的 Markdown 文档,Jekyll 总是会以仓库中 `_layouts` 目录下的 `default.html` 模板来生成最终的网页;如果你在 Markdown 文档中指定了「分类」,则 Jekyll 还会在 `_layouts` 搜索与这个分类对应的模板。 > :warning: 在阅读以下内容之前,你需要确保自己对 HTML 文档(文件结构、标签)有基本的概念。 > > :book: 如果你缺少 HTML 的基本知识,可以先快速浏览这篇文章:[菜鸟教程 - HTML 简介](http://www.runoob.com/html/html-intro.html)。 {% raw %} ### 页面生成原理 以本站的页面模板为例,`_layouts/default.html` 的主要内容大致如下: ```html

{{ site.title }}

{{ site.description }}

{{ content }}

本文发布于 {{ page.data }}。

{{ site.extra_info }}

``` > :warning: 以上这份 HTML 代码已经被大幅度删改,仅用于展示原理。 文档结构看似繁复,实际上仅是一个常见的单栏网页框架。 首先,在 `` 标签中,模板引用了仓库中的 `style.scss` 样式表及 `main.js` 脚本,由此即可实现样式与功能的自定义。当然,在模板中也不限于引用本地文件,可以引入像 jQuery 这样的外部脚本。样式表使网页变得更加美观,而脚本则可以使「静态」的网页具有一定的「动态」特性。 其次,在 `` 标签中,贮存着最终显示在网页上的所有内容。静态的标签,自然将在最终的网页上原样呈现;而真正使得这个 HTML 文档成为「模板」的,却是 Jekyll 所支持的 Liquid 标签,由 `{{ variable }}` 的形式标记出来。在最终生成网页时,Jekyll 会把这些标签「代入」为具体的信息、参数,由此实现模板的功能。在这里的模板中,有三种 Liquid 标签: - `{{ site.variable }}` 对应于**站点**的元数据信息,如这份模板中的 `{{ site.title }}`(站点标题)。它们通常由用户在根目录下的 `_config.yml` 文件定义。 - `{{ page.variable }}` 对应于**本页面**的元数据信息,如这份模板中的 `{{ page.data }}` (页面的发布或更新日期)。它们通常以[头信息](http://jekyllcn.com/docs/frontmatter/)的方式定义在 Markdown 文档中。 - 没有前缀的 `{{ variable }}`,一般是由 Jekyll 预定义、自动处理的数据,例如这份模板中最重要的 `{{ content }}` 变量就代表着这一页面的具体内容(即由 Markdown 文档转换而来的 HTML 代码)。 由此可以看出,如果说 Markdown 文档经 Jekyll 转换后变成了网页的「内容」,则 `default.html` 便是容纳这「内容」的「容器」,可以有复杂的结构、「外壳」。至于 Liquid 标签,则是自动生成内容时所必须的工具——你可以将它理解为「时空传送门」或者「叮当猫的神奇口袋」,要什么给什么。 > :book: 关于 Liquid 的详细讨论,可参考:[Liquid 模板语言中文文档](https://liquid.bootcss.com)。 {% endraw %} ### 定义多个模板 那么,如何为不同分类的文档使用不同的模板?事实上,只需要完成以下两步: 1. 在 `_layouts` 目录下新建一个模板文件,例如给「文章」专用的 `article.html` 模板。 2. 在需要按「文章」呈现的 Markdown 文档中,以如下形式标记其头信息: ```markdown --- layout: article --- # 文章标题 这是一份文档 …… ``` 这样就能够实现多种模板了。 ## 样式改进:CSS 或 Sass HTML 模板仅决定了页面上的「布局」:它定义了页面上应当有标题、正文、底部说明,但没有定义它们的「样式」。这时,就需要 CSS 样式表了。 > :book: 如果你对 CSS 还一无所知,可以先快速浏览这两篇文章:[CSS 简介](https://www.w3school.com.cn/css/css_jianjie.asp)与 [CSS 基础语法](https://www.w3school.com.cn/css/css_syntax.asp)。 ### 新机制:Sass 与传统的站点不同,Jekyll 采用 Sass 来生成最终的 CSS 样式表。Sass 可以被称为是一种「CSS 预处理器」,它使得 CSS 的编写过程变得系统、轻松;更好的是,Sass 最常用的语法被称为 SCSS(不要晕了),而这种语法与 CSS 完全兼容,这使得我们既可以尝试 Sass 的新功能,也可以仍然用传统的 CSS 来「堆叠」样式。 > :warning: 注意 Sass 与 CSS 的差异:Sass 的代码并非样式表,不能被直接使用,需要「处理」为 CSS 后才能生效。而上面所说的 SCSS 之「兼容」,本质上说的是:如果你在 Sass 的代码中粘贴了传统的 CSS 代码,则其按 SCSS 语法处理后将得到完全相同的 CSS 样式表,因此可以像使用 CSS 样式表那样编写 Sass 代码。 通常而言,站点的 Sass 代码被存放在 `_sass` 目录下。对于使用现成主题的站点(如本站)来说,`_sass` 目录存放在远端,一般不用「取」到自己的仓库之中——HTML 模板会自行从远端加载由主题所定义的样式。 > :book: 如果你想了解 Sass 究竟怎样使编写 CSS 变得「系统、轻松」,可以参考这篇文章:[SASS 用法指南 - 阮一峰的网络日志](http://www.ruanyifeng.com/blog/2012/06/sass.html)。 ### 样式覆盖 众所周知,CSS 的最大特点就是「堆叠」:首先允许在不同的位置、以不同的方式多次定义样式,然后按一定的优先级、继承法则决定最终的样式。在这种情况下,采用已有主题定制的 Jekyll 站点就具有特别的优势:既可以保有他人精心定制的样式,也可以根据自己的需要进行样式的「覆盖」。 自定义样式的方法是:在仓库中创建名为 `assets/css` 的目录,新建名为 `style.scss` 的 Sass 代码;打开该文件后,先输入这样几行: ```scss --- --- @import "{{ site.theme }}"; ``` 其中,前面的两行「分割线」实际上是一个空的「头信息」,它告诉 Jekyll 这份文件需要「处理」,不能省略;否则,这份 Sass 代码不会被处理为 CSS 样式表。接下来是一个 Sass 命令,它将由主题所定义的那些 Sass 样式代码全部引入到现有的这份 `style.scss` 文件中,以供覆盖。 接下来,读者就可以在以上的这几行代码后,写上自己的 CSS 样式,例如让 `` 标签内的所有段落(`

`)用亮灰色显示: ```css body p { color: lightgray; } ``` 以此类推。当然,如果你已经精通了 Sass 的 SCSS 语法,甚至可以写的更为简洁。 > 自定义样式表的位置,取决于 HTML 模板中的定义。这里所确定的目录,是由 GitHub Pages 的主题中所定义的;读者可以修改仓库中 `_layouts/default.html` 模板引用样式表的方式,进而自定义样式表的存放位置。 ### 检查样式效果 定义 CSS 样式,最值得担心的问题是:在不同的浏览器、不同大小的屏幕上,显示效果是否始终如一?为了测试不同平台上的显示效果,你可以使用浏览器自带的「开发者工具」,检查样式的定义情况,切换窗口大小,甚至直接修改样式。 > :book: 不同浏览器的「开发者工具」不尽相同,因此这里并不详细介绍。读者可参考这篇文章:[MDN - 什么是浏览器开发者工具 ](https://developer.mozilla.org/zh-CN/docs/Learn/Discover_browser_developer_tools)。其是以 Firefox 为例介绍的,但同时也给出了其他浏览器的对应链接。 ## 开发 Javascript 脚本 许多人可能对仅由 HTML 与 CSS 组织的「静态」页面不甚满意。例如,我们希望学辅信息站上能支持这些功能: - 根据文章的各级标题,自动生成一个导航菜单/目录,点击其中的条目就能「平滑」地滚动到文章对应位置; - 搜索页面上的一些特定对象,改变它们的样式(CSS 自有的选择器往往无能为力); - 光标在页面上移动时,会伴随炫丽的幻影。 除了第三个功能没有意义外,剩余的几项功能都非常有必要实现。这时,可以用 Javascript 或相关的库(如 JQuery)写一些简单的脚本,实现这些带有「动态」属性的功能。Javascript 并非网页设计的必选项,你可以充分的依赖别人已有的成果;不过,即使是做一些简单的个性化调整,也需要你至少具有一定的 Javascript 基础。 > :book: 如果你希望快速了解 Javascript 的语法与特性,可浏览这篇教程:[菜鸟教程 - Javascript 简介](http://www.runoob.com/js/js-intro.html)。此外,我们的网站中常常使用到 jQuery,它是一个 Javascript 库,你可以浏览[菜鸟教程 - jQuery 教程](http://www.runoob.com/jquery/jquery-tutorial.html)中的有关条目——它的语法非常简单,且功能强大,很容易上手。 ### 脚本在哪里? 在我们所用的主题中,其仅使用了一份脚本:位于 `assets/js` 目录下的 `main.js`。在原本的主题中,其定义了两项功能: - `sectionHeight()` 函数,用于计算网页的高度; - 导航栏的生成与运行脚本,定义了导航栏的生成方式(提取正文标题)、运行方式(点击链接后,会以动画的形式跳转到对应位置)。 其中,第二项功能的实现不甚完备,特别是对中文支持不佳。为了完善这些问题,首先在本地仓库的对应位置克隆了原有的 `main.js` 文件,然后再根据实际需求进行改动。 ### 覆写实例:导航栏 > :warning: 导航栏的改动尚未完成,个别样式还需进一步优化。因此,这里暂不讨论改动的具体内容。 ### 新建实例:`shieldsManu.js` 除了优化已有的功能,你也可以在自己的站点中尝试新的脚本。例如,在本站中,有一份名为 `shieldsManu.js` 的脚本,用来优化网站中 [shields](https://shields.io) 标牌的样式与使用。它用 jQuery 写成,便于理解,也便于修改。 > :scroll: 关于 `shieldsManu` 插件的功能与使用方法,请先跳转至这份技术文档:[Markdown 文档规范](Markdown-文档规范#并不足够shieldsmanu)。 这里对 `shiledsManu.js` 的实现方式作简单讨论。……