枯燥的代码总是过目就忘,鲜活的角色总是印象深刻。 ——《CSS世界》
前言
CSS这门语言就像被遗失的世界,很少有人专注于研究CSS。张鑫旭的《CSS世界》不会讲太多CSS的属性。区别传统的页面布局,他会根据规范和实战详细挖掘CSS不为人知的潜力。
在CSS世界里,HTML是魔法石,CSS属性是魔法师,属性值就是魔法技能,而浏览器就是他们所在的王国。
css变量
这个功能是书中没有,是突然想起来的,虽然相比Less、Sass比较繁琐,但是了解一下还是不错的。而且主流浏览器都支持。 只需要两点:声明:声明变量的时候,变量名前面要加两根连词线(--)。
使用:var()函数用于读取变量。
<style>
body {
--foo: #7F583F;
--bar: #F7EFD2;
}
.demo{
background-color: var(--foo);
height: 40px;
}
style>
<body>
<div class="demo">
<a>Demoa>
div>
body>
关于CSS变量详细的介绍,可以查看阮一峰的博客《CSS 变量教程》。
CSS世界的流
整书离不开的基调就是"流"。纵观CSS的发展,离不开两个特点“层叠”和“流”。 关于层叠,类似HTML标签,一层一层构建起整个“骨架”。同样css世界也是如此,这也就是我们常见的样式冲突,或者可以理解为“权重“。书中有一个很贴切的词叫“论资排辈“。 关于流,我们听到最多的是文档流, 流是一种特性,像水一样,有一个很贴切的例子就是width:auto。 关于宽度的默认值:auto,有4种不同的表现:充分利用可用空间
包裹性:盒子的大小由子元素的宽度决定(内联块元素)
收缩到最小:最常见的是table-layout为auto的表格,某一列的宽度被挤到最小。
超出容器限制:父元素定宽,父元素设置white-space:nowrap。子元素会随着内容的长度超出父元素宽度。
如果我们想要使用流特性可以设置display:block,这是“块级盒子”的流特性。但是如果你“多此一举”的设置width:100%,就会使块级元素流动性丢失。
流特性还有一个很好的体现就是自动换行,标签按钮才会自动换行,标签按钮,默认 white-space:pre,是不会换行的,需要将 pre 值重置为默认的 normal。
鑫三无准则
“鑫三无准则”,即“无宽度,无图片,无浮动”。为什么要“无宽度”?
因为块级元素一旦设置了宽度失去了流动性,就是常见的“砌砖头”、“搭积木”的思维方式!虽然效果一样,但是如果宽度发生变化,就会伴随着重新计算。
一个简单的例子:我们需求是一个宽度为100px的盒子,1px的边框
.fa{
border: 1px solid #ccc;
width: 98px;
}
为什么要“无浮动”?
浮动元素会影响整个文档布局,它会脱离标准流。而且你还需要清除浮动。浮动元素是真正的“牵一发而动全身”。
为什么要无“图片”? 这里的无图片不是真正要通过CSS代替所有图片,虽然理论上可以,但是运算量太大。这里的无图片是用CSS图形生成技术。
这里有45个通过CSS实现的形状,可以点击去查看CSS实现的小图标。
宽度分离原则
“宽度分离原则”,就是CSS中的width属性不与影响宽度的padding/border属性共存。当一件事情的发展可以被多个因素所左右的时候,这个事情最终的结果就会变数很大而不可预期。 如果设计师想要一个102宽度的盒子和1px的边框:
.box {
width: 100px;
border: 1px solid;
}
如果使用“宽度分离原则”
.father {
width: 102px;
}
.son {
border: 1px solid;
}
父元素定宽,子元素因为 width 使用的是默认值 auto,所以会如水流般 自动填满父级容器。
虽然说过深的嵌套会增加页面渲染和维护成本,但是这个成本相比收益来说简直就是毛毛雨。
比!important更强
众所周知,!important的权重是最大的,在业界相当于“泰坦尼克“。但就是这么厉害的!important被max-width一个浪头拍翻了。
.demo {
height: 40px;
width: 100px !important;
max-width: 20px;
}
你可能会说他们不是一个属性啊,但是表现层表现形式是一样的,而且还涉及到另一个规则:
超越最大
与上述相反,超越最大指的是min-width覆盖max-width,此规则发生在 min-width 和 max-width冲突的时候。
.demo {
background-color: var(--foo);
height: 40px;
width: 100px !important;
min-width: 1400px;
max-width: 1200px;
}
幽灵空白节点
在 HTML5 文档声明中,内联元素的所有解析和渲染表现就如同每个行框盒子的前面有一个“空白节点”一样。这个“空白节点”永远透明,不占据任何宽度,看不见也无法通过脚本获取,就好像幽灵一样, 但又确确实实地存在,表现如同文本节点一样,因此,我称之为“幽灵空白节点”。 CSS世界
这个幽灵空白节点很常见,比如这样:
<body>
<style>
.fa {
background-color: #7F583F;
}
.so {
display: inline-block;
}
style>
<div class="fa">
<span class="so">span>
div>
body>
按传统思维来说高度为0,但是不是这样,浏览器不同可能“幽灵空白节点“的高度不同。
我的chrome版本是版本 83.0.4103.116,这里为什么是22px就解释不清了。
content内容生成技术
content属性最常见就是清除浮动,几乎都是用在::before/::after伪元素中。 content有一个很具有代表性的应用就是辅助实现“两端对齐“以及”垂直居中“效果,活脱脱一个弹性盒子布局。
.box {
width: 256px;
height: 256px;
/* 两端对齐关键 */
text-align: justify;
border-bottom: 1px solid #cccccc;
}
.box:before {
content: "";
display: inline-block;
height: 100%;
}
.box:after {
content: "";
display: inline-block;
width: 100%;
}
.bar {
display: inline-block;
width: 20px;
}
:before 伪元素用于辅助实现底对齐,:after伪元素用于辅助实现两端对齐,但这种方法也有不足之处,就是HTML代码需要注意有些地方不能换行或者空格,有些地方则必须要换行或者有空格,这在多人协作的时候就容易出问题。
还有一个例子是动态加载页面内容的时候,经常用的"正在加载中...",后面这三个点要让他动起来。
<div class="box">
正在加载中<dot>...dot>
div>
dot {
display: inline-block;
height: 1em;
line-height: 1;
text-align: left;
vertical-align: -.25em;
overflow: hidden;
}
dot::before {
display: block;
content: '...\A..\A.';
white-space: pre-wrap;
animation: dot 3s infinite step-start both;
background-color: aquamarine;
}
@keyframes dot {
33% {
transform: translateY(-2em);
}
66% {
transform: translateY(-1em);
}
}
'\A'其实指的是换行符中的 LF 字符,LF 是将光标“垂直”移动到下一行;3 个点在第一行的目的在于兼容 IE9 浏览器。
vertical-align版弹框居中
如果你想要实现一个居中的弹框dialog,你会想到什么?定位套定位?定位+flex布局吗? 这里有一个很非常棒的实现:
<div class="container">
<div class="dialog">
<span>内容占位span>
div>
div>
.container {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: rgba(0, 0, 0, .5);
text-align: center;
white-space: nowrap;
overflow: auto;
z-index: 99;
}
.container:after {
content: '';
display: inline-block;
height: 100%;
vertical-align: middle;
}
.dialog {
display: inline-block;
vertical-align: middle;
border-radius: 6px;
background-color: #fff;
padding: 20px;
text-align: left;
white-space: normal;
}
强大的direction
direction只有两个值,非常好记:ltr(默认)、rtl。ltr就是left-to-right,同样rtl也是。 direction用来改变水平流向。 举个例子,我们可以改变元素水平排放位置:
<body>
<style>
.dir {
direction: rtl;
background-color: chocolate;
color: aliceblue;
width: 100px;
text-align: center;
}
style>
<div class="dir">
<span>1span>
<span>2span>
div>
body>
效果如上图,本来的顺序是12,现在我们改变了水平流向版变为21。
同样html有个dir的属性指的就是direction。
<div class="dir" dir="rtl">
<span>1span>
<span>2span>
div>
可能你会问,如果我不是两个元素,只是一个元素,想要改变文本水平排序,如下怎么办?
<div class="dir" dir="rtl">
<span>1234567span>
div>
把1234567变为7654321,这里你首先想到的是什么?反转字符串?写个算法吗?
没必要,我们有unicode-bidi,你可以把 unicode 理解为“字符集”, 而 bidi 则是单词 bidirectionality 的简写,中文意思是“双向性”。
<body>
<style>
.dir {
/* direction: rtl; */
background-color: chocolate;
color: aliceblue;
width: 100px;
text-align: center;
unicode-bidi: bidi-override;
}
style>
<div class="dir" dir="rtl">
<span>12345678span>
div>
body>
CSS世界充斥着神奇与未知,等着我们不断探索。js很强大,但是我们不妨换个角度,CSS是否可以实现?