CSS 世界 阅读笔记:(Ch4-上篇)
CSS 世界 阅读笔记:
对于CSS 这门语言,3 年学习80 分和10 年学习90 分对于产品价值的区别其实有限。
拨开眼前的面纱,定睛一看,会发现,缺的其实不是前端,而是优秀的、有资历的、技术有深度的前端开发人员。
在CSS 的世界里,页面上的任何看似简单的呈现都是由许许多多CSS 属性共同作用的结果。
Ch4 盒尺寸四大家族
4.1 深入理解content
4.1.1 content 与替换元素
1.什么是替换元素
替换元素,顾名思义,内容可以被替换。这种通过修改某个属性值呈现的内容就可以被替换的元素就称为“替换元素”。
(1)内容的外观不受页面上的CSS 的影响。用专业的话讲就是在样式表现在CSS 作用域之外。
(2)有自己的尺寸。
(3)在很多CSS 属性上有自己的一套表现规则。
2.替换元素的默认display 值
元素 | Chrome | Firefox | IE |
---|---|---|---|
<img> | inline | inline | inline |
<iframe> | inline | inline | inline |
<video> | inline | inline | inline |
<select> | inline-block | inline-block | inline-block |
<input> | inline-block | inline | inline-block |
range/file <input> | inline-block | inline-block | inline-block |
hidden <input> | none | none | none |
<button> | inline-block | inline-block | inline-block |
<textarea> | inline-block | inline | inline-block |
3.替换元素的尺寸计算规则
(1)固有尺寸指的是替换内容原本的尺寸。
(2)HTML 尺寸这个概念略微抽象,“HTML 尺寸”只能通过HTML 原生属性改变,这些HTML 原生属性包括<img> 的width 和height 属性、<input> 的size 属性、<textarea> 的cols 和rows 属性等。
(3)CSS 尺寸特指可以通过CSS 的width 和height 或者max-width/min-width 和max-height/min-height 设置的尺寸,对应盒尺寸中的content box。
如果没有CSS 尺寸和HTML 尺寸,则使用固有尺寸作为最终的宽高。
如果没有CSS 尺寸,则使用HTML 尺寸作为最终的宽高。
如果有CSS 尺寸,则最终尺寸由CSS 属性决定。
如果“固有尺寸”含有固有的宽高比例,同时仅设置了宽度或仅设置了高度,则元素依然按照固有的宽高比例显示。
如果上面的条件都不符合,则最终宽度表现为300 像素,高度为150 像素,宽高比2:1。
内联替换元素和块级替换元素使用上面同一套尺寸计算规则。
CSS 世界中的替换元素的固有尺寸有一个很重要的特性,那就是“我们是无法改变这个替换元素内容的固有尺寸的”。
div:before {
content: url(1.jpg);
display: block;
width: 200px; height: 200px;
}
图片中的content 替换内容默认的适配方式是填充(fill),也就是外部设定的尺寸多大,我就填满、跟着一样大。尺寸变化的本质并不是改变固有尺寸,而是采用了填充作为适配HTML 尺寸和CSS 尺寸的方式。
4.替换元素和非替换元素的距离有多远
观点1:替换元素和非替换元素之间只隔了一个src 属性!
由于我们平时使用图片肯定都会使用src 属性,所以难免会思维定式,认为<img> 等同于图片,实际上完全不是的。如果我们把src 属性去掉,<img> 其实就是一个和<span> 类似的普通的内联标签,也就是成了一个非替换元素。
<img alt="美女沉思图" data-src="1.jpg">
<p><button>设置src属性显示图片</button></p>
img {
display: inline-block;
width: 256px; height: 192px;
/* 隐藏Firefox alt文字 */
color: transparent;
position: relative;
overflow: hidden;
}
img:not([src]) {
/* 隐藏Chrome alt文字以及银色边框 */
visibility: hidden;
}
img::before {
/* 淡蓝色占位背景 */
content: "";
position: absolute; left: 0;
width: 100%; height: 100%;
background-color: #f0f3f9;
visibility: visible;
}
img::after {
/* 黑色alt信息条 */
content: attr(alt);
position: absolute;
left: 0; bottom: 0;
width: 100%;
line-height: 30px;
background-color: rgba(0,0,0,.5);
color: white;
font-size: 14px;
transform: translateY(100%);
/* 来点过渡动画效果 */
transition: transform .2s;
visibility: visible;
}
img:hover::after {
transform: translateY(0);
}
var eleButton = document.querySelector('button'),
eleImg = document.querySelector('img');
if (eleButton && eleImg) {
var initValueButton = eleButton.innerHTML;
// 图片地址
var srcImage = eleImg.getAttribute('data-src');
// 移除该属性
eleImg.removeAttribute('data-src');
// 按钮点击事件
eleButton.addEventListener('click', function() {
if (this.innerHTML == initValueButton) {
this.innerHTML = '移除src属性';
// 图片显示
eleImg.setAttribute('src', srcImage);
} else {
this.innerHTML = initValueButton;
// src属性移除
eleImg.removeAttribute('src');
}
});
}
此时,图片src 没有,因此,::before 和::after 可以生效,我们就可以把alt 属性值通过content 属性呈现出来。当我们点击按钮给图片添加一个src 地址时,图片从普通元素变成替换元素,原本都还支持的::before 和::after 此时全部无效,此时再hover 图片,是不会有任何信息出现的。
观点2:替换元素和非替换元素之间只隔了一个CSS content 属性!
替换元素之所以为替换元素,就是因为其内容可替换,而这个内容就是margin、border、padding 和content 这4 个盒子中的content box,对应的CSS 属性是content,所以,从理论层面讲,content 属性决定了是替换元素还是非替换元素。
如果图片原来是有src 地址的,我们也是可以使用content 属性把图片内容给置换掉的,于是,我们就能轻松实现hover 图片变成另外一张图片的效果。要是放在以前,我们只能借助background-image 或者两个<img> 元素显隐控制实现。
<img class="emoji" src="laugh.png">
.emoji:hover {
content: url(laugh-tear.png);
}
然后,还有一点有必要说明一下,content 属性改变的仅仅是视觉呈现,当我们以右键或其他形式保存这张图片的时候,所保存的还是原来src 对应的图片。
不仅如此,使用content 属性,我们还可以让普通标签元素变成替换元素。
<h1>《CSS世界》</h1>
h1 {
content: url(logo.png);
}
传统CSS 代码的<h1>是一个普通元素,因此需要设定尺寸隐藏文字;但是,使用content 属性实现,<h1>分分钟就变成了替换元素,文字自动被替换,同时尺寸规则就是替换元素的尺寸规则,完美适应原始图片大小。
此外,虽然视觉上文字被替换了,但是屏幕阅读设备阅读的还是文字内容,搜索引擎SEO
抓取的还是原始的文本信息,因此,对页面的可访问性等没有任何影响。
5.content 与替换元素关系剖析
(1)我们使用content 生成的文本是无法选中、无法复制的,好像设置了user-select: none 声明一般。
(2)不能左右:empty 伪类。:empty 是一个CSS 选择器,当元素里面无内容的时候进行匹配。
<h4>有内容</h4>
<div class="box">有内容</div>
<h4>无内容</h4>
<div class="box"></div>
<h4>空格也算内容</h4>
<div class="box"> </div>
<h4>伪元素不算内容</h4>
<div class="box pseudo"></div>
.box {
width: 216px;
padding: 10px;
border: 10px solid #cd0000;
margin: auto;
}
.box:empty {
border-style: dashed;
}
(3)content 动态生成值无法获取。
4.1.2 content 内容生成技术
1.content 辅助元素生成
清除浮动;
.clear:after {
content: '';
display: table; /* 也可以是'block' */
clear: both;
}
辅助实现“两端对齐”以及“垂直居中/上边缘/下边缘对齐”效果。:before 伪元素用于辅助实现底对齐;:after 伪元素用于辅助实现两端对齐。
<div id="box" class="box"><i class="bar"></i>
<i class="bar"></i>
<i class="bar"></i>
<i class="bar"></i>
</div>
.box {
width: 256px;
height: 256px;
border-bottom: 1px dashed #ccc;
text-align: justify;
}
.box:before {
content: "";
display: inline-block;
height: 100%;
}
.box:after {
content: "";
display: inline-block;
width: 100%;
}
.bar {
display: inline-block;
width: 20px; height: 0;
}
2.content 字符内容生成
content 字符内容生成就是直接写入字符内容,中英文都可以,比较常见的应用就是配合@font-face 规则实现图标字体效果。除常规字符之外,我们还可以插入Unicode 字符,比较经典的就是插入换行符来实现某些布局或者效果。
正在加载中<dot>...</dot>
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;
}
@keyframes dot {
33% { transform: translateY(-2em); }
66% { transform: translateY(-1em); }
}
3.content 图片生成
content 图片生成指的是直接用url 功能符显示图片。不支持CSS3 渐变背景图。设置宽高无法改变图片的固有尺寸。
4.了解content 开启闭合符号生成
content 支持的属性值中有一对不常用的open-quote 和close-quote 关键字,顾名思义,就是“开启的引号”和“闭合的引号”,使用纯正的中文解释就是“上引号”和“下引号”。
CSS 世界中有一个名为quotes 的属性,可以指定open-quote 和close-quote 字符具体是什么。
5.content attr 属性值内容生成
attr 功能符中的属性值名称千万不要在外面加个引号,否则浏览器会认为是无效的声明。
6.深入理解content 计数器
所谓CSS 计数器效果,指的是使用CSS 代码实现随着元素数目增多,数值也跟着变大的效果。
(1)属性counter-reset。顾名思义,就是“计数器-重置”的意思,主要作用就是给计数器起个名字。默认是0,counter-reset 的计数重置可以是负数,另外,counter-reset 还可以设置为none 和inherit。取消重置以及继承重置。
(2)属性counter-increment。顾名思义,就是“计数器递增”的意思。值为counterreset 的1 个或多个关键字,后面可以跟随数字,表示每次计数的变化值。如果省略,则使用默认变化值1。
普照源(counter-reset)唯一,每普照(counter-increment)一次,普照源增加一次计数值。无论位置在何处,只要有counter-increment,对应的计数器的值就会变化。
计数器的数值变化遵循HTML 渲染顺序,遇到一个increment 计数器就变化,什么时候counter 输出就输出此时的计数值。
counter-reset 可以一次命名两个计数器名称,counter-increment 自然有与之呼应的设定,在写法上也是空格区分就可以了。
正如本节开始时提到的,这变化的值不一定是1,可以灵活设置。值还可以是none 或者inherit。
(3)方法counter()/counters()。这是方法,不是属性。
counter(name);
counter(name, style);
style 参数的作用是:我们递增递减可以不一定是数字,还可以是英文字母或者罗马文等。
counter 还支持级联。也就是说,一个content 属性值可以有多个counter()方法。
counters(name, string);
其中,string 参数为字符串(需要引号包围的,是必需参数),表示子序号的连接字符串。
显示 content 计数值的那个DOM元素在文档流中的位置一定要在counter-increment 元素的后面,否则是没有计数效果的。
<p>我叫王小二,字如其名,下面要出现的数字是:</p>
<p class="counter counter1"></p>
<p>我叫王小二,万万没想到,会出现另外一个数字:</p>
<p class="counter counter2"></p>
<p>我本名王小二,万万没想到,我现在居然成了王小...</p>
<p class="counter counter3"></p>
<p>我叫王小二,万万没想到,兄弟情深,计数递增!</p>
<p class="counter counter4"></p>
<p>我叫王小二,万万没想到,我变成了罗马人!</p>
<p class="counter counter5"></p>
<p>我叫王小二,万万没想到,一着不慎,娃娃连营满地滚:</p>
<div class="reset">
<div class="counter6">我是王小二
<div class="reset">
<div class="counter6">我是王小二的大儿子</div>
<div class="counter6">我是王小二的二儿子
<div class="reset">
<div class="counter6">我是王小二的二儿子的大孙子</div>
<div class="counter6">我是王小二的二儿子的二孙子</div>
<div class="counter6">我是王小二的二儿子的小孙子</div>
</div>
</div>
<div class="counter6">我是王小二的三儿子</div>
</div>
</div>
<div class="counter6">我是王小三</div>
<div class="counter6">我是王小四
<div class="reset">
<div class="counter6">我是王小四的大儿子</div>
</div>
</div>
</div>
.counter {
counter-reset: wangxiaoer 2 wangxiaosan 3;
font-size: 32px;
font-family: Arial black;
color: #cd0000;
}
.counter1:before {
content: counter(wangxiaoer);
}
.counter2:before {
content: counter(wangxiaoer);
}
.counter2:after {
content: counter(wangxiaosan);
}
.counter3 {
counter-increment: wangxiaoer;
}
.counter3:before {
content: counter(wangxiaoer);
counter-increment: wangxiaoer;
}
.counter4:before,
.counter4:after {
content: counter(wangxiaoer);
counter-increment: wangxiaoer;
}
.counter5:before,
.counter5:after {
display: block;
content: counter(wangxiaoer, lower-roman);
counter-increment: wangxiaoer;
}
.reset {
padding-left: 20px;
counter-reset: wangxiaoer;
}
.counter6:before {
content: counters(wangxiaoer, '-') '. ';
counter-increment: wangxiaoer;
}
7.content 内容生成的混合特性
各种content 内容生成语法是可以混合在一起使用的。
4.2 温和的padding 属性
4.2.1 padding 与元素的尺寸
CSS 中默认的box-sizing 是content-box,所以使用padding 会增加元素的尺寸。
内联元素padding 对视觉层和布局层具有双重影响。
首先,我们可以在不影响当前布局的情况下,优雅地增加链接或按钮的点击区域大小。
利用内联元素的padding 实现高度可控的分隔线。
a + a:before {
content: "";
font-size: 0;
padding: 10px 3px 1px;
margin-left: 6px;
border-left: 1px solid gray;
}
4.2.2 padding 的百分比值
padding 百分比值无论是水平方向还是垂直方向均是相对于宽度计算的!
.box {
padding: 10% 50%;
position: relative;
}
.box > img {
position: absolute;
width: 100%; height: 100%;
left: 0; top: 0;
}
对于内联元素,其padding 是会断行的,也就是padding 区域是跟着内联盒模型中的行框盒子走的。
内联元素的垂直padding 会让“幽灵空白节点”显现,也就是规范中的“strut”出现。由于内联元素默认的高度完全受font-size 大小控制,因此,我们只要:font-size: 0; 此时,“幽灵空白节点”高度变成了0,高和宽就会一样,和块状元素一样的正方形就出现了。
4.2.3 标签元素内置的padding
(1)ol/ul 列表内置padding-left,但是单位是px 不是em。
(2)很多表单元素都内置padding。既语义良好行为保留,同时UI 效果棒兼容效果好的实现小技巧,那就是使用<label>元素。
4.2.4 padding 与图形绘制
padding 属性和background-clip 属性配合,可以在有限的标签下实现一些CSS 图形绘制效果。
不使用伪元素,仅一层标签实现大队长的“三道杠”分类图标效果。
.icon-menu {
display: inline-block;
width: 140px; height: 10px;
padding: 35px 0;
border-top: 10px solid;
border-bottom: 10px solid;
background-color: currentColor;
background-clip: content-box;
}
不使用伪元素,仅一层标签实现双层圆点效果。
.icon-dot {
display: inline-block;
width: 100px; height: 100px;
padding: 10px;
border: 10px solid;
border-radius: 50%;
background-color: currentColor;
background-clip: content-box;
}