<CSS世界>读书笔记

最近在看张鑫旭的<<CSS世界>>,对里面说的一些干货做了点总结,如果希望看到更多知识,请自行购买.

概论

何为流?

“流”实际上是CSS世界中的一种基本的定位和布局机制,可以理解为现实世界的一套物理规则,”流”和现实世界的”水流”有异曲同工之妙.就好像我们把水流入一个容器,水面一定是平整的,我们在水中放入物体,水面升高物体依次排列.所以”流”就是CSS世界中引导元素排列和定位的一条看不见的水流.

流,元素与基本尺寸

块级元素

“块级元素”和display:block;不是一个概念.比如<li>元素默认的display是list-item,<table>对应的display是table,但它们都是块级元素,因为它们符合块级元素的特征,也就是一个水平流上只能单独显示一个元素,多个元素则换行显示.正是由于块级元素的换行特性,理论上它都可以配合clear属性来清除浮动.

1
2
3
4
5
.clear:after{
content: '';
display: table;//或block等.
clear: both;
}

外部尺寸和内部尺寸

当一个元素的尺寸由外部元素决定就称为外部尺寸,当一个元素的尺寸由内部元素决定就称为内部尺寸.

深藏不漏的width: auto

  • 正常流宽度

    在页面中随便扔一个div元素,它就会具备block容器的流特性.

1
2
3
4
a{
display: block;
width: 100%;
}

a元素的display 默认是 inline,当它设置为 block的时候使其具有块状化.但width设置为100%则完全没有必要.”鑫三无原则”,即”无宽度,无图片,无浮动”.为何无宽度?因为表现为”外部尺寸的”块级元素一旦设置了宽度,流动性就失去了.所谓流动性,并不是看上去宽度为100%那么简单,而是一直margin/border/padding以及content内容区域自动分配水平空间的机制.

  • 格式化宽度

    格式化宽度值出现在”绝对定位模型”中,也就是当position为absolute或fixed元素中,默认情况下,绝对定位元素的宽度是由内部尺寸决定的,但是有一种情况宽度由外部尺寸决定.对于非替换元素(…)当left/right或top/bottom对立的属性值同时存在时,元素的宽度为格式化宽度

    1
    2
    3
    4
    5
    6
    7
    8
    9
    div1{
    width: 1000px;
    position: relative;
    div2{
    position: absolute;
    left: 20px;
    right: 20px;
    }
    }

    由以上样式可知,div2的宽度为1000-20-20 = 960

  • 内部尺寸和流式特性

    button按钮是CSS极具代表的inline-block元素,是展示”包裹性”最好的例子,具体表现为:按钮文字越多宽度越宽(内部尺寸特性),但文字足够多,在容器宽度处自动换行(自适应特性).

    包裹性在实际开发中的用处: 页面某个模块文字内容是动态的,希望文字少的时候居中显示,文字多的时候居左显示.代码如下:

    1
    2
    3
    4
    5
    6
    7
    .box{
    text-align: center;
    }
    .content{
    display: inline-block;
    text-align: left;
    }
  • width值作用的细节

    CSS盒模型的组成模式有两种: 一种是border-box.即padding和border也被包含在width和height中的怪异下的盒模型,还有一种是content-box为标准模式下的盒模型.

    给width属性赋一个值,该值作用在content上,且一旦设定width值,该元素就没有了流动性,所以提出”无宽度准则”,这样会更灵活,容错性更强.

  • CSS流体布局下的宽度分离原则(便于维护)

    也就是CSS中的width属性不与其他影响宽度的padding/border/margin属性共存.width属性独占一层标签,而padding/border等属性利用流动性在内部自适应实现.

    1
    2
    3
    4
    5
    6
    7
    8
    .father{
    width: 180px;
    .son{
    margin: 0 20px;
    padding: 20px;
    border: 1px solid;
    }
    }

相对简单单纯的height: auto

