CSS和JS的加载,并不是一个很难的过程。随着各种前端效果、框架和理论的兴起,人们逐渐意识到一个问题,那就是这些文件的加载、控制、整理涉及到两个最重要的问题,一个是性能问题——如果不顾需求,任意加载,就会减慢页面的加载速度;另一个问题是CSS代码的可维护性,随心所欲毫无章法的写编写CSS会导致代码的重复利用成为不可能完成的任务,同时也造成后期维护的巨大开销。而关于这两个问题,D8给出了自己相应的解决方案:对于性能问题,D8的策略是按需加载库,以避免在页面上加载不需要的文件从而拖慢速度;对于CSS的可维护性,D8提倡所有的CSS都应该采用SMACSS的方式来整理,以提高CSS的效率和可维护性。
主题中通过库,可以用SMACSS的方式来整理CSS文件;可以声明库之间的依赖关系;可以控制网站中任一一个库,无论它来自于核心、一个模块或者一个基主题;还可以指定某一个库,并将它移除或者替换掉——而所有这些工作都都不需要写哪怕一行PHP代码。你只需学会如何编写.libraries.yml文件就可以了。
在这个文件中定义的每一个库都应该有一个名字,有一些CSS和JS文件,还可能需要声明库之间间的依赖关系以及其它定义库所必要的信息(或参数)。以下是一个.libraries.yml文件的例子:
# 以下代码存在于mytheme.libraries.yml文件中。 # 定义一个库名,这里的库名为my-library-name。 my-library-name: version: "1.0.x" css: # SMACSS分类,base。 base: # CSS文件的路径。 assets/css/base.css: {} # SMACSS分类,skin。 theme: assets/css/print.css: { media: print } js: assets/js/myglobal.js: {} dependencies: - core/jquery # 接下来,我们再添加一个谷歌字体(Lato),这是另一个库。 lato: css: base: '//fonts.googleapis.com/css?family=Lato': { external: true } |
和info文件一样,.libraries.yml文件的前缀名也应该是其所在主题的名字。接下来,让我们逐行解释这个例子。
命名
# 声明库的名称,这里的库名为my-library-name。 my-library-name: |
每个库都应该有一个名字。你可以随意命名但是在同一个主题或者模块的两个库不应该重名。库名不需要在整个网站中都是独一无二的,因为在info文件中加载一个库的时候,需要同时指定库名和库的来源。如下:
# 在info文件中加载库 libraries: -mytheme/libraryname |
版本
version: "1.0.x" |
这一行是可选的,可以省略。其目的是为了在开发的时候进行版本追踪,在多人协助、同时开发多个项目的时候会有所帮助。再比如,你引用了一个前端库,那么你可以在这里标明这个库的版本号,这样以后就一目了然了。
CSS
css: # SMACSS分类,bass。 base: # CSS文件的路径。 assets/css/base.css:{} # SMACSS分类,skin。 theme: assets/css/print.css: { media:print } |
所有的CSS文件都应该位于“css:”这一行的下面,每个文件占用单独的一行。在这个例子中有两个CSS文件,base.css和print.css。它们分别属于两个不同的分类,一个是base一个是skin。这种分类方式来自于SMACSS,这是D8引入的新的CSS编写规范。这里CSS文件的路径是相对于主题根目录的相对路径。
SMACSS
base:
theme: |
这两行看似简单,但是其背后隐藏着一个很大的话题,那就是SMACSS。这里,我们简单讲一下。
SMACSS是一种编写和整理CSS的规范。D8并不强制你使用这种规范,但是你必须理解他,因为,一方面它被看作一种重要的前端趋势/潮流,为前端开发者带来了显而易见和无可争辩的好处,解决了以前CSS写得十分混乱的情况;另一方面,它是D8的标准,这意味着你从D.O.下载的所有主题和模块都会使用和遵循SMACSS。因此,如果你还不知道什么是SMACSS,那么你应该学习一下相关知识。而在此,你应该记住SMACSS规范把样式表分为五个不同的类型,它们分别是:Base、Layout、Module、State和Theme。这其中的Module和Theme是纯粹的SMACSS术语,与Drupal中的Module和Theme没有关系,因此,为了以示区别,Drupal圈子里的人常常以Component替代Module、偶尔也用Skin替代Theme。并且,SMACSS的5个分类,即Base、Layout、Module(Component)、State和Theme(Skin)的顺序,应该是Base在Layout前面,Layout在Module前面、Module在State前面、State在Theme前面。
当主题系统将样式表加载到页面上的时候,是按照.libraries.yml文件中声明CSS文件的顺序来加载的。因此,在.libraries.yml文件中,SMACSS的5个分类的顺序也应该如上所术。虽然.libraries.yml文件中并不一定会出现五个分类,但是分类的顺序一定是固定的。因此,一个属于Base的CSS文件就会在一个属于Theme(Skin)的文件之前加载。但是,在Drupal中,所有模块所包含的库会被编成一个组,所有主题所包含的库会被编成另一个组,模块库会被先加载,而主题库会被后加载,因此,在这种情况下,主题所提供的样式表总是会晚于模块所提供的样式表,而不会受到SMACSS分类规则的影响。
假设SMACSS的5个分类都在libraries.yml文件中定义了,代码是类似这样的:
css: # The SMACSS category base: build/css/elements.css layout: build/css/grid.css component: build/css/blocks.css state: build/css/animations.css theme: build/css/i-dont-care-just-make-it-work.css |
附加属性
theme:assets/css/print.css:{media:print } |
文件路径后紧跟着冒号和一对大括号,大括号中用于声明此文件的附加属性。在这个例子中,media属性被设置为print。它的意思是在打印状态下加载这个样式表。这个值还可以被设置成screen或者all。如果大括号为空,则默认值为all。
JavaScript
js: assets/js/myglobal.js: {} |
和CSS一样,我们在“js:”这一行的下面加载JavaScript文件,每个文件占用单独的一行。和CSS不一样的地方在于,这里不需要考虑SMACSS分类。但是,和CSS一样,你可以在大括号中加入一些附加属性来进一步声明这个文件。比如,你可以把minified属性设置为true,即
js: assets/js/myglobal.js:{minified:true} |
来告诉Drupal这个文件已经被压缩过了,因此,当启用了CSS聚合压缩功能之后,不要对这个文件进行再一次压缩。在默认情况下,所有的JS都会在页面的底部(footer)加载。
依赖关系
dependencies: -core/jquery |
“dependencies:”这一行用于声明你的库所依赖的库。你的库所依赖的库应该是一个已经被定义过的库,比如你的主题或者别人的主题,某个模块或者Drupal核心。声明依赖关系的时候需要使用到“-”。接着是库的来源+库名,这个做法类似于info文件中加载一个库。本例中,提供jQuery库的是Drupal核心。
外部文件
lato: css: base: '//fonts.googleapis.com/css?family=Lato': { external:true } |
这里定义了另一个库,这个库引用了一个外部的样式表。引用外部文件的时候需要声明这个文件的URL并将参数external设置为true。
加载谷歌map库
mymodule.libraries.yml
js-header: header: true js: https://maps.googleapis.com?key=myownapikey: type: external defer: true async: true data-test: map-link dependencies: -core/jquery |
attributes是谷歌map库要求的一些属性。最后当这个js被添加到页面上的时候,代码是这样的:
<script src="https://maps.googleapis.com?key=myownapikey" async="" defer="" data-test="map-link"></script> |