1. CSS总论 | CSS语法的研究
CSS2.1的语法
CSS产生式
- [] 代表组的概念
- ? 可以存在可以不存在
- | 或
- * 0个或多个
- import 在charset之后其他规则之前,多个
- CDO,CDC HTML注释的起点和止点
- ruleset 普通CSS规则
- media CSS3中media query
- page 用打印的信息(浏览器不会用)
stylesheet
: [ CHARSET_SYM STRING ';' ]? //@charset
[S|CDO|CDC]* [ import [ CDO S* | CDC S* ]* ]*
[ [ ruleset | media | page ] [ CDO S* | CDC S* ]* ]*
CSS总体结构
- @charset
- @import
- rules
- @media
- @page
- rule
CSS知识结构图
2. CSS总论 | CSS @规则的研究
At-rules
- @charset : www.w3.org/TR/css-synt… 声明CSS字符集
- @import :www.w3.org/TR/css-casc… 级联规则
- @media :www.w3.org/TR/css3-con… 有条件规则
- @page : www.w3.org/TR/css-page… 分页媒体(打印)
- @counter-style :www.w3.org/TR/css-coun… 列表前的数字或黑点
- @keyframes :www.w3.org/TR/css-anim… 动画
- @fontface :www.w3.org/TR/css-font… 字体
- @supports :www.w3.org/TR/css3-con… 兼容性不建议使用
- @namespace :www.w3.org/TR/css-name… 命名空间
CSS知识结构图
3. CSS总论 | CSS规则的结构
selector+declaration
div{
background-color:blue;
}
- 选择器
- 声明
- Key
- Properties 声明属性
- Variables: www.w3.org/TR/css-vari…
- Value
标准
-
selectors-3
产生式
selectors_group //产生式根元素 : selector [ COMMA S* selector ]* //COMMA逗号 优先级最低 ; selector : simple_selector_sequence [ combinator simple_selector_sequence ]* ; combinator /* combinators can be surrounded by whitespace */ : PLUS S* | GREATER S* | TILDE S* | S+ //PLUS+, GREATER>, TILDE~ ,空格 ; simple_selector_sequence //简单选择器 : [ type_selector | universal ] //类型选择器|* 在最前 [ HASH | class | attrib | pseudo | negation ]* //# . [] : :not | [ HASH | class | attrib | pseudo | negation ]+ ;
-
selectors-4 增加了很多伪类选择器 状态:W3C Working Draft
-
Key
:root { --main-color: #06c; --accent-color: #006; } /* The rest of the CSS file */ #foo h1 { color: var(--main-color); } /*默认值*/ .component .header { color: var(--header-color, blue); } .component .text { color: var(--text-color, black); } /*用作key*/ .foo { --side: margin-top; var(--side): 20px; } /*替换后成为无效值*/ :root { --not-a-color: 20px; } p { background-color: red; } p { background-color: var(--not-a-color); }
-
css-values-4
/*进行简单计算*/ :root { font-size: calc(100vw / 35); } /*让CSS的值和元素属性绑定*/ Attribute References: attr()
CSS知识结构图
4. CSS总论 | 收集标准
收集第一步: 进入www.w3.org/TR/
收集第二步: 打开控制台输入以下代码并复制结果
JSON.stringify(Array.prototype.slice.call(document.querySelector("#container").children).filter(
e => e.getAttribute("data-tag").match(/css/)).map(e => ({
name: e.children[1].innerText,
href: e.children[1].children[0].href
})))//结果为数组
收集第三步: 将结果命名var standards =
收集第四步: 获取第二步结果页面里面的数据 ``` let iframe = document.createElement('iframe'); document.body.innerHTML = ""; document.body.append(iframe);
function happen(element,event){
return new Promise(function (resolve) {
let handler = () =>{
setTimeout(()=>{resolve();},2001)
element.removeEventListener(event,handler)
}
element.addEventListener(event,handler)
});
}
void async function () {
for (let standard of standards) {
iframe.src = standard.href;
console.log(standard.name);
await happen(iframe,"load")
console.log(iframe.contentDocument.querySelector(".propdef"));
}
}()
// if (getCookie('hide-obsolescence-warning') == '1') setTimeout(removeWIP, 2000);访问次数过多
```
5. CSS总论 | CSS总论总结
6. CSS选择器 | 选择器语法
-
简单选择器
- * 通用选择器
- div svg|a
type selector 选择的是tagName属性 命名空间:HTML SVG MathML - .cls class 空白分隔符
- #id id
- [attr=value]
属性选择器,囊括了class属性选择器id选择器
attr = value name = 值 等号之前加~,表示像class一样支持拿空格分隔的值得序列 等号之前加|,表示这个属性以这个值开头即可 - :hover伪类,元素特殊状态
- ::before 伪元素以双冒号开头,提倡双冒号,这可以更好的分别伪类和伪元素
-
复合选择器
combined
- <简单选择器><简单选择器><简单选择器>
- * 或者 div 必须写在最前面
-
复杂选择器
- <复合选择器><复合选择器> 子孙选择器
- <复合选择器>">"<复合选择器> 父子选择器
- <复合选择器>"~"<复合选择器>
- <复合选择器>"+"<复合选择器>
- <复合选择器>"||"<复合选择器> 选中某一列
7. CSS选择器 | 选择器的优先级
- 简单选择器计数
#id div.a#id { //...... } 1 2 [0, 2, 1, 1] S = 0 * N³+ 2 * N²+ 1 * N¹+ 1 取N = 1000000 S = 2000001000001
// 选择器优先级 div#a.b .c[id=x] [0,1,3,1] #a:not(#b) [0,2,0,0] *.a [0,0,1,0] div.a [0,0,1,1]
// https://www.w3.org/TR/CSS2/cascade.html#specificity
// [a,b,c,d]
// 1、如果样式声明来源于style属性则a=1;
// 2、ID属性的数量 = b;
// 3、其他属性和伪类的数量 = c;
// 4、元素名称和伪元素的数量 = d;
// 5、如果将id作为属性选择器[id = p33]那么优先级为[0,0,1,0];
// 6、:not(), 虽然它本身是不计权重的, 但是写在它里面的 css selector 是需要计算权重的
Some examples:
* {} // a=0 b=0 c=0 d=0 -> specificity = 0,0,0,0
li {} // a=0 b=0 c=0 d=1 -> specificity = 0,0,0,1
li:first-line {} // a=0 b=0 c=0 d=2 -> specificity = 0,0,0,2
ul li {} // a=0 b=0 c=0 d=2 -> specificity = 0,0,0,2
ul ol+li {} // a=0 b=0 c=0 d=3 -> specificity = 0,0,0,3
h1 + *[rel=up]{} // a=0 b=0 c=1 d=1 -> specificity = 0,0,1,1
ul ol li.red {} // a=0 b=0 c=1 d=3 -> specificity = 0,0,1,3
li.red.level {} // a=0 b=0 c=2 d=1 -> specificity = 0,0,2,1
#x34y {} //a=0 b=1 c=0 d=0 -> specificity = 0,1,0,0
style="" // a=1 b=0 c=0 d=0 -> specificity = 1,0,0,0
8. CSS选择器 | 伪类
-
链接/行为
-
:any-link 任何超链接
-
:link :visited
还没有访问 已经访问
:link :visited使用过后无法更改文字颜色以外的属性
-
:hover 鼠标移入
-
:active 激活状态
-
:focus 焦点
-
:target 链接到当前目标
-
-
树结构
-
:empty 是否有子元素
-
:nth-child()
父元素的第几个子元素
支持一种语法 even odd 奇偶 3n+1 4n-1
-
:nth-last-child() 从后往前
-
:first-child :last-child :only-child
第一个子元素 最后一个子元素 只有一个子元素
-
-
逻辑型
-
:not伪类 复合选择器
-
:where :has
-
9. CSS选择器 | 伪元素
- ::before ::after 元素内容前后插入伪元素
- ::first-line 选中第一行
- ::first-letter 选中第一个字母
<::before/>
content content content content
content content content content
content content content content
content content content content
content content content content
content content content content
<::after/>
</div>
<div>
<::first-letter>c</::first-letter> content content content content
content content content content
content content content content
content content content content
content content content content
content content content content
</div>
伪元素
<div>
<::first-line>content content content content </::first-line>
content content content content
content content content content
content content content content
content content content content
content content content content
</div>
思考
• 为什么first-letter可以设置float之类的,而first-line不行呢?
first-letter是在布局完成之后,确定了一段文字中的第一个文字,可以对其操作布局时性能开销小; 而first-line选中的是第一行文字,不同的宽度选中的文字内容不一样,要对其重新布局排版消耗性能大,所以first-letter 可以设置 float 之类的,而 first-line 不行。
• 编写一个match函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div #id.class {
font-size: 20px;
}
</style>
</head>
<body>
<div>
<div class="class" id="id">123</div>
</div>
</body>
<script>
function match(selector, element) {
if (!selector || !element.attributes) {
return false;
}
// reverse 标签匹配从当前元素往外匹配,首先获取当前元素
// 检查一个选择器是否匹配当前元素,需要一级一级往父元素去找
let selectLists = selector.split(" ").reverse();//所有选择器 ["#id.class","div"]
// 将得到的第一个选择器进行检索
let selectList =selectLists[0].match(/(#|.)?[\w]+/g);
if (selectList.length > 1) {
// 重新走一遍match函数
for (let i = 0; i < selectList.length; i++) {
if(!match(selectList[i],element)){
return false;
}
}
// 不返回false
return true;
}
if(selector.charAt(0) == "#"){
var attr = element.attributes['id'].name === 'id';
if(attr && element.attributes['id'].value === selector.replace("#","")){
return true;
}
}else if (selector.charAt(0) == ".") {
var attr = element.attributes['class'].name === 'class'
if (attr) {
return element.attributes['class'].value.split(" ").some((value) => {
return value === selector.replace(".", '');
});
}
}else{
if(element.tagName === selector){
return true;
}
}
return false;
}
console.log(match("div #id.class", document.getElementById("id")));
</script>
</html>