CSS的默认流是水平方向的,宽度是稀缺的,高度是无限的,所以宽度的分配规则比较复杂,高度显得比较随意.

  • 关于height: 100%

    对于width属性就算父元素的width是auto,其百分比值也是支持的.但是,对于height属性,如果父元素的height为auto,只要子元素在文档流中,其百分比的值就被忽略了.我们发现百分比高度值想要生效,其父级必须有一个可以生效的高度值.

    要明白其中的原因要先了解浏览器渲染的基本原理.首先下载文档内容,加载头部的样式资源,然后从上而下,自外而内的顺序渲染DOM内容.因此,当渲染到父元素的时候,子元素的width:100%;并没有渲染,宽度就是内容的宽度,等渲染到子元素时,父元素宽度已经固定,此时width:100%;就是父元素的宽度.宽度不够溢出就好了.overflow属性就是为此而生的.为什么宽度支持,高度不支持呢?规范中给出了答案,如果包含块的高度没有显式指定(即高度由内容决定),并且该元素不是绝对定位,则计算值为auto.一句话总结就是,高度没有显式指定则解释为auto,再和百分比计算结果为NaN

    想要他生效只有如下设置:

    1
    2
    3
    html,body{
    height:100%;
    }
    1
    2
    3
    4
    div{
    height:100%;
    position: absolute;
    }
  • max-width/height,min-width/height与width/height区别

    width/height的默认值是auto,而min-width/height 的默认值是0,max-width/height的默认值是none.

    他们三者也有一套相互覆盖的规则:超越!important,超越最大

    1
    2
    3
    4
    <img src="1.jpg" style="width: 480px!important"/>
    img{
    max-width: 260px;//max-width会覆盖width.
    }
    1
    2
    3
    4
    5
    div{
    min-width: 1400px;
    max-width: 1200px;
    //当min比max还要大的时候,遵循'超越最大'原则
    }

内联元素

​ inline和block是流式布局的本质所在.从作用上来讲,块级负责结构,内联负责内容.且内联元素设计的属性非常多,且往往具有继承属性.

​ 从定义看,内联元素与display:inline不是一个概念.因为display:inline-block;display:inline-table;也是内联元素,因为他们的外在盒子都是内联元素.

从表现上,内联元素的典型特征就是可以和文字显示在一行.因此,文字是内联元素,按钮也是内联元素,输入框下拉框都是.

盒尺寸四大家族

深入理解content

  • 什么是替换元素?

    根据”外在盒子”是内联还是块级,我们把元素分为内联元素和块级元素.而根据是否具有可替换内容我们把元素分为替换元素和非替换元素.举个例子,<img src="1.jpg">但我们把src换为2.jpg图片就会替换,这种通过修改某个属性值就可以被替换的元素称为”替换元素”.所以的替换元素都是内联水平元素.

    替换元素有三种尺寸,分别为固有尺寸,HTML尺寸,CSS尺寸.

    1
    2
    3
    4
    5
    6
    7
    <img src="1.jpg"> /如果没有HTML尺寸和CSS尺寸,则使用固有尺寸即图片的尺寸/
    <img src="1.jpg" width="128" height="96"> /如果没有CSS尺寸则使用HTML尺寸/
    <img src="1.jpg">
    img{
    width:200px;
    height:100px;/如果有css尺寸则使用css尺寸/
    }

    CSS世界中的替换元素有一个很重要的特性,那就是’我们无法改变这个替换元素内容的固有尺寸’.那为什么我们设置width和height会影响图片尺寸呢?那是因为图片中的content替换内容的默认适配方式是”填充”,不管设置的尺寸有多大,就填充多大.在CSS3之前这种适配方式是不能修改的.CSS3我们可以通过object-fit属性修改该方式,例如<img>元素的默认声明是object-fit:fill;如果我们设置为object-fit:none;那么图片的尺寸就完全不受控制.如果我们设置为object-fit: contain;则图片保持比例尽可能的利用HTML的尺寸但又不会超出的方式显示.

    替换元素和非替换元素的区别主要在于src和content.

  • content生成辅助元素

    实际项目中,content属性主要用于::before以及::after这两个伪元素中.此应用的核心点不在content上,而在伪元素上,所以我们通常会写content:''; 生成辅助元素后再实现特定布局或实现图形效果.辅助元素最常用的应用是清除浮动.如下:

    1
    2
    3
    4
    5
    .clear:after{
    content: '';
    display: block;
    clear: both;
    }
  • content字符内容生成

    content字符内容生成就是直接写入字符内容,中英文都可以,比较常见的就是配合@font-face规则实现图标字体效果.

  • content图片生成

    content图片生成指的是直接使用url功能符显示图片.

    1
    2
    3
    div:before{
    content: url(1.jpg);
    }

    但我们对于图片的宽高不好控制,无法改变图片的固有尺寸.所以我们通常使用background-image.

    1
    2
    3
    4
    div:before{
    content: '';
    background: url(1.jpg)
    }
  • content计数器

    主要是两个属性和一个方法.

    counter-reset: 计数器名字 计数器的默认值;

    counter-increment: 计数器名字 递增的值(省略的话默认是1);

    方法:counter(name) 显示计数.

