发表于: 2019-08-19 21:08:26

1 1103


今天完成的事情:

             完成了任务十三,开始自己的CSS库搭建

             在任务十三中对代码规范有了新的理解,不过是表头,注释,还是类,都有着一套流程。

           在这一套流程中,其中《header》代表着表头准备开始。

                                                                    《main》代表着主要内容,《footer》代表着结尾部分。


            学习并且尝试CSS的架构。

            对于HTML结构做出了优化。

            对于代码规范更加严谨化。

 

 明天计划的事情:

             完成任务十四CSS代码库的搭建开启任务十五。


   遇到的难题:

             在学习CSS架构时,如何做到一个健壮且可扩展的CSS架构呢

                      他要做到以下八点:

1.总是类名优先

 2.组件代码放在一起

                                 4.维护命名空间和文件名之间的严格映射

       8.松散地整合外部样式

其中最后两点暂时理解不了,在这里不做总结和知识点介绍。等到时候我看的懂了再来写到日报里

1. 总是类名优先 

这是显而易见的。

不要去使用 ID 选择器 (如 #header),因为每当你认为某样东西只会有一个实例的时候,在无限的时间范围内,你都将被证明是错的。一个典型的例子就是,当想要在我们构建的大型应用中修复任何数据绑定漏洞的时候(这种情况尤为明显)。我们从为 UI 代码创建两个实例开始,它们并行在同一个 DOM,并都绑定到一个数据模型的共享实例上。这么做是为了保证所有数据模型的变化都可以正确体现到这两个 UI 上。所以任何你可能假设总是唯一的组件,如一个头部模板,就不再唯一了。顺便一提,这对找出其他唯一性假设相关的细微漏洞来说,也是一个很好的基准。我跑题了,但这个故事告诉我们的就是:没有一种情况是使用 ID 选择器会比使用类选择器更好,所以只要不使用就行了。

同样也不应该直接使用元素选择器(如 p)。通常对一个属于组件的元素使用元素选择器是可以的(看下面),但是对于元素本身来说,最终你将会为了一个不想使用它们的组件,而不得不将那些样式给撤销掉。回想一下我们的主要目标,这同样也违背了它们(面向组件,避免折磨人的层叠(cascade),以及默认局部化)。如果你这么选择的话,那么在body上设置一些像字体,行高以及颜色的属性(也叫可继承属性),对这个规则来说也可以是一个特例,但是如果你真正想做到组件隔离的话,那么放弃这些也完全是可行的(看下面关于使用外部样式的部分)。

所以在极少特例的情况下,你的样式应该总是类名优先。

2. 组件代码放在一起

当使用一个组件的时候,如果所有和组件相关的资源(其 JavaScript 代码,样式,测试用例,文档等等)都可以非常紧密地放在一起,那就更好了:

1
2
3
4
5
6
7
8
9
10
ui/
├── layout/
|   ├── Header.js              // component code
|   ├── Header.scss            // component styles
|   ├── Header.spec.js         // component-specific unit tests
|   └── Header.fixtures.json   // any mock data the component tests might need
├── utils/
|   ├── Button.md              // usage documentation for the component
|   ├── Button.js              // ...and so on, you get the idea
|   └── Button.scss

当你写代码的时候,只需要简单地打开项目的浏览工具,组件的所有其他内容都唾手可得了。样式代码和生成DOM的JavaScript之间有着天然的耦合性,而且我敢打赌你在修改完其中一个之后不久肯定会去修改另外一个。举例来说,这同样适用于组件及其测试代码。可以认为这就是 UI 组件的访问局部性原理。我以前也会细致地去维护各种独立的镜像文件,它们各自存在 styles/、 tests/ 和 docs/ 等目录下面,直到我意识到,实际上我一直这么做的唯一原因是因为我就是一直这样做的。

3. 使用一致的类命名空间

CSS 对类名及其他标识符(如 ID、动画名称等)都有一个独立扁平的命名空间。就像过去在 PHP 里,其社区想通过简单地使用更长且具有结构性的名称来处理这个问题,因此就效仿了命名空间(BEM 就是个例子)。我们也想要选择一个命名空间规范,并坚持下去。

比如,使用 myapp-Header-link 来当做一个类名,组成它的三个部分都有着特定的功能:

  • myapp 首先用来将我们的应用和其他可能运行在同一个 DOM 上的应用隔离开来
  • Header 用来将组件和应用里其他的组件隔离开来
  • link 用来为局部样式效果保存一个局部名称(在组件的命名空间内)

作为一个特殊的情况,Header 组件的根元素可以简单地用 myapp-Header 类来标记。对于一个非常简单的组件来说,这可能就是所需要做的全部了。

不管我们选择怎样的命名空间规范,我们都想要通过它保持一致性。那三个类名组成部分除了有着特定功能,也同样有着特定的含义。只需要看一下类名,就可以知道它属于哪里了。这样的命名空间将成为我们浏览项目样式的地图。

目前为止我都假设命名空间的方案为 app-Component-class,这是我个人在工作当中发现确实好用的方案,当然你也可以琢磨出自己的一套来。

4. 维护命名空间和文件名之间的严格映射

这只是对之前两条规则的逻辑组合(组件代码放在一起以及类命名空间):所有影响一个特定组件的样式都应该放到一个文件里,并以组件命名,没有例外。

如果你正在使用浏览器,然后发现一个组件表现异常,那么你就可以点击右键检查它,接着你就会看到:

1
<div class="myapp-Header">...</div>

注意到组件名称,然后切换至你的编辑器,按下“快速打开文件”的快捷键,然后开始输入“head”,就可以看到:

Quick open file

这种来自 UI 组件关联源代码文件的严格映射非常有用,特别是如果你新进入一个团队并且还没有完全熟悉代码结构,通过这个方法你不需要熟悉就可以快速找到你应该写代码的地方了。

有一个对这种方法的自然推论(但或许不是那么快变得明显):一个单独的样式文件应该只包含属于一个独立命名空间的样式。为什么?假设我们有一个登录表单,只在 Header 组件内使用。在 JavaScript 代码层面,它被定义成一个名为 Header.js 的辅助组件,并且没有在任何地方被引入。你可能想声明一个类名为 myapp-LoginForm,并在 Header.js 和 Header.scss 里使用。那么假设团队里有一个新人被安排去修复登录表单上一个很小的布局问题,并想通过检查元素发现在哪里开始修改。然而并没有 LoginForm.js 或者 LoginForm.scss 可以被发现,这时他就不得不凭借 grep (Linux 命令)或者靠猜去寻找相关联的源代码文件。这也就是说,如果这个登录表单产生了一个独立的命名空间,那么就应该将其分割成一个独立的组件。一致性在大型项目里是非常有价值的。

5. 避免组件外的样式泄露

我们已经建立了自己的命名空间规范,并且现在想使用它们去沙箱化我们的 UI 组件。如果每个组件都只使用加上它们唯一的命名空间前缀的类名,那我们就可以确定它们的样式不会泄露到其他组件中去。这是非常高效的(看后面的注意事项),但是不得不反复输入命名空间也会变得越来越冗长乏味。

一个健壮,且仍然非常简单的解决方案就是将整个样式文件包装成一个前缀。注意我们是怎样做到只需要重复一次应用和组件名称:

1
2
3
4
5
6
7
8
9
10
11
12
.myapp-Header {
background: black;
color: white;
&-link {
color: blue;
}
&-signup {
border: 1px solid gray;
}
}

上面的例子是在 SASS 中实现的,但其中的 & 符号(或许让人有点惊讶)在所有相关的 CSS 预处理器中都做着同样的工作(SASSPostCSSLESS 以及 Stylus)。出于完整性,接下来给出上面 SASS 代码编译后的结果:

1
2
3
4
5
6
7
8
9
10
11
12
.myapp-Header {
background: black;
color: white;
}
.myapp-Header-link {
color: blue;
}
.myapp-Header-signup {
border: 1px solid gray;
}

所有常见的模式也可以使用它很好地表示出来,比如不同的组件状态有着不同的样式(想想 BEM 条件下的修饰符):

1
2
3
4
5
6
7
8
9
10
.myapp-Header {
&-signup {
display: block;
}
&-isScrolledDown &-signup {
display: none;
}
}

上面的编译结果如下:

1
2
3
4
5
6
7
.myapp-Header-signup {
display: block;
}
.myapp-Header-isScrolledDown .myapp-Header-signup {
display: none;
}

只要你的预编译器支持冒泡(SASS、LESS、PostCSS 和 Stylus 都可以做到),甚至媒体查询也可以很方便表示:

1
2
3
4
5
6
7
8
9
10
.myapp-Header {
&-signup {
display: block;
@media (max-width: 500px) {
display: none;
}
}
}

上面的代码就会变成:

1
2
3
4
5
6
7
8
9
.myapp-Header-signup {
display: block;
}
@media (max-width: 500px) {
.myapp-Header-signup {
display: none;
}
}

上面的模式让使用长且唯一的类名变得非常方便,因为你再也无需反复输入它们了。方便性是强制的,因为如果不方便,那么我们就会偷工减料了。

             

6. 避免组件内的样式泄露

还记得我说过给每个类名加上组件命名空间的前缀时,这是对沙箱化样式来说很高效的一种方式吗?还记得我说过这里有个“注意事项”吗?

考虑下面的样式:

1
2
3
4
5
.myapp-Header {
a {
color: blue;
}
}

以及下面的组件层:

1
2
3
4
5
+-------------------------+
| Header                  |
|                         |
| [home] [blog] [kittens] | <-- 这些都是 <a> 元素
+-------------------------+

这很酷,不是吗?Header 里只有 <a> 元素会变成蓝色,因为我们生成的规则如下:

1
.myapp-Header a { color: blue; }

但是考虑布局在之后做一下变化:

1
2
3
4
5
6
7
+-----------------------------------------+
| Header                    +-----------+ |
|                           | LoginForm | |
|                           |           | |
| [home] [blog] [kittens]   | [info]    | | <-- 这些是 <a> 元素
|                           +-----------+ |
+-----------------------------------------+

选择器 .myapp-Header a 同样匹配了 LoginForm 里的 <a> 元素,所以我们搞砸了这里的样式隔离。事实证明,将所有样式包装到一个命名空间里对于隔离组件及其邻居组件来说,是一个高效的方式,但却不能总是和其子组件隔离

这个问题可以通过两种方法修复:

  1. 绝不在样式表中使用元素名称选择器。如果 Header 里的 <a> 元素都使用 <a class="myapp-Header-link"> 替代,那么我们就不需要处理这个问题了。再往下看,有时候你会设置一些语义化标签,像 <article><aside>以及 <th>,都放在了正确的位置上,并且你又不想用额外的类名来弄乱它们,这种情况下:
  2. 在你的命名空间之外只使用 > 操作符 来选择元素。

根据第二个方法来做调整,我们的样式代码就可以改写如下:

1
2
3
4
5
.myapp-Header {
> a {
color: blue;
}
}

这样就可以确保隔离同样作用于更深层次的组件树,因为生成的选择器变成了 .myapp-Header > a

如果这听起来有争议,那么让我通过下面这个同样运行良好的例子更进一步地使你信服:

1
2
3
4
5
.myapp-Header {
> nav > p > a {
color: blue;
}
}

经过多年的可靠建议,我们一直认为要尽量避免选择器嵌套(包括这个使用了 > 的强关联形式)。但是为什么呢?这个引用的原因归结为以下三个:

  1.                       层叠样式最终会毁掉你的一天。要是嵌套越多的选择器,那么就有越高的机会造成一个元素匹配上多于一个组件的情况。如果你读到这里,你就会知道我们已经消除了这种可能性了(使用严格的命名空间前缀,并在需要的时候使用强关联子元素选择器)。
  2.                        太多的特性会减少可复用性。写给 nav p a 的样式将不能在特定情况下之外的任意地方被复用。但其实我们从来没想要它可复用,事实上,我们特意禁止这个可复用的方法,因为这种可复用性并不能在我们想实现组件隔离的目标上产生好的作用。
  3.                        太多的特性会让重构变得更加困难。这可以在现实中找到依据,假设你只有一个 .myapp-Header-link a,你可以很自由地在组件的 HTML 中移动 <a> 元素,同样的样式总是会一直生效。然而如果使用 > nav > p > a,就需要更新选择器去匹配组件的 HTML 内这个链接的新位置。但考虑到我们想要 UI 是由一些小且隔离性好的组件组成,这个问题也不是相当重要。当然,如果你不得不在重构的时候考虑整个应用的 HTML 和 CSS,那么这个问题可能就有点严重了。但是现在你是在一个只有十行样式代码的小沙箱内进行操作,并且还知道沙箱外没有其他东西需要考虑,那么这种类型的变化就不是问题了。

            

             今天遇到最大的问题是一个关于CSS模块开发和组件的,因为师兄的意思是在任务十五的时候会需要用到。

              大概意思就是把一个页面分成一个个模块然后分别储存,在要用的时候直接分别引用组装就可以了。然后我今天有意识的看了些关于这方面的资料。

              

说起前端模块化开发,大部分人可能只会想到js模块化开发吧,网上也确实有各种各样的js模块化方法,但是鲜有谈论Css模块化开发的吧。因为JS是编程语言,比如业内的seajs、KISSY loader等,都有很成熟的模块化规则和方案了,前端工程师可以采用模块化的方法去编写页面,打包,上线,但是CSS界却没有。

后来,CSS界出现了SASS、LESS之类的语言,这些语言的出现可以说是非常应景的,有一点很重要,拿LESS举例,less支持了模块化,你可以@import ‘xxx.less’的形式导入其他less文件(模块),方便模块化。最近因为研究Css模块化的东西,查询了许多的有关模块化的资料,也确实有所收获,今天我就来介绍一下我了解的Css模块化开发方式吧。

其实,CSS规范里面就已经提到模块化相关内容了,就是@import语法。这个语法是被当前主流浏览器(当然包括ie6)原生支持的。具体怎么用我就不再多介绍了,属于Css基础最基础的部分,如果不会的自行脑补一下吧。为啥大家很少用呢,大概是因为在生产环境单独去用@import,会有较为严重的性能问题,而且不同的浏览器以及不同的用法下也有不同的表现,比较让人郁闷。但是,这并不妨碍《@import成为 CSS模块化 的利器。

           然后我在菜鸟上面看了关于《@import》代码的介绍

docker import : 从归档文件中创建镜像?



打算明天再看一些视频详细介绍,研究一下这个东西。


       收获:

    已经开始搭建自己的CSS代码库,对于HTML基础结构搭建有了新的理解,对于类的命名有了进一步加强。


返回列表 返回列表
评论

    分享到