我是三钻,一个在《技术银河》中等你们一起来终生漂泊学习。 点赞是力量,关注是认可,评论是关爱!下期再见 👋
进入重学 CSS 的第一步,首先需要找到一些线索。我们在前面的课程中讲学习方法的部分也讲过,要想建立知识体系骨架,我们需要一个完备性更权威,更全的线索。但是 CSS 现在标准的状态非常复杂,所以我们没有办法找到一份像 JavaScript 或者 HTML 中比较完备的现形标准,能把 CSS 的一切都浓缩在内。
不过这种情况也是我们平时学习知识的一种常态,知识并不是有人给我们总结好一本书,或者能有一个地方包含了所有的知识。一般来说知识都会分布在各种不同的文档当中。
根据 Winter 老师比较喜欢学习一个线索,凡是对于编程语言,都会先从它的语法去了解它。
所以 CSS 也不例外,它也有自己的一套语法体系。但是 CSS 标准是分散开的,我们想找到它完整的语法非常的不容易的。所以我们这里先从 CSS 2.1 语法标准开始。
CSS 2.1 确实是一个比较老的版本了,但是它有一个好处,在 2.1 的版本的时候建立了一个 Snapshot,也就是说没有其他版本去替代它。所以 CSS 2.1 的 Grammar Summary 部分是当时一个比较完整的一份语法列表。
当然现在我们已经大量的引入了 CSS3 了,所以这里面会有一些语法差异和不全。但是总体来讲是一个不错的起点,让我们可以先开始认识 CSS 的语法基础。
这里的语法是使用 “产生式” 来表达的。但是这里会有一些 CSS 中特别的表达方式和标准:
[ ]
—— 方括号代表组的概念?
—— 问号代表可以存在和不存在|
—— 单竖线代表 “或” 的意思*
—— 星号代表 0 个或 多个+ @media
+ @page
+ rule —— 这里基本上就是我们平时写的 CSS 样式规则部分
我们平时写都是在写普通的 CSS 规则,
charset
我们基本都不会用,一般我们都会用UTF-8
。
这里讲到的是 CSS 2.1 的 CSS 结构,在 CSS3 中我们有更多的 @
规则 和 CSS 规则,我们首先要在 CSS3 中找到这两块的所有内容,然后补充道这个总体结构中,那么我们就可以形成 CSS 的总体结构。这时候我们对 CSS 的语法认识就有完备性了。
@charset
: https://www.w3.org/TR/css-syntax-3/
@import
: https://www.w3.org/TR/css-cascade-4/
@media
: https://www.w3.org/TR/css3-conditional/
@page
: https://www.w3.org/TR/css-page-3/
@counter-style
: https://www.w3.org/TR/css-counter-styles-3/
@keyframes
: https://www.w3.org/TR/css-animations-1/
@fontface
: https://www.w3.org/TR/css-fonts-3/
@supports
: https://www.w3.org/TR/css3-conditional/
@namespace
: https://www.w3.org/TR/css-namespaces-3/
这里不是完整的列表,还有 3 个规则,因为 它们本身状态太年轻在讨论状态,要不就是已经没有浏览器支持了,或者是已经被废弃了。分别有
document
、color-profile
、font-feature
。 然后最常用的有三种:@media
、@keyframes
、@fontface
这里我们选中了 HTML 所有的 DIV 并且给予它们一个 blue
的背景颜色。
div { background-color: blue;}
通过以上代码示例,我们看到一段 CSS 代码是有分为
选择器
和声明
两部分的。在我们《实战中理解浏览器原理》的文章中,我们编写我们的CSS parsor
的时候,就是把 CSS parse 成 selector 部分和 declaration 部分。我们这里也会按照这个方法来理解 CSS 规则。
div
) + Key —— 键 (background-color
)
+ Value —— 值 (blue
)
+ Selectors_group —— 选择器组:用逗号分隔
+ Selector —— 选择器:需要用 combinator (组合器) 把多个简单选择器拼在一起的
+ Combinator —— 组合器:+
、>
、~
、空格
+ Simpleselectorsequence —— 简单选择器:类型选择器
、*
一定会在最前面,然后可以是 ID
、class
、attr
、pseudo
等选择器
+ Level 4 和 Level 3 是非常的相似的,但是它的选择器更复杂
+ 增加了很多的伪类选择器、“或” 和 “与” 的关系
+ 而且它的 NOT 也更强大
+ Level 4 的话我们看一看拓展思路就可以了,因为从 2018年12月 开始也没有再更新了
+ 所以目测是遇到问题了,处于比较难推动的阶段,所以投入使用还有很漫长的路要走
+ 可以声明一个双减号开头的变量:--main-color: #06c
+ 然后我们可以在子元素中使用这些 CSS 变量了 color: var(--main-color)
+ 可以跟其他的函数进行嵌套:--accent-background: linear-gradient(to top, var(--main-color), white);
+ 使用 var()
函数的时候是可以给默认值的,传入第二个参数就是默认值:var(--main-color, black)
+ CSS 变量处理可以用作 value,还可以用作 key:先声明了--side: margin-top
然后就可以这样使用 var(--side): 20px
+ 它也是 working draft (工作草稿) 状态,但是实现状态非常的好
+ 而且这个版本一直有保持更新,最后一次更新是 2019年1月份
+ 数字类型有:整型
、百分比
、浮点型
还有带维度 (Dimensions)
+ 长度单位有:相对单位 (em, ex, cap, ch ... )
、视口单位 (vw, vh, vi, vb, vmin, vmax)
、绝对单位 (cm, mm, Q, in, pt, pc px)
+ 其他单位:弧度单位 (deg, grad, rad, turn)
、时间单位 (s, ms)
、频率单位 (Hz, kHz)
、分辨率单位 (dpi, dpcm, dppx)
+ 数据类型:颜色 <color>
、图片 <image>
、2D 位置 <position>
等类型
+ 函数:计算 cal()
、最小值 min()
、最大值 max()
、范围剪切 clamp()
、切换value toogle()
、属性引用 attr()
通过上面讲到的几个部分,我们已经了解了整个 CSS 的架构。但是我们发现整个的 CSS 标准是散落在几份标准当中的,为了我们更好的阅读标准,我们想拿到一份比较完整的标准列表是需要我们做一些工作的。很多时候我们都是需要在零散的标准里面,去搜集一些共性的内容。
接下来我们来做一个小实验,通过类似爬虫的方法,在 W3C 网站上抓取标准的内容。然后我们对他进行一些处理,方便我们后续的一些工作。
首先我们打开 W3C 的标准和草稿的列表页:https://www.w3.org/TR/
这里我们可以看到所有的 W3C 的标准和草稿,但是这里我们只需要 CSS 部分的。如果我们检查元素中查看,我们可以看到其实所有的数据都已经挂载在 DOM 上了,只是前端做了筛选分页而已。
所以我们就可以用一段代码,直接复制到浏览器的 console
中运行就可以筛选出所有 CSS 相关的文章列表了。
// 获取 CSS 相关的标准列表JSON.stringify( Array.prototype.slice .call(document.querySelector('#container').children) .filter(e => e.getAttribute('data-tag').match(/css/)) // 找到有 CSS tag 的 .map(e => ({ name: e.children[1].innerText, url: e.children[1].children[0].href })) // 只获取标题名字和链接);
最终输入的内容如下:
然后我们点击下方的 "Copy
" 即可复制,把这个 JSON 内容保存在一个 JavaScript 文件里面,并且赋予一个变量叫 standards
。在我们后面的爬虫代码中需要用到。
这里我们用一个简单的方法来获取爬取信息,就是在 W3C 原本的页面上开启一个 iframe
,这样我们就可以忽略掉跨域的问题。
let standards = [...] // 这里面的内容就是我们刚刚从 W3C 网页中爬取到的内容 let iframe = document.createElement('iframe');document.body.innerHtml = '';document.body.appendChild(iframe);function happen(element, event) { return new Promise(function (resolve) { let handler = () => { resolve(); element.removeEventListener(event, handler); }; element.addEventListener(event, handler); });}void (async function () { for (let standard of standards) { iframe.src = standard.url; // 让 Iframe 跳转到每个 standards 中的详情页面 console.log(standard.name); await happen(iframe, 'load'); // 等待 iframe 中的页面打开完毕 }})();
然后我们需要的信息就是属性表格中的内容:
如果我们看一下这个 table 的 HTML 代码,我们会发现这个 table 都是有一个 class 名叫 propdef
的。我们就可以用这个特性来获取这个表格中的内容了。
所以我们就可以在 await happen(iframe, 'load')
,后面添加一行代码来答应这个表格的 DOM 元素来看一下:
let iframe = document.createElement('iframe');document.body.innerHTML = '';document.body.appendChild(iframe);function happen(element, event) { return new Promise(function (resolve) { let handler = () => { resolve(); element.removeEventListener(event, handler); }; element.addEventListener(event, handler); });}void (async function () { for (let standard of standards) { iframe.src = standard.url; console.log(standard.name); await happen(iframe, 'load'); console.log(iframe.contentDocument.querySelectorAll('.propdef')); // 这里答应出表格的内容 }})();
领取专属 10元无门槛券
私享最新 技术干货