温和的padding属性

  • padding和元素的尺寸

    因为CSS默认的box-sizing是content-box,所以使用padding会影响元素的尺寸.但对于内联元素(不包括替换元素)而言,padding影响水平方向,而不影响垂直方向,这样的说法也不完全准确.由于内联元素没有可视宽度和可视高度的说法,垂直方向完全受line-height和vertical-align的影响,所以从视觉上来说,padding在垂直方向上没有起作用,但是我们给它加个背景色会发现其尺寸确实受到影响了.在实际开发中,我们可以在不影响布局的前提下,优雅的增加链接或按钮的点击区域大小.

  • padding的百分比取值

    padding的值和margin值不同之处在于,padding的值不可以是负数.还有,padding的值如果是百分比,不论是水平方向还是垂直方向都是相对于宽度来说的.

  • padding与图像绘制

    padding和background-clip属性配合可以在有限的标签下实现一些CSS绘制效果.

    比如如何用一个标签绘制”大队长”三道杠的分类图标效果.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    .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;
    }

激进的margin属性

  • 相关概念

    元素尺寸: border + padding + content

    元素内部尺寸: padding + content

    元素外部尺寸: margin + border + padding + content

  • margin与元素尺寸以及相关布局

    一旦宽度设定,margin就无法改变元素尺寸.

    1
    2
    3
    4
    .div{
    width: 100px;
    margin: 0 -20px;//元素宽度还是100px
    }

    只要元素的尺寸表现符合’充分利用可用空间’无论是垂直方向还是水平方向都可以通过margin改变尺寸.

    1
    2
    3
    4
    5
    6
    .father{
    width: 100px;
    }
    .son{
    margin: 0 -20px; //该元素空间为140px;
    }

    正是这种具有流体特性下的改变尺寸特性,margin可以很方便的实现很多流体布局效果,比如说一侧定宽,一侧自适应.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    .left{
    width:100px;
    height:100px;
    float: left;
    }
    .right{
    height: 100px;
    margin-left: 100px;
    }
  • margin的百分比值

    和padding一样,margin的百分比值无论是水平方向还是垂直方向都是相对于宽度计算的.

  • margin的合并

    块级元素的margin-top和margin-bottom通常会合并为一个margin.我们可以捕获两点重要信息,一是块级元素,二是垂直方向.

    margin合并的计算规则:正正取大值,正负值相加,负负最负值.

  • 深入理解margin: auto;

    我们首先要知道,有时候元素就算没有设置height和width,也会自动填充和自动填充对应的方位.假设一个外部的容器宽度是300px, 而内部的容器因为设置宽度为200px而导致原本应该自动填满的空间现在有100px闲置了,margin: auto就是为了填充这个闲置的尺寸的.margin:auto;的填充规则是: 如果一侧定值,一侧auto,则auto为剩余的空间大小.如果两侧都是auto,则平分剩余空间.

    当我们想要某个块级元素右对齐时,脑子里不要就一个float:right;,很多时候margin-left:auto;才是最佳实践.浮动毕竟是个”魔鬼”,margin属性的auto计算就是为了块级元素左右对齐而设计的,和内联元素的text-align控制左右对齐相呼应.

    我们可能会发现margin:auto;并不能实现垂直居中,但是我们可以利用绝对定位实现这个需求.因为绝对定位后,top/bottom/left/right会自动填充,但又因为设置了宽高,导致多余的空间闲置,这时margin:auto;就可以计算空间了.

    1
    2
    3
    4
    5
    6
    .son{
    position: absolute;
    top:0; right: 0; bottom: 0: left:0;
    width:200px; height:100px;
    margin: auto;//实现垂直居中.
    }

功勋卓越的border属性

  • border与透明边框技巧

    优雅的增加点击区域大小.

    1
    2
    3
    4
    5
    .click{
    width:16px;
    height: 16px;
    border: 11px solid transparent;
    }

    三角形图形绘制

    1
    2
    3
    4
    5
    div{
    width: 0;
    border: 10px solid;
    border-color: #f30 transparent transparent;
    }

内联元素与流

字母x是CSS中隐匿的举重若轻的角色

各种内联相关模型中,凡是涉及垂直方向的排版或是对齐的,都离不开最基本的基线.字母x下的下边缘就是基线.

vertical-align:middle;并不是绝对的垂直居中对齐,这里的middle是基线往上1/2 x-height的高度,也就是字母x的交叉点的位置.所以middle得垂直居中只是一种近似效果.

字母X衍生了x-height(字母x的高度)的概念,并进一步衍生出了ex,ex是css中的一个尺寸单位,是一个相对单位,指的是小写字母x的高度.其实就是x-height.

内联元素的基石 line-height

思考下面的问题,一个默认的空div高度是0,里面写上几个文字后高度就有了,这个高度从何而来?

不少人认为是由文字把内容撑开的,但本质上是由line-height属性所决定的,对于文本这样的纯内联元素,line-height就是高度计算的基石.

为什么line-height可以让内联元素垂直居中?这是一个误区,要想让单行文字垂直居中只要设置line-height大小就可以了,和height没有任何关系.

1
2
3
4
5
6
7
.title{
height: 24px;
line-height: 24px;
}
.title2{
line-height:24px;
}

多行文本和替换元素的垂直居中和单行文本不一样, 需要用到vertical-align:middle的帮助.

1
2
3
4
5
6
.content{
display: inline-block;
line-height: 20px;
margin: 0 20px;
vertical-align: middle;
}

line-height的值一般为固定长度值,也可以是数值和是百分比,两者的值都是与font-size相乘后的值.

内联元素的大值特性:无论内联元素的line-height如何设置,最终父级元素的高度都是由数值最大的那个line-height所决定的.

line-height的好朋友vertical-align

为什么说他们是好朋友呢,因为凡是line-height起作用的地方vertical-align也一定起作用.因为vertical-align的默认值是baseline基线对齐,而基线的定义是x的下边缘.它等同于vertical-align:0;

####基于vertical-align属性的水平垂直居中大小不固定弹框

1
2
3
4
5
<div class="container">
<div class="dialog">

</div>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.container{
position: fixed;
top:0;right:0;bottom:0;left:0;
background-color: rgba(0,0,0,.5);
text-align: center;
font-size:0;
white-space: nowarp;
overflow: auto;
}
.container:after{
content: '';
display: inline-block;
height: 100%;
vertical-align:middle;
}
.dialog{
display: inline-block;
vertical-align:middle;
text-align:left;
font-size:14px;
white-space: nowarp;
}

流的破坏与保护

魔鬼属性float

浮动的本质就是为了实现文字环绕效果,这种文字环绕主要指文字环绕图片的显示效果.理论上可以通过float把整个页面结构都弄出来,但这种方式太脆弱缺乏弹性.一旦某个元素宽高发生变化,就会发生布局错位.

float的特性:

  1. 包裹性

    假设浮动元素的父元素width为200px,浮动元素子元素是一个宽度为128px的图片,此时元素宽度表现为”包裹”,就是里面图片的宽度128px;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    .father{
    width:200px;
    .float{
    float: left;//该元素宽度为128px;
    img{
    width:128px;
    }
    }
    }

    如果浮动元素的子元素不止是一张图片,还有许多文字,就会出现”自适应性”,此时浮动元素的宽度为父元素的宽度200px;

  2. 块状化并格式化上下文

    块状化即float的值只要不是none,其display就会成为block或table.

  3. 破坏文档流

  4. 没有任何margin合并

float的作用机制

float的最著名的特性表现就是会让父元素的高度塌陷.但只要父元素设置了一个具体的值就不需要担心高度塌陷的问题了.但不建议这样做,比较稳妥的做法还是采用一些手段清除浮动带来的影响.

float与流体布局

我们可以利用float破坏css正常流的特性,实现两栏或多栏的自适应布局.

一侧定宽,一侧自适应布局.

1
2
3
4
5
6
7
8
9
.left{
width:100px;//不定宽可以设置为百分比
height:100px;
float:left;
}
.right{
height:100px;
margin-left: 100px;//不定宽可以设置为百分比
}

float的天然克星clear

其语法如下: clear : none | left | right | both;

clear属性本质上并不是清除浮动,而是让自身不能和浮动元素相邻,但clear属性只对块级元素有效.这也就是我们在借助::after等伪元素(内联)清除浮动时需要设置display的原因.

1
2
3
4
5
.clear:after{
content: '';
display: block;
clear: both;
}

CSS的结界-BFC

BFC全称 block formatting context,中文为”块级格式化上下文”.

它的表现原则为: 如果一个元素具有BFC,内部子元素再怎么样也不会影响外部的元素,所以BFC不可能发生margin重叠的.BFC也可以用来清除浮动的影响,因为不清除浮动会影响后面的布局和定位.

什么时候会触发BFC呢?

  1. <html>根元素
  2. float的值不为none;
  3. overflow的值为auto, scroll 或 hidden;
  4. display 的值为: inline-block,table-cell,table-caption中的任何一个;
  5. position的值不为static和relative;

只要元素符合上面的任何一个条件就无需使用clear:both;去清除浮动的影响了.

最佳结界overflow

要想彻底清除浮动的影响,最适合的属性不是clear而是overflow.一般使用overflow:hidden;

HTML中有两个标签是可以默认产生进度条的,一个是根元素<html>,另一个是文本域<textarea>,之所以出现滚动条是因为这两个标签的overflow的默认值不是visible.

滚动条是可以自定义的.支持-webkit-前缀的浏览器可以这样设置.

1
2
3
4
5
6
7
8
9
10
11
12
::-webkit-scrollbar{
width: 8px;/*血槽宽度*/
height: 8px;
}
::-webkit-scrollbar-thumb{
background-color: rgba(0,0,0,.3);/*拖动条*/
border-radius: 6px;
}
::-webkit-scrollbar-track{
background-color: #ddd;/*背景槽*/
border-radius: 6px;
}

overflow与锚点定位:锚点就是可以让页面定位到某个位置的点,本质上是通过改变容器滚动高度或者宽度来实现的.设置了overflow属性为auto,scroll,hidden的元素是可以滚动的,overflow:hidden与scroll 和 auto的区别就在于有没有那个滚动条.高度溢出,滚动依旧存在,只是滚动条不存在,牢记这一点可以让我们更简单更原生的方式实现一些交互效果.

CSS世界的层叠规则

在css中,z-index属性只有和定位元素(position不为static的元素)在一起的时候才有用,可以是正数也可以是负数.但随着css3到来,flex盒子也可以使用z-index属性.

CSS层叠顺序类型如下:(由低到高)

层叠上下文background/border -> 负z-index -> block盒子 -> float浮动盒子 -> inline水平盒子 -> z-index: auto或0 -> 正z-index.

CSS3新时代的层叠上下文:

  1. 元素为flex布局的元素.
  2. 元素opacity不是1
  3. 元素的transform不是none
  4. 元素mix-blend-mode不是 normal
  5. 元素isolation是isolate
  6. 元素will-change属性为上面2-6的任意一个
  7. 元素filter不是none
  8. 元素的-webkit-overflow-scrolling为touch

z-index”不犯二”准则:对于非浮层元素,避免设置z-index的值,z-index的值没有任何道理需要超过2.

强大的文本处理能力

font-size的能力

line-height的部分类别属性是相对于font-size计算的,而vertical-align百分比属性值又是相对于line-height计算的.

1
2
3
4
5
6
7
p{
font-size: 16px;
line-height: 1.5;
}
p > img{
vertical-align: -25%; /* (即16px * 1.5 * -25% = -6px) */
}

font-size与ex,em,和rem的关系: ex是字符x的高度,font-size越大,对应的ex越大.em是根据当前元素的font-size计算的,而rem( root-em )是相对于HTML根元素的font-size进行计算的.

桌面Chrome浏览器有一个12px的字号限制但并不是所有小于12px的字号都当做12px处理,有一个值例外那就是0.

如果font-size:0;那么文字就会被直接隐藏掉.不然哪怕是0.00001px也会被当做12px处理.

font-weight表示文字的粗细程度,我们通常设置为bold 和 normal.也可以设置为100-900,该值必须是整百数.其中400等同于normal,700等同于bold.

font属性联写: [font-style] ? font-size [/line-height].例如.font{ font: normal 700 14px/20px }

了解@font face

@font face 本质上就是一个定义字体和字体集的变量.这个变量不仅仅是简单的自定义字体,还包括字体重命名,默认字体样式设置.它大多用于字体图标技术.所谓字体本质上就是字符集和图形的一种映射关系.字体图标技术通常把字符映射成另外的图标形状,我们看到的图标,本质上就是一个普通的字符.

文本的控制

text-indent就是对文本进行缩进控制.项目中我们用的最多的就是给text-indent一个很大的负值来隐藏文本内容.比如很多网站的LOGO放在<h1>中,然后设置一个很大的负值,比如-9999em.

letter-spacing用来控制与字符的间距.这里的字符包括英文字母,汉字以及空格.支持负值.

word-spacing用来控制与单词间的间距.它仅作用于空格而不是字面上的单词.

white-space 声明了如何处理元素内的空白字符,normal为合并,pre为不合并,只有在换行符的地方换行.nowrap合并空白但不允许文字环绕.当设置为nowrap时,元素的宽度此时表现为”最大可用宽度”,换行符和一些空格全部合并,文本在一行显示.

如何解决text-decoration下划线和字体重叠的问题?可以用兼容性并不好的text-decoration-skip属性,或用box-shadow或background-image模拟,然而最好的解决方式是看似普通却很有用的border属性.

1
2
3
4
a{
text-decoration: none;
border-bottom: 1px solid;
}

text-transform是专门为英文字符设计的,要么全部大写text-transform: uppercase,要么全部小写text-transform: lowercase,身份证号的x输入以及验证码的字母大小写都可以使用这个属性实现需求.

元素的显示与隐藏

  • display:none;

    display:none;可以让元素以及所有后代元素都隐藏,占据的空间消失,是真正意义上的隐藏.

    在火狐浏览器下display:none的元素的background-image是不加载的,但是chrome和safari视情况而定,父元素隐藏图片不加载,自身元素隐藏,图片依旧会加载.

  • visibility:hidden;

    与display:none一样可以隐藏元素,但visibility:hidden;保留元素的空间.但他和display:none不一样的是,它具有继承性,父元素设置visibility:hidden;子元素也会看不到,一旦子元素设置visibility:visible;子元素就会显示出来这种后代可见特性在开发中非常有用.

    visibility可以喝transition配合使用,而display不能和transition配合,因为transition的属性有visibility而没有display.

    1
    2
    3
    4
    5
    6
    7
    8
    .list{
    position:absolute;
    visibility: hidden;
    }
    td:hover .list{
    visibility: visible;
    transition: visibility 0s .2s;
    }
  • 希望元素不可见,不能点击,不占空间,但键盘可访问可以使用clip: rect(0 0 0 0 )剪切隐藏.

  • 希望元素不可见,不能点击,但占据空间且键盘可访问使用relative配合负z-index隐藏

  • 希望元素不可见,但可以点击,不占空间可以使用opacity:0;