px、em和rem
在css中单位长度用的最多的是px、em、rem,这三个的区别是:
- px像素(Pixel),相对长度单位。像素px是相对于显示器屏幕分辨率而言的,一旦设置了就无法因为适应页面大小而改变。
- em是相对长度单位。相对于当前父元素内文本的字体尺寸font-size。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸(16px)
- rem(root em,根em)是CSS3新增的一个相对单位,相对于根元素的字体尺寸。除了IE8及更早版本外,所有浏览器均已支持rem。为标签的font-size设定一个数值,比如设为100px,当需要50px的时候,直接用0.5rem就可以了
总之:对于em和rem的区别一句话概括:
em相对于父元素的font-size,rem相对于根元素的font-size。
应用场景:
1、像素(px):用于元素的边框或定位。
2、em/rem:用于做响应式页面,不过我更倾向于rem,因为em不同元素的参照物不一样(都是该元素父元素),所以在计算的时候不方便,相比之下rem就只有一个参照物(html元素),这样计算起来更清晰。
3、不要在多列布局中使用 em 或 rem -改用 %。
4、使用 em 或 rem,如果缩放会不可避免地导致要打破布局元素。
需要注意的是:
样式的reset中需先设置html字体的初始化大小为50px,这是为了防止js被禁用或者加载不到或者执行错误。
而做的兼容样式的reset中需先设置body字体的初始化大小为16px,这是为了让body内的字体大小不继承父级html元素的50px,而用系统默认的16px
HTML 引入CSS的方式(link、@import)
CSS 和 HTML 的结合方式有 3 种:
-
行内样式表:在某个特定的标签里采用 style属性。范围只针对此标签。
-
内嵌样式表:在页面的 head 里采用
<style>标签。范围针对此页面。 -
外部样式表:这种引入方式又分为两种:
1、采用
<link>标签。link直接写在head中,是一种xhtml标签。例如:<link rel = "stylesheet" type = "text/css" href = "a.css"></link>2、采用@import,写在head中的
<style>标签中,并且必须是第一句。例如:@import url(a.css) ;
两种引入样式方式的区别:
1 .link是HTML方式,除了加载CSS外,还可以定义RSS等其他事务;@import属于CSS范畴,只能加载CSS。
2.link引用CSS时,在页面载入时同时加载;@import需要页面网页完全载入以后加载, 所以一般我们不推荐使用@import方法。
3.link是XHTML标签,无兼容问题; @import是在CSS2.1提出的,低版本的浏览器不支持,从这点来说,我们同样不推荐使用@import方法。
4.link支持使用Javascript控制DOM去改变样式;而@import不支持。
CSS 的四种基本选择器
CSS 的选择器分为两大类:基本选择题和扩展选择器。
1、标签选择器:无符号
标签选择器,选择的是页面上所有这种类型的标签,所以经常描述“共性”,无法描述某一个元素的“个性”。
举例:
p{
font-size:14px;
}
【总结】需要注意的是:
(1)所有的标签,都可以是选择器。比如 ul、li、label、dt、dl、input。
(2)无论这个标签藏的多深,一定能够被选择上。
(3)选择的所有,而不是一个。
2、ID 选择器:#
针对某一个特定的标签来使用,只能使用一次。css 中的 ID 选择器以”#”来定义。
举例:
#mytitle{
border:3px dashed green;
}
这个id标签的名字,可以任取,但是:
- (1)只能有字母、数字、下划线。
- (2)必须以字母开头。
- (3)不能和标签同名。比如 id 不能叫做 body、img、a。
另外,特别强调的是:HTML 页面,不能出现相同的 id,哪怕他们不是一个类型。比如页面上有一个 id 为 pp 的 p,一个 id 为 pp 的 div,是非法的!
3、类选择器:.
针对你想要的所有标签使用。优点:灵活。
css 中用.来表示类。举例如下:
.one{
width:800px;
}
id 非常相似,任何的标签都可以携带 id 属性和 class 属性。class 属性的特点:
- 特性 1:类选择器可以被多种标签使用。
- 特性 2:同一个标签可以使用多个类选择器。用空格隔开。举例如下:(正确)
<h3 class="teshu zhongyao">我是一个h3啊</h3>
初学者常见的错误,就是写成了两个 class。举例如下:(错误)
<h3 class="teshu" class="zhongyao">我是一个h3啊</h3>
也就是说:
(1)不要去试图用一个类名,把某个标签的所有样式写完。这个标签要多携带几个类,共同完成这个标签的样式。
(2)每一个类要尽可能小,有“公共”的概念,能够让更多的标签使用。
问题:到底用 id 还是用 class?
答案:尽可能的用 class,除非极特殊的情况可以用 id。
原因:id 是 js 用的。也就是说,js 要通过 id 属性得到标签,所以 css 层面尽量不用 id,要不然 js 就很别扭。另一层面,我们会认为一个有 id 的元素,有动态效果。
举例如下:
css 和 js 都在用同一个 id,会出现不好沟通的情况。
我们记住这句话:类上样式,id 上行为。意思是说,class属性交给 css 使用,id属性交给 js 使用。
上面这三种选择器的区别:
- 标签选择器针对的是页面上的一类标签。
- ID 选择器是只针对特定的标签(一个),ID 是此标签在此页面上的唯一标识。
- 类选择器可以被多种标签使用。
4、通用选择器:*
通用选择器,将匹配任何标签。不建议使用,IE 有些版本不支持,大网站增加客户端负担。
效率不高,如果页面上的标签越多,效率越低,所以页面上不能出现这个选择器。
举例:
* {
margin-left: 0px;
margin-top: 0px;
}
CSS 的几种高级选择器
1、后代选择器: 定义的时候用空格隔开
对于E F这种格式,表示所有属于 E 元素后代的 F 元素,有这个样式。空格就表示后代。
后代选择器,就是一种平衡:共性、特性的平衡。当要把某一个部分的所有的什么,进行样式改变,就要想到后代选择器。
后代选择器,描述的是祖先结构。
看定义可能有点难理解,我们来看例子吧。
举例 1:
<style type="text/css">
.div1 p {
color: red;
}
</style>
空格就表示后代。.div1 p 表示.div1的后代所有的p。
这里强调一下:这两个标签不一定是连续紧挨着的,只要保持一个后代的关联即可。也就是说,选择的是后代,不一定是儿子。
2、交集选择器:定义的时候紧密相连
定义交集选择器的时候,两个选择器之间紧密相连。一般是以标签名开头,比如div.haha,再比如p.special。
如果后一个选择器是类选择器,则写为div.special;如果后一个选择器 id 选择器,则写为div#special。
来看下面这张图就明白了:
h3.special {
color: red;
}
选择的元素要求同时满足两个条件:必须是 h3 标签,然后必须是 special 标签。
3、并集选择器:定义的时候用逗号隔开
三种基本选择器都可以放进来。只要属于其中一个标签即被选中
举例:
p,
h1,
#mytitle,
.one {
color: red;
}
4、伪类选择器
伪类:同一个标签,根据其不同的种状态,有不同的样式。这就叫做“伪类”。伪类用冒号来表示。
比如div是属于box类,这一点很明确,就是属于box类。但是a属于什么类?不明确。因为需要看用户点击前是什么状态,点击后是什么状态。所以,就叫做“伪类”。
静态伪类和动态伪类
伪类选择器分为两种。
(1)静态伪类:只能用于超链接的样式。如下:
:link超链接点击之前:visited链接被访问过之后
(2)动态伪类:针对所有标签都适用的样式。如下:
:hover“悬停”:鼠标放到标签上的时候:active“激活”: 鼠标点击标签,但是不松手时。:focus是某个标签获得焦点时的样式(比如某个输入框获得焦点)
超链接的四种状态
a标签有4种伪类(即对应四种状态),要求背诵。如下:
a:link“链接”:超链接点击之前a:visited“访问过的”:链接被访问过之后a:hover“悬停”:鼠标放到标签上的时候a:active“激活”: 鼠标点击标签,但是不松手时。
关于顺序:
我们一定要将a标签写在前面,将:link、:visited、:hover、:active这些伪类写在后面。
并且这四种状态必须按照固定的顺序写:
a:link 、a:visited 、a:hover 、a:active
如果不按照顺序,那么将失效。“爱恨准则”:love hate。必须先爱,后恨。
a{}和a:link{}的区别
a{}定义的样式针对所有的超链接(包括锚点)a:link{}定义的样式针对所有写了href属性的超链接(不包括锚点)
如上方代码所示,最标准的写法,就是把link、visited、hover这三个伪类都要写。但是前端开发工程师在大量的实践中,发现不写link、visited也挺兼容。写法是:
a:link、a:visited都是可以省略的,简写在a标签里面。也就是说,a标签涵盖了link、visited的状态(前提是都具有了相同的属性)。当然了,在写
a:link、a:visited这两个伪类的时候,要么同时写,要么同时不写。如果只写a属性和a:link属性,不规范。
CSS的继承性
继承性是从自己开始,直到最小的元素。
- 关于文字样式的属性,都具有继承性。这些属性包括:color、 text-开头的、line-开头的、font-开头的。
- 关于盒子、定位、布局的属性,都不能继承。
以后当我们谈到css有哪些特性的时候,我们要首先想到继承性。而且,要知道哪些属性具有继承性、哪些属性没有继承性。
CSS的层叠性(优先级)
选择器与样式表优先级
层叠性:就是css处理冲突的能力。
当多个选择器,选择上了某个元素的时候,要按照如下顺序统计权重:
- id 选择器
- 类选择器、属性选择器、伪类选择器
- 标签选择器、伪元/素选择器
综合来说,选择器排序的优先级为:
-
1、对于相同的选择器(比如同样都是类选择器),其样式表排序:行级样式 > 内嵌样式表 > 外部样式表(就近原则)
(对于同一个标签,如果用到的都是外部样式表,且权重一致,那它的优先级:html文件中,引用样式表的位置越近,就用谁。)
-
2、对于相同类型的样式表(比如同样都是内部样式表),其选择器排序:ID选择器 > 类选择器 > 标签选择器
-
3、外部样式表的ID选择器 > 内嵌样式表的标签选择器
总结:就近原则。ID选择器优先级最大。
多层叠性计算
有多个选择器时,先比ID选择器的数量,再比类选择器的数量,最后比标签选择器的数量,前面的有决出胜负就不用往后比了。
举例1:计算权重
如上图所示,统计各个选择器的数量,优先级高的胜出。文字的颜色为红色。
PS:不进位,实际上能进位(冷知识:255个标签,等于1个类名)但是没有实战意义!
举例2:权重相同时
上图可以看到,第一个样式和第二个样式的权重相同。但第二个样式的书写顺序靠后,因此以第二个样式为准(就近原则)。
举例3:继承性造成的影响
这里需要声明一点:
如果不能直接选中某个元素,通过继承性影响的话,那么权重是0。
为了验证上面这句话,我们来看看下面这样的例子:
另外:如果大家的权重相同,那么就采用就近原则:谁描述的近,听谁的。
层叠性权重计算的问题大总结
通过列举上面几个例子,我们对权重问题做一个总结。
上面这个图非常重要,我们针对这个图做一个文字描述:
- 选择上了,数权重,(id的数量,类的数量,标签的数量)。如果权重一样,谁写在后面听谁的。
- 没有选择上,通过继承影响的,就近原则,谁描述的近听谁的。如果描述的一样近,比如选择器权重,如果权重再一样重,谁写在后面听谁的。
权重问题补充
同一个标签携带了多个类名
这里需要补充两种冲突的情况:
- 1、对同一个标签,如果用到了了多个相同的内嵌样式表,它的优先级:定义的样式表中,谁最近,就用谁。
- 2、对于同一个标签,如果引用了多个相同的外部样式表,它的优先级:html文件中,引用样式表的位置越近,就用谁。
例如:(就近原则)
上图中,文字显示的颜色均为红色。因为这和在标签中的挂类名的书序无关,只和css的顺序有关。
!important标记
important是英语里面的“重要的”的意思。我们可以通过如下语法:
k:v !important;
来给一个属性提高权重。这个属性的权重就是无穷大。
注意,一定要注意语法的正确性。
正确的语法:
font-size:60px !important;
!important标记需要强调如下3点:
(1)!important提升的是一个属性,而不是一个选择器
p{
color:red !important; 只写了这一个!important,所以只有字体颜色属性提升了权重
font-size: 100px ; 这条属性没有写!important,所以没有提升权重
}
(2)!important无法提升继承的权重,该是0还是0
比如HTML结构:
<div>
<p>哈哈哈哈哈哈哈哈</p>
</div>
有CSS样式:
div{
color:red !important;
}
p{
color:blue;
}
由于div是通过继承性来影响文字颜色的,所以!important无法提升它的权重,权重依然是0。干不过p标签,因为p标签是实实在在选中了,所以字是蓝色的(以p为准)。
(3)!important不影响就近原则
如果大家都是继承来的,按理说应该按照“就近原则”,那么important能否影响就近原则呢? 答案是:不影响。远的,永远是远的。不能给远的写一个important,干掉近的。
为了验证这个问题,我们可以搞两层具有继承性的标签,然后给外层标签加一个!important,最终看看就近原则有没有被打破。举例如下:
PS:做网站的时候,!important 尽量不要用。否则会让css写的很乱。
盒子模型
标准盒模型和IE盒模型
我们目前所学习的知识中,以标准盒子模型为准。
标准盒子模型:
IE盒子模型也就是怪异盒模型:
上图显示:
在 CSS 盒子模型 (Box Model) 规定了元素处理元素的几种方式:
- width和height:内容的宽度、高度(不是盒子的宽度、高度)。
- padding:内边距。
- border:边框。
- margin:外边距。
CSS盒模型和IE盒模型的区别:
- 在 标准盒子模型中,width 和 height 指的是内容区域的宽度和高度。增加内边距、边框和外边距不会影响内容区域的尺寸,但是会增加元素框的总尺寸。
- IE盒子模型中,width 和 height 指的是内容区域+border+padding的宽度和高度。
盒子模型的相互转换
元素可以通过 CSS 中的 box-sizing 样式属性可用来转换盒子模型
| 属性值 | 说明 |
|---|---|
| content-box | 标准盒子模型 |
| border-box | IE盒子模型 |
margin
<body>标签也有margin
<body>标签有必要强调一下。很多人以为<body>标签占据的是整个页面的全部区域,其实是错误的,正确的理解是这样的:整个网页最大的盒子是<document>,即浏览器。而<body>是<document>的儿子。浏览器给<body>默认的margin大小是8个像素,此时<body>占据了整个页面的一大部分区域,而不是全部区域。来看一段代码。
padding
padding区域也有颜色和背景
padding就是内边距。padding的区域有背景颜色,css2.1前提下,并且背景颜色一定和内容区域的相同。也就是说,background-color将填充所有border以内的区域。**
padding、margin四个方向
方法有两种,第一种写小属性;第二种写综合属性,用空格隔开。
小属性的写法:
padding-top: 30px;
padding-right: 20px;
padding-bottom: 40px;
padding-left: 100px;
综合属性的写法:(上、右、下、左)(顺时针方向,用空格隔开。margin的道理也是一样的)
padding:30px 20px 40px 100px;
如果写了四个值,则顺序为:上、右、下、左
如果只写了三个值,则顺序为:上、右(左)、下
如果只写了两个值,则顺序为:上(下)、右(左
要懂得,用小属性层叠大属性。比如:
padding: 20px;
padding-left: 30px;
上面的padding对应盒子模型为:
下面的写法:
padding-left: 30px;
padding: 20px;
第一行的小属性无效,因为被第二行的大属性层叠掉了。
border
border合写
border就是边框。边框有三个要素:粗细、线型、颜色。比如:
border: 2px solid red;
颜色如果不写,默认是黑色。另外两个属性如果不写,则无法显示边框。
比较稳定的border-style就几个:solid、dashed、dotted。
border拆分
PS:小技巧:在sublime text中,为了快速输入border:1px solid red;这个属性,可以直接输入bd,然后选第二个后回车。
border属性是能够被拆开的,有两大种拆开的方式:
- (1)按三要素拆开:border-width、border-style、border-color。(一个border属性是由三个小属性综合而成的)
- (2)按方向拆开:border-top、border-right、border-bottom、border-left。
现在我们明白了:一个border属性,是由三个小属性综合而成的。如果某一个小属性后面是空格隔开的多个值,那么就是上右下左的顺序。举例如下:
border-width:10px 20px;
border-style:solid dashed dotted;
border-color:red green blue yellow;
效果如下:
举例1:利用 border 属性画一个直角三角形(小技巧)
完整代码如下:
div{
width: 0;
height: 0;
border: 50px solid transparent;
border-top-color: red;
border-bottom: none;
}
步骤如下:
(1)当我们设置盒子的width和height为0时,此时效果如下:
(2)然后将border的底部取消:
(3)最后设置border的左边和右边为白色或者透明:
这样,一个三角形就画好了。
举例2:利用 border 属性画一个等边三角形(更推荐的技巧)
上面的例子1中,画出来的是直角三角形,可如果我想画等边三角形,要怎么做呢?
完整代码如下:(用 css 画等边三角形)
.div1{
width: 0;
height: 0;
border-top: 30px solid red;
/* 通过改变 border-left 和 border-right 中的像素值,来改变三角形的形状 */
border-left: 20px solid transparent;
border-right: 20px solid transparent;
}
效果如下:
浮动属性float
脱标一共就三种方法:浮动/绝对定位/固定定位
使用场景
主要是一栏中有多个平级小盒子并排
浮动的性质
性质1:浮动的元素脱标
脱标即脱离标准流。我们来看几个例子。
所以能够证明一件事:一旦一个元素浮动了,那么,将能够并排了,并且能够设置宽高了。无论它原来是个div还是个span。 所有标签,浮动之后,已经不区分行内、块级了,都是行内块。
性质2:浮动的元素互相贴靠
我们来看一个例子就明白了。
我们给三个div均设置了float: left;属性之后,然后设置宽高。当改变浏览器窗口大小时,可以看到div的贴靠效果:
上图显示,3号如果有足够空间,那么就会靠着2号。如果没有足够的空间,那么会靠着1号大哥。 如果没有足够的空间靠着1号大哥,3号自己去贴左墙。
性质3:浮动的元素有“字围”效果
来看一张图就明白了。我们让div浮动,p不浮动。
上图中,我们发现:div挡住了p,但不会挡住p中的文字,形成“字围”效果。
总结:标准流中的文字不会被浮动的盒子遮挡住。(文字就像水一样)
关于浮动我们要强调一点,浮动这个东西,为避免混乱,我们在初期一定要遵循一个原则:永远不是一个东西单独浮动,浮动都是一起浮动,要浮动,大家都浮动。
性质4:收缩
收缩:一个浮动的元素,如果没有设置width,那么将自动收缩为内容的宽度(这点非常像行内元素)。
div本身是块级元素,如果不设置width,它会单独霸占整行;但是,设置div浮动后,它会收缩
浮动清除的方法
一句话解释为什么要清除浮动:清除浮动主要是为了解决,父元素因为子级元素浮动引起的内部高度为0的问题
详细解释:如果一个父级盒子里的子元素全是浮动的,并且父盒子本身没有指定高度,那么即使子元素有高度,父盒子的高度也会塌陷为0,因为父盒子中不再有标准文档流的元素了。
方法1:给父元素加高度
给父级div设置一个正确的合适的高度(至少保证高度大于儿子的高度),就可以看到正确的现象:
方法2:额外标签法
在最后一个浮动标签后,新加一个标签,给其设置clear:both;
clear就是清除,both指的是左浮动、右浮动都要清除。clear:both的意思就是:不允许左侧和右侧有浮动对象。
注意一定要用块级元素比如div装clear:both,span就不行。
.clear{
clear:both;
}
<body>
<div class="fahter">
<div class="bigfloat">big</div>
<div class="smallfloat">small</div>
<div class="clear">额外标签法</div>
</div>
<div class="footer"></div>
</body>
如果我们清除了浮动,父元素自动检测子盒子最高的高度,然后与其同高。
优点:通俗易懂,方便
缺点:添加无意义标签,语义化差
方法3:使用after伪元素清除浮动(推荐使用)
伪元素写在避免塌陷的父级上。伪元素在CSS3之前用单冒号:,在CSS3之后为了与伪类相区分,使用双冒号::
.clearfix:after{/*伪元素是行内元素 正常浏览器清除浮动方法*/
/*伪元素必须有content*/
content: "";
display: block;
height: 0;
clear:both;
visibility: hidden;
}
/*ie6清除浮动的方式 *号只有IE6-IE7执行,其他浏览器不执行*/
.clearfix{
*zoom: 1;
}
<body>
<div class="fahter clearfix">
<div class="big">big</div>
<div class="small">small</div>
</div>
<div class="footer"></div>
</body>
优点:符合闭合浮动思想,结构语义化正确
缺点:ie6-7不支持伪元素:after,使用zoom:1触发hasLayout.
推荐使用
方法4:使用before和after双伪元素清除浮动
.clearfix:after,.clearfix:before{
content: "";
display: table;
}
.clearfix:after{
clear: both;
}
.clearfix{
*zoom: 1;
}
<div class="fahter clearfix">
<div class="big">big</div>
<div class="small">small</div>
</div>
<div class="footer"></div>
为什么有了after伪元素还需要双伪元素?
优点:代码更简洁
缺点:用zoom:1触发hasLayout
推荐使用
方法5:触发BFC
例如父级添加overflow:hidden等
优点:代码简洁
缺点:内容增多的时候容易造成不会自动换行导致内容被隐藏掉,无法显示要溢出的元素
不推荐使用
定位属性position
使用场景主要是父级盒子定长宽时,子元素可以在父元素中任意位置定位
CSS的定位属性有六种:
position: absolute; <!-- 绝对定位 -->
position: relative; <!-- 相对定位 -->
position: fixed; <!-- 固定定位 -->
position: static; <!-- 默认值 -->
position: inherit; <!-- 从父元素继承position的值 -->
position: sticky; <!-- 粘性定位 -->
相对定位
相对定位:让元素相对于自己原来的位置,进行位置调整(可用于盒子的位置微调)。
我们之前学习的背景属性中,是通过如下格式:
background-position:向右偏移量 向下偏移量;
但这回的定位属性,是通过如下格式:
position: relative;
left: 50px;
top: 50px;
相对定位不脱标
相对定位:不脱标,老家留坑,别人不会把它的位置挤走。
也就是说,相对定位的真实位置还在老家,只不过影子出去了,可以到处飘。
相对定位的用途
如果想做“压盖”效果(把一个div放到另一个div之上),我们一般不用相对定位来做。相对定位,就两个作用:
- (1)微调元素
- (2)做绝对定位的参考,子绝父相
相对定位的定位值
- left:盒子右移
- right:盒子左移
- top:盒子下移
- bottom:盒子上移
PS:负数表示相反的方向。
绝对定位
绝对定位:定义横纵坐标。原点在父容器的左上角或左下角。横坐标用left表示,纵坐标用top或者bottom表示。
格式举例如下:
position: absolute; /*绝对定位*/
left: 10px; /*横坐标*/
top/bottom: 20px; /*纵坐标*/
绝对定位脱标
绝对定位的盒子脱离了标准文档流。
所以,所有的标准文档流的性质,绝对定位之后都不遵守了。
绝对定位之后,标签就不区分所谓的行内元素、块级元素了,不需要display:block就可以设置宽、高了。
以页面为参考点
(1)如果用top描述,那么参考点就是页面的左上角,而不是浏览器的左上角:
(2)如果用bottom描述,那么参考点就是浏览器首屏窗口尺寸(好好理解“首屏”二字),对应的页面的左下角:
为了理解“首屏”二字的含义,我们来看一下动态图:
以盒子为参考点
一个绝对定位的元素,如果父辈元素中也出现了已定位(无论是绝对定位、相对定位,还是固定定位)的元素,那么将以父辈这个元素,为参考点。
如下:(子绝父相)
以下几点需要注意。
(1) 要听最近的已经定位的祖先元素的,不一定是父亲,可能是爷爷:
<div class="box1"> 相对定位
<div class="box2"> 没有定位
<p></p> 绝对定位,将以box1为参考,因为box2没有定位,box1就是最近的父辈元素
</div>
</div>
再比如:
<div class="box1"> 相对定位
<div class="box2"> 相对定位
<p></p> 绝对定位,将以box2为参考,因为box2是自己最近的父辈元素
</div>
</div>
(2)不一定是相对定位,任何定位,都可以作为儿子的参考点:
子绝父绝、子绝父相、子绝父固,都是可以给儿子定位的。但是在工程上,如果子绝、父绝,没有一个盒子在标准流里面了,所以页面就不稳固,没有任何实战用途。
工程应用:
“子绝父相”有意义:这样可以保证父亲没有脱标,儿子脱标在父亲的范围里面移动。于是,工程上经常这样做:
父亲浮动,设置相对定位(零偏移),然后让儿子绝对定位一定的距离。
(3)绝对定位的儿子,无视参考的那个盒子的padding:
下图中,绿色部分是父亲div的padding,蓝色部分p是div的内容区域。此时,如果div相对定位,p绝对定位,那么, p将无视父亲的padding,在border内侧为参考点,进行定位:
工程应用:
绝对定位非常适合用来做“压盖”效果。我们来举个lagou.com上的例子。
现在有如下两张图片素材:
要求作出如下效果:
代码实现如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
.box{
margin: 100px;
width: 308px;
height: 307px;
border: 1px solid #FF7E00;
position: relative; /*子绝父相*/
}
.box .image img{
width: 308px;
height: 196px;
}
.box .dtc{
display: block; /*转为块级元素,才能设置span的宽高*/
width: 52px;
height: 28px;
background-image: url(http://img.smyhvae.com/20180116_1115.png);
background-position: -108px 0px; /*这里用到了精灵图*/
position: absolute; /*采用绝对定位的方式,将精灵图盖在最上层*/
top: -9px;
left: 13px;
}
.box h4{
background-color: black;
color: white;
width:308px;
height: 40px;
line-height: 40px;
position: absolute;
top: 156px;
}
</style>
</head>
<body>
<div class="box">
<span class="dtc"></span>
<div class="image">
<img src="http://img.smyhvae.com/20180116_1116.jpg" alt="">
</div>
<h4>广东深圳宝安区建安一路海雅缤纷城4楼</h4>
</div>
</body>
</html>
代码解释如下:
- 为了显示“多套餐”那个小图,我们需要用到精灵图。
- “多套餐”下方黑色背景的文字都是通过“子绝父相”的方式的盖在大海报image的上方的。
让绝对定位中的盒子在父亲里水平居中
我们知道,如果想让一个标准流中的盒子在父亲里水平居中,可以将其设置margin: 0 auto属性。
可如果盒子是绝对定位的,此时已经脱标了,如果还想让其居中(位于父亲的正中间),可以这样做:
div {
width: 600px;
height: 60px;
position: absolute; 绝对定位的盒子
left: 50%; 首先,让左边线居中
top: 0;
margin-left: -300px; 然后,向左移动宽度(600px)的一半
}
如上方代码所示,我们先让这个宽度为600px的盒子,左边线居中,然后向左移动宽度(600px)的一半,就达到效果了。
我们可以总结成一个公式:
left:50%; margin-left:负的宽度的一半
固定定位
固定定位:就是相对浏览器窗口进行定位。无论页面如何滚动,这个盒子显示的位置不变。
备注:IE6不兼容。
用途1:网页右下角的“返回到顶部”
比如我们经常看到的网页右下角显示的“返回到顶部”,就可以固定定位。
<style type="text/css">
.backtop{
position: fixed;
bottom: 100px;
right: 30px;
width: 60px;
height: 60px;
background-color: gray;
text-align: center;
line-height:30px;
color:white;
text-decoration: none; /*去掉超链接的下划线*/
}
</style>
用途2: 顶部导航条
我们经常能看到固定在网页顶端的导航条,可以用固定定位来做。
需要注意的是,假设顶部导航条的高度是60px,那么,为了防止其他的内容被导航条覆盖,我们要给body标签设置60px的padding-top。
z-index属性
z-index属性:表示谁压着谁。数值大的压盖住数值小的。
有如下特性:
(1)属性值大的位于上层,属性值小的位于下层。
(2)z-index值没有单位,就是一个正整数。默认的z-index值是0。
(3)如果大家都没有z-index值,或者z-index值一样,那么在HTML代码里写在后面,谁就在上面能压住别人。定位了的元素,永远能够压住没有定位的元素。
(4)必须有定位,才能有z-index值。也就是说,不管相对定位、绝对定位、固定定位,都可以使用z-index值。而浮动的元素不能用。
(5)从父现象:父亲怂了,儿子再牛逼也没用。意思是,如果父亲1比父亲2大,那么,即使儿子1比儿子2小,儿子1也能在最上层。
粘性定位
position属性中最有意思的就是sticky了,设置了sticky的元素,在屏幕范围(viewport)时该元素的位置并不受到定位影响(设置是top、left等属性无效),当该元素的位置将要移出偏移范围时,定位又会变成fixed,根据设置的left、top等属性成固定位置的效果。
可以知道sticky属性有以下几个特点:
- 该元素并不脱离文档流,仍然保留元素原本在文档流中的位置。
- 当元素在容器中被滚动超过指定的偏移值时,元素在容器内固定在指定位置。亦即如果你设置了top: 50px,那么在sticky元素到达距离相对定位的元素顶部50px的位置时固定,不再向上移动。
- 元素固定的相对偏移是相对于离它最近的具有滚动框的祖先元素,如果祖先元素都不可以滚动,那么是相对于viewport来计算元素的偏移量
比较蛋疼的是这个属性的兼容性还不是很好,目前仍是一个试验性的属性,并不是W3C推荐的标准。它之所以会出现,也是因为监听scroll事件来实现粘性布局使浏览器进入慢滚动的模式,这与浏览器想要通过硬件加速来提升滚动的体验是相悖的。
具体情况可以看下图,基本上可以说这个属性使用的浏览器只有FireFox和iOS的Safari:
简单的说,要让sticky属性生效的条件有以下两点:
- 一个是元素自身在文档流中的位置
- 另一个是该元素的父容器的边缘
第一点上面已经讲过了,如果设置了top: 50px,那么元素在达到距离顶部50px时才会发生定位,否则并不会发生定位。
第二点则需要考虑父容器的高度情况:sticky元素在到达父容器的底部时,则不会再发生定位,如果父容器高度并没有比sticky元素高,那么sticky元素一开始就达到了底部,并不会有定位的效果。
此外还有一点就是父元素的overflow属性,如果父元素的overflow属性并不是默认的visible属性,那么sticky元素则相对于该父元素定位。此时也就无法定位在顶部了。
BFC
BFC 定义
BFC(Block formatting context)直译为"块级格式化上下文"。它是一个独立的渲染区域, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。 Formatting context 是 W3C CSS2.1 规范中的一个概念。它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。最常见的 Formatting context 有 Block fomatting context (简称BFC)和 Inline formatting context (简称IFC)。
BFC是一个独立的布局环境,其中的元素布局是不受外界的影响,并且在一个BFC中,块盒与行盒(行盒由一行中所有的内联元素所组成)都会垂直的沿着其父元素的边框排列。
BFC的布局规则
内部的Box会在垂直方向,依次放置。
Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠。
每个盒子(块盒与行盒)的margin box的左边,与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
BFC的区域不会与float box重叠。
BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
计算BFC的高度时,浮动元素也参与计算。
如何创建BFC
1、float !== none (top/right/bottom/left) 2、position !== static或者relative (absolut/fixed) 3、display : inline-block、table-cell、flex、table-caption或者inline-flex 4、overflow !== visible(hidden/auto/scroll)
BFC的作用
1、避免margin重叠
对其中一个兄弟设置BFC
2、清除浮动(高度塌陷)
对父元素设置BFC
3、自适应两栏布局
如果左盒子有浮动属性float: left,右盒子没有,那么会导致左边盖在右边上面,这时应该对右盒子清除浮动。
.left {
width: 100px;
height: 150px;
<-- 加了浮动 -->
float: left;
background: rgb(139, 214, 78);
text-align: center;
line-height: 150px;
font-size: 20px;
}
.right {
/*加上BFC*/
overflow: hidden;
height: 300px;
background: rgb(170, 54, 236);
text-align: center;
line-height: 300px;
font-size: 40px;
}
right会自动的适应页面宽度,这时候就形成了一个两栏自适应的布局。
Flex布局
2009年,W3C 提出了一种新的方案----Flex 布局,可以简便、完整、响应式地实现各种页面布局。目前,它已经得到了所有浏览器的支持,这意味着,现在就能很安全地使用这项功能。
一、Flex 布局是什么?
Flex 是 Flexible Box 的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性。
任何一个容器都可以指定为 Flex 布局。
.box{
display: flex;
}
行内元素也可以使用 Flex 布局。
.box{
display: inline-flex;
}
Webkit 内核的浏览器,必须加上-webkit前缀。
.box{
display: -webkit-flex; /* Safari */
display: flex;
}
注意,设为 Flex 布局以后,子元素的**float、clear和vertical-align属性**将失效。
二、基本概念
采用 Flex 布局的元素,称为 Flex 容器(flex container),简称"容器"。它的所有子元素自动成为容器成员,称为 Flex 项目(flex item),简称"项目"。
容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)。主轴的开始位置(与边框的交叉点)叫做main start,结束位置叫做main end;交叉轴的开始位置叫做cross start,结束位置叫做cross end。
项目默认沿主轴排列。单个项目占据的主轴空间叫做main size,占据的交叉轴空间叫做cross size。
三、父项属性
以下6个属性设置在容器上。
- //flex-direction: row | row-reverse | column | column-reverse; 设置主轴方向
- //flex-wrap: nowrap | wrap | wrap-reverse; 是否换行
- //flex-flow: row nowrap; 上面两个合写
- justify-content: flex-start | flex-end | center | space-between | space-around; 每行内部左右对齐
- align-items: flex-start | flex-end | center | baseline | stretch; 单行上下对齐
- align-content: flex-start | flex-end | center | space-between | space-around | stretch; 多行上下对齐
3.1 flex-direction属性
flex-direction属性决定主轴的方向(即项目的排列方向)。
它可能有4个值。
row(默认值):主轴为水平方向,起点在左端。row-reverse:主轴为水平方向,起点在右端。column:主轴为垂直方向,起点在上沿。column-reverse:主轴为垂直方向,起点在下沿。
3.2 flex-wrap属性
默认情况下,项目都排在一条线(又称"轴线")上。flex-wrap属性定义,如果一条轴线排不下,如何换行。
它可能取三个值。
(1)nowrap(默认):不换行。
(2)wrap:换行,第一行在上方。
(3)wrap-reverse:换行,第一行在下方。(少见)
3.3 flex-flow
flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap。
.box {
flex-flow: row nowrap;
}
3.4 justify-content属性 左右对齐
justify-content属性定义了项目在主轴上的对齐方式。
.box {
justify-content: flex-start | flex-end | center | space-between | space-around;
}
它可能取5个值,具体对齐方式与轴的方向有关。下面假设主轴为从左到右。
flex-start(默认值):从头对齐flex-end:从尾对齐center: 居中space-between:先两边贴边,再平分剩余空间space-around:平分剩余空间。所以,项目之间的间隔比项目与边框的间隔大一倍。
3.5 align-items属性 单行上下对齐
align-items属性定义项目在侧轴上如何对齐。单行时起效
它可能取5个值。具体的对齐方式与交叉轴的方向有关,下面假设交叉轴从上到下。
flex-start:交叉轴的起点对齐。flex-end:交叉轴的终点对齐。center:交叉轴的中点对齐。baseline: 项目的第一行文字的基线对齐。stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。
3.6 align-content属性 多行上下对齐
align-content属性定义了多根轴线的对齐方式。多行时起效
该属性可能取6个值。
flex-start:从侧轴头部开始flex-end:从侧轴尾部开始center:居中对齐space-between:先两端对齐,再平均分布轴线之间的间隔space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。stretch(默认值):子项元素平分父项高度
四、子项属性
以下6个属性设置在项目上。
order(掌握)flex-growflex-shrinkflex-basisflex(掌握)align-self(掌握)
4.1 order属性
order属性定义项目的排列顺序。数值越小,排列越靠前,默认为0。
.item {
order: <integer>;
}
4.2 flex-grow属性
flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。
.item {
flex-grow: <number>; /* default 0 */
}
如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。
4.3 flex-shrink属性
flex-shrink属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。
.item {
flex-shrink: <number>; /* default 1 */
}
如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小。如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。
负值对该属性无效。
4.4 flex-basis属性
flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。
.item {
flex-basis: <length> | auto; /* default auto */
}
它可以设为跟width或height属性一样的值(比如350px),则项目将占据固定空间。
4.5 flex属性
flex属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。
.item {
flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}
该属性有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)。
建议优先使用这个属性,而不是单独写三个分离的属性,因为浏览器会推算相关值。
一般就写第一个数字,代表某子项在主轴剩余长度上占的份数
4.6 align-self属性
align-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。
.item {
align-self: auto | flex-start | flex-end | center | baseline | stretch;
}
该属性可能取6个值,除了auto,其他都与align-items属性完全一致。
Grid布局
Grid 布局与Flex布局有一定的相似性,都可以指定容器内部多个项目的位置。但是,它们也存在重大区别。
Flex 布局是轴线布局,只能指定"项目"针对轴线的位置,可以看作是一维布局。Grid 布局则是将容器划分成"行"和"列",产生单元格,然后指定"项目所在"的单元格,可以看作是二维布局。Grid 布局远比 Flex 布局强大。
<div class="container">
<div class="item item-1"></div>
<div class="item item-2"></div>
<div class="item item-3"></div>
</div>
.container {
display: grid | inline-grid;
}
父项属性
子项属性
双飞翼/圣杯布局
共同点:
- 两侧宽度固定,中间宽度自适应
- 中间部分在DOM结构上优先,以便先行渲染
- 允许三列中的任意一列成为最高列
- 只需要使用一个额外的
<div>标签
圣杯布局
核心是通过container的左右两个padding预留固定位置
1. DOM结构
<div id="header"></div>
<div id="container">
<div id="center" class="column"></div>
<div id="left" class="column"></div>
<div id="right" class="column"></div>
</div>
<div id="footer"></div>
首先定义出整个布局的DOM结构,主体部分是由container包裹的center,left,right三列,其中center定义在最前面。
2. CSS代码
假设左侧的固定宽度为200px,右侧的固定宽度为150px,则首先在container上设置:
#container {
padding-left: 200px;
padding-right: 150px;
}
为左右两列预留出相应的空间,得到如下示意图:
创建布局框架
随后分别为三列设置宽度与浮动,同时对footer设置清除浮动:
#container .column {
float: left;
}
#center {
width: 100%;
}
#left {
width: 200px;
}
#right {
width: 150px;
}
#footer {
clear: both;
}
得到如下效果:
设置宽度和清除浮动
根据浮动的特性,由于center的宽度为100%,即占据了第一行的所有空间,所以left和right被“挤”到了第二行。
接下来的工作是将left放置到之前预留出的位置上,这里使用**负外边距(nagetive margin)** :
#left {
width: 200px;
margin-left: -100%;
}
得到:
将left移动到预留位置-1
随后还需要使用定位(position) 方法:
#left {
width: 200px;
margin-left: -100%;
position: relative;
right: 200px;
}
这里使用position: relative和right: 200px将left的位置在原有位置基础上左移200px,以完成left的放置:
将left移动到预留位置-2
接下来放置right,只需添加一条声明即可:
#right {
width: 150px;
margin-right: -150px;
}
得到最终的效果图:
将right移动到预留位置
至此,布局效果完成。不过还需要考虑最后一步,那就是页面的最小宽度:要想保证该布局效果正常显示,由于两侧都具有固定的宽度,所以需要给定页面一个最小的宽度,但这并不只是简单的200+150=350px。回想之前left使用了position: relative,所以就意味着在center开始的区域,还存在着一个left的宽度。所以页面的最小宽度应该设置为200+150+200=550px:
body {
min-width: 550px;
}
综上所述,圣杯布局的CSS代码为:
body {
min-width: 550px;
}
#container {
padding-left: 200px;
padding-right: 150px;
}
#container .column {
float: left;
}
#center {
width: 100%;
}
#left {
width: 200px;
margin-left: -100%;
position: relative;
right: 200px;
}
#right {
width: 150px;
margin-right: -150px;
}
#footer {
clear: both;
}
最后提醒一下很多朋友可能会忽略的小细节:在#center中,包含了一条声明width: 100%,这是中间栏能够做到自适应的关键。可能会有朋友认为不需要设置这条声明,因为觉得center在不设置宽度的情况下会默认将宽度设置为父元素(container)的100%宽度。但需要注意到,center是浮动元素,由于浮动具有包裹性,在不显式设置宽度的情况下会自动“收缩”到内容的尺寸大小。如果去掉width: 100%,则当中间栏不包含或者包含较少内容时,整个布局会“崩掉”,而达不到这样的效果:
中间栏仅包含较少内容
双飞翼布局
核心是通过container的左右两个margin来预留位置
1. DOM结构
<body>
<div id="header"></div>
<div id="container" class="column">
<div id="center"></div>
</div>
<div id="left" class="column"></div>
<div id="right" class="column"></div>
<div id="footer"></div>
<body>
双飞翼布局的DOM结构与圣杯布局的区别是用container仅包裹住center,另外将.column类从center移至container上。
2. CSS代码
按照与圣杯布局相同的思路,首先设置各列的宽度与浮动,并且为左右两列预留出空间,以及为footer设置浮动清除:
#container {
width: 100%;
}
.column {
float: left;
}
#center {
margin-left: 200px;
margin-right: 150px;
}
#left {
width: 200px;
}
#right {
width: 150px;
}
#footer {
clear: both;
}
得到如下效果示意图:
双飞翼布局初始设置
以上代码将container,left,right设置为float: left,而在container内部,center由于没有设置浮动,所以其宽度默认为container的100%宽度,通过对其设置margin-left和margin-right为左右两列预留出了空间。
将left放置到预留位置:
#left {
width: 200px;
margin-left: -100%;
}
得到:
将right放置到预留位置:
#right {
width: 150px;
margin-left: -150px;
}
得到最终效果:
双飞翼布局最终效果
最后计算最小页面宽度:由于双飞翼布局没有用到position:relative进行定位,所以最小页面宽度应该为200+150=350px。但是当页面宽度缩小到350px附近时,会挤占中间栏的宽度,使得其内容被右侧栏覆盖,如下所示:
中间栏内容被覆盖
因此在设置最小页面宽度时,应该适当增加一些宽度以供中间栏使用(假设为150px),则有:
body {
min-width: 500px;
}
至此双飞翼布局大功告成!其布局整体代码为:
body {
min-width: 500px;
}
#container {
width: 100%;
}
.column {
float: left;
}
#center {
margin-left: 200px;
margin-right: 150px;
}
#left {
width: 200px;
margin-left: -100%;
}
#right {
width: 150px;
margin-left: -150px;
}
#footer {
clear: both;
}
总结与思考
双飞翼布局的DOM结构与圣杯布局的区别是:
双飞翼的container仅包裹住center,与left/right并列,圣杯的container包住left、center、right三个(双飞翼的左右盒子像两个翅膀到处乱飞==)
通过对圣杯布局和双飞翼布局的介绍可以看出,圣杯布局在DOM结构上显得更加直观和自然,且在日常开发过程中,更容易形成这样的DOM结构(通常<aside>和<article>/<section>一起被嵌套在<main>中);而双飞翼布局在实现上由于不需要使用定位,所以更加简洁,且允许的页面最小宽度通常比圣杯布局更小。
其实通过思考不难发现,两者在代码实现上都额外引入了一个<div>标签,其目的都是为了既能保证中间栏产生浮动(浮动后还必须显式设置宽度),又能限制自身宽度为两侧栏留出空间。
从这个角度出发,如果去掉额外添加的<div>标签,能否完成相同的布局呢?答案是肯定的,不过这需要在兼容性上做出牺牲:
DOM结构
<div id="header"></div>
<div id="center" class="column"></div>
<div id="left" class="column"></div>
<div id="right" class="column"></div>
<div id="footer"></div>
去掉额外的<div>标签后,得到的DOM结构如上所示,基于双飞翼布局的实现思路,只需要在center上做出修改:
使用calc()实现三栏布局
.column {
float: left;
}
#center {
margin-left: 200px;
margin-right: 150px;
width: calc(100% - 350px);
}
通过calc()可以十分方便地计算出center应该占据的自适应宽度,目前calc()支持到IE9。
使用border-box实现三栏布局
.column {
float: left;
}
#center {
padding-left: 200px;
padding-right: 150px;
box-sizing: border-box;
width: 100%;
}
使用border-box可以将center的整个盒模型宽度设置为父元素的100%宽度,此时再利用padding-left和padding-right可以自动得到中间栏的自适应宽度。不过需要注意的是,由于padding是盒子的一部分,所以padding部分会具有中间栏的背景色,当中间栏高于侧栏时,会出现这样的情况:
padding背景色影响左侧空间
目前box-sizing支持到IE8。
使用flex实现三栏布局
这里使用flex还是需要与圣杯布局相同的DOM结构,不过在实现上将更加简单:
<!-- DOM结构 -->
<div id="container">
<div id="center"></div>
<div id="left"></div>
<div id="right"></div>
</div>
CSS代码如下:
#container {
display: flex;
}
#center {
flex: 1;
}
#left {
flex: 0 0 200px;/*或者直接width: 200px;*/
order: -1;
}
#right {
flex: 0 0 150px;/*或者直接width: 150px;*/
}
让一个元素水平垂直居中
零、纯文字的情况
水平:text-align: center
垂直:line-height的取值等于父盒子height
一、使用 flex 弹性布局
首先将父元素设置为
开启弹性布局:display:flex;
水平居中:justify-content: center;
垂直居中:align-items: center;
其次将父元素高度设置为 height:100vh,根据 css3 的规范,1vh 等于视口高度的1%,那么 100vh 就是适口高度的 100%,即占满整个屏幕。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<title>React App</title>
</head>
<style>
body{
margin: 0;
}
#father{
display: flex;
justify-content: center;
align-items: center;
background: rgba(0,0,0,0.7);
height:100vh;
}
#son{
width: 80%;
height: 60%;
background: white;
border-radius: 30px;
}
</style>
<body>
<div id="father"><div id="son"></div></div>
</body>
</html>
二、基于子绝父相
负margin法
父元素设置position为relative,子元素position为absolute,top,left为:50%,margin-left,margin-top各为其自身宽或高的一半的负数(依赖元素宽高)
calc法
同上,父元素设置position为relative,子元素position为absolute,top,left为:50%,采用calc(50%-其自身宽或高的一半)
transform法
同上,父元素设置position为relative,子元素position为absolute,top,left为:50%,并使用 transform: translate(-50%, -50%);
4个0法
还是父元素设置position为relative,子元素position为absolute,其它见代码
三、display:table-cell法
父元素 display:table-cell; vertical-align:middle
四、伪元素法
在父元素中增加一个高度为100%的空元素,其他详见代码
让一个元素隐藏
opacity:0
占位 交互
opacity属性的意思是设置一个元素的透明度。它不是为改变元素的边界框(bounding box)而设计的。这一位着将opacity设置为0只能从视觉上隐藏元素。而元素本身依然占据它自己的位置并对网页的布局起作用,它也将响应用户交互。
visibility:hidden
占位 不交互
如同opacity属性,被隐藏的元素依然会对我们的网页布局起作用。与opacity唯一不同的是它不会响应任何用户交互。此外元素在读屏软件中会被隐藏
注意,如果一个元素的visibility被设置为hidden,同时想要显示它的某个子孙元素,只要将那个元素的visibility显式设置为visible即可。
dispaly:none
不占位 不交互
display属性依照词义真正隐藏元素。将display属性设为none确保元素不可见并且连盒模型也不生成。使用这个属性,被隐藏的元素不占据任何空间。不仅如此,一旦display设为none任何对该元素直接打用户交互操作都不可能生效。此外,读屏软件也不会读到元素的内容。这种方式产生的效果就像元素完全不存在。
任何这个元素的子孙元素也会被同时隐藏。为这个属性添加过度动画是无效的,他的任何不同状态值之间的切换总是会立即生效。
不过请注意,通过DOM依然可以访问到这个元素。因此你可以通过DOM来操作它。
总结visibility:hidden和dispaly:none的区别
- display会让元素在渲染树中消失,渲染时不占据空间;visibility不会让元素在渲染树中消失,渲染占据空间
- display是非继承属性,修改子孙节点的display属性也不能让它们显示;visibility是继承属性,给子孙节点加visibility:visible可以让子孙节点显示
- 修改display会造成重排,修改display只会造成重绘
position:absolute + 移动到不可见区域
动画
一、transition
transition的属性
属性可以分开写,也可以放在一起写,比如下面的代码,图片的宽高本来都是15px,想要让它1秒的时间内过渡到宽高为450px,通过:hover来触发,那么代码就可以如下:
img{
height:15px;
width:15px;
transition: 1s 1s height ease;/*合在一起*/
}
或者:
img{
height:15px;
width: 15px;
transition-property: height;
transition-duration: 1s;
transition-delay: 1s;
transition-timing-function: ease;/*属性分开写*/
}
img:hover{
height: 450px;
width: 450px;
}
因为过渡所需要时间与过渡延迟时间的单位都是秒,所以在合起来写transition的属性的时候,第一个time会解析为transiton-duration,第二个解析为transition-delay。所以,可以给transition一个速记法
transiton: 过渡属性 过渡所需要时间 过渡动画函数 过渡延迟时间;
属性详解
transition-property 不是所有属性都能过渡,只有属性具有一个中间点值才具备过渡效果。
transition-duration 指定从一个属性到另一个属性过渡所要花费的时间。默认值为0,为0时,表示变化是瞬时的,看不到过渡效果。
transiton-timing-function 过渡函数,有如下几种:
liner :匀速 ease-in:减速 ease-out:加速 ease-in-out:先加速再减速 cubic-bezier:三次贝塞尔曲线,可以定制
触发过渡
单纯的代码不会触发任何过渡操作,需要通过用户的行为(如点击,悬浮等)触发,可触发的方式有: :hoever :focus :checked 媒体查询触发 JavaScript触发
局限性
transition的优点在于简单易用,但是它有几个很大的局限。 (1)transition需要事件触发,所以没法在网页加载时自动发生。 (2)transition是一次性的,不能重复发生,除非一再触发。 (3)transition只能定义开始状态和结束状态,不能定义中间状态,也就是说只有两个状态。 (4)一条transition规则,只能定义一个属性的变化,不能涉及多个属性。 CSS Animation就是为了解决这些问题而提出的。
二、animatioin
CSS3的animation属性可以像Flash制作动画一样,通过控制关键帧来控制动画的每一步,实现更为复杂的动画效果。ainimation实现动画效果主要由两部分组成: 1)通过类似Flash动画中的帧来声明一个动画; 2)在animation属性中调用关键帧声明的动画。
Note:animation属性到目前位置得到了大多数浏览器的支持,但是,需要添加浏览器前缀哦!
animation动画属性
还是先列表格来说明属性,自己感觉会比较清晰:
(1)animation-name:none为默认值,将没有任何动画效果,其可以用来覆盖任何动画 (2)animation-duration:默认值为0,意味着动画周期为0,也就是没有任何动画效果 (3)animation-timing-function:与transition-timing-function一样 (4)animation-delay:在开始执行动画时需要等待的时间 (5)animation-iteration-count:定义动画的播放次数,默认为1,如果为infinite,则无限次循环播放 (6)animation-direction:默认为nomal,每次循环都是向前播放,(0-100),另一个值为alternate,动画播放为偶数次则向前播放,如果为基数词就反方向播放 (7)animation-state:默认为running,播放,paused,暂停 (8)animation-fill-mode:定义动画开始之前和结束之后发生的操作,默认值为none,动画结束时回到动画没开始时的状态;forwards,动画结束后继续应用最后关键帧的位置,即保存在结束状态;backwards,让动画回到第一帧的状态;both:轮流应用forwards和backwards规则。
@keyframes
CSS3的animation制作动画效果主要包括两部分:1. 用关键帧声明一个动画,2.在animation调用关键帧声明的的动画。
@keyframes就是关键帧。这个帧与Flash里的帧类似,一个动画中可以有很多个帧。
一个@keyframes中的样式规则是由多个百分比构成的,可以在这个规则上创建多个百分比,从而达到一种不断变化的效果。另外,@keyframes必须要加webkit前缀。举个例子:
div:hover {
-webkit-animation: 1s changeColor;
animation: 1s changeColor;
}
@-webkit-keyframes changeColor {
0% { background: #c00; }
50% { background: orange; }
100% { background: yellowgreen; }
}
@keyframes changeColor {
0% { background: #c00; }
50% { background: orange; }
100% { background: yellowgreen; }
}
上面代码中的0% 100%的百分号都不能省略,0%可以由from代替,100%可以由to代替。要让changeColor动画有效果,就必须要通过CSS3animation属性来调用它。
区别
animation和transition都是随着时间改变元素的属性值,其主要区别在于:
transition需要触发一个事件才会随着时间改变其CSS属性;animation在不需要触发任何事件的情况下,也可以显式的随时间变化来改变元素CSS属性,达到一种动画的效果
SASS与LESS
Sass和Less都属于Css预处理器,Css预处理器定义了一种新的语言,其基本思想是用一种专门的编程语言,为Css增加一些编程的特性,将Css作为目标生成文件,然后开发者使用这种语言进行Css编码工作(用一种专门的编程语言,进行Web网页样式设计,再通过编译器转化为正常的Css文件,以供项目使用)。
为什么要使用Sass、Less
因为css只是单纯的属性描述,它并不具有变量、条件语句等,css的特性导致了它难组织和维护。
Less与Sass的共性
- 混合(Mixins):将一个定义好的classA引入到另一个classB中,从而简单实现classB继承了classA的所有属性;
- 参数混合(Parametric):可以像函数一样传递参数的class
- 嵌套规则:class中嵌套class,从而减少重复的代码
- 运算:css中的数学计算
- 颜色功能:可以编辑你的颜色
- 命名空间:样式分组,从而方便被调用
- 作用域:局部修改样式
- JavaScript表达式:在css样式中使用javaScript表达式赋值
Less与Sass的不同
Less是基于JavaScript的在客户端处理,很多开发者不会选择Less因为javaScript引擎需要额外的时间来处理代码然后输出修改过的Css到浏览器
【解决:只在开发阶段使用Less,一旦开发完成,复制Less输出的到一个压缩器,然后用一个单独的css文件来代替Less文件;另一种方式是使用Less App来编译和压缩你的Less文件;这两种方式都是最小化样式输出】
Sass是基于ruby在服务器处理
less表示变量
需要使用@符号声明变量, 并使用冒号(:)来分配变量中的特定值。还必须在变量的值之后添加分号(;)。
例如:
@primarycolor: #FF7F50;
@color:#800080;
h1 {
color: @primarycolor;
}
h3 {
color: @color;
}
在Less的上述示例中, Less编程中使用的两个变量的值分别为#FF7F50和#800080。
CSS3新特性
新增选择器
属性选择器
E[abc*="def"] 选择adc属性值中包含子串"def"的所有元素
(1)利用属性选择器可以不用借助类或id选择器
例:input [values] { ....; } //选择出input中带有values属性的 1 (2)属性选择器还可以选择属性等于值的某些元素(重要)
input [type=text]{ ...; } //选择处input中type值等于text的 1 (3)属性选择器可以选择以某属性值开头的某些元素
div[class^=icon]{....;} //选择div中具有class属性,且属性必须是icon开头的这些元素 1 (4)属性选择器可以选择以某属性值结尾的某些元素
div[class$=data]{....;} //选择div中具有class属性,且属性必须是data结尾的这些元素 1 (5)属性选择器可以选择内含某些属性值的元素
div[class*=icon]{....;} //选择div中具有class属性,且属性内含icon的这些元素
结构伪类选择器
E:nth-child(n) 选择器匹配其父元素的第n个子元素,不论元素类型,n可以使数字,关键字,或公式
E:nth-of-type(n) 选择与之其匹配的父元素的第N个子元素
E:frist-child 相对于父级做参考,“所有”子元素的第一个子元素,并且“位置”要对应
E:frist-of-type 相对于父级做参考,“特定类型”(E)的第一个子元素
E:empty 选择没有子元素的每个E元素
E:target 选择当前活动的E元素
结构伪类选择器主要根据文档结构来选择元素,常用于根据父级选择器里面的子元素 (1)E:first-child 选择元素中的第一个子元素。
div:first-child { background-color: var(--red);
}
(2)E:last-child 选择元素的最后一个子元素。
div:last-child { background-color: var(--red); }
(3):nth-child(n) 定位某个父元素的一个或多个特定的子元素。其中 n 是其参数。(会把所有的孩子都标注序号)n 取值如下:
整数值(1 || 2 || 3 || 4 || …) 参数n的起始值为1,不是0,若要选中第一个元素nth-child(1)。
表达式(2n+1 || -n+5(前五个,包括第五个) || …) 为表达式时,n从0开始,表达式的值为0或小于0的时,不选择任何匹配的元素。
关键词(odd || even) odd 和 even 是可用于匹配下标是奇数(odd)或偶数(even)的子元素的关键词(第一个子素的下标是 1)。
div:nth-child(2n) { background-color: var(--red); }
E:first-of-type 指定元素E的第一个
E:last-of-type 指定元素E的最后一个
E:nth-of-type(n)选择器 指定类型E的第n个
伪元素选择器
一、 ::first-letter 第一个字
二、 ::first-line 第一行(以浏览器为准的第一行)
三、 ::selection 被选中的字行(鼠标选中的字段)只能向 ::selection 选择器应用少量 CSS 属性:color、background、cursor 以及 outline。
四、 ::before 和 ::after \1. 必须带一个属性content \2.在内部内容的前面或者后面插入内容
伪元素选择器可以帮助我们CSS创建新标签元素,而不需要HTML标签,从而简化HTML结构 语法:
element :: before/after { 样式; }
before和after必须有content属性 before在父元素内容的前面创建元素,after在父元素内容的后面插入元素 伪元素选择器和标签选择器权重相同 例:
.tudou::before{ content :''; /隐藏遮罩层/ display:none; position:absolute; top :0; left:0; width:100%; height:100%; backgroung:rgba(0,0,0,0.4) url(images/arr.png) no-repeat ccenter; }
/当鼠标经过土豆这个盒子,就让里面的before遮罩层显示出来/ .tudou:hover::before{ /显示元素/ display:block; }
应用:伪元素清除浮动(前面学过)
盒子模型
CSS3中可以通过box-sizing来指定盒模型,有两个值:即可指定为content-box,border-box,这样我们计算盒子大小的方式就发生了改变。 可分为两种情况: 1.box-sizing:content-box 盒子大小为 widtn+padding+border(以前默认的) 2.box-sizing:border-box 盒子大小为width(此法中padding和border就不会撑大盒子)(常用)
transition animation transform
过渡 transition: CSS属性,花费时间,效果曲线(默认ease),延迟时间(默认0)复制代码
动画 animation:动画名称,一个周期花费时间,运动曲线(默认ease),动画延迟(默认0),播放次数(默认1),是否反向播放动画(默认normal),是否暂停动画(默认running)复制代码
形状转换 transform:适用于2D或3D转换的元素
rotate(30deg); translate(30px,30px); scale(.8); skew(10deg,10deg); rotateX(180deg); rotateY(180deg); rotate3d(10,10,10,90deg);
CSS性能优化
1. 合并css文件,如果页面加载10个css文件,每个文件1k,那么也要比只加载一个100k的css文件慢。
2. 减少css嵌套,最好不要嵌套三层以上。
3. 不要在ID选择器前面进行嵌套,ID本来就是唯一的而且权限值大,嵌套完全是浪费性能。
4. 建立公共样式类,把相同样式提取出来作为公共类使用。
5. 减少通配符*或者类似[hidden="true"]这类选择器的使用,挨个查找所有...这性能能好吗?
6. 巧妙运用css的继承机制,如果父节点定义了,子节点就无需定义。
7. 拆分出公共css文件,对于比较大的项目可以将大部分页面的公共结构样式提取出来放到单独css文件里,这样一次下载 后就放到缓存里,当然这种做法会增加请求,具体做法应以实际情况而定。
8. 不用css表达式,表达式只是让你的代码显得更加酷炫,但是对性能的浪费可能是超乎你想象的。
9. 少用css rest,可能会觉得重置样式是规范,但是其实其中有很多操作是不必要不友好的,有需求有兴趣,可以选择normolize.css。
10. cssSprite,合成所有icon图片,用宽高加上background-position的背景图方式显现icon图,这样很实用,减少了http请求。
11. 善后工作,css压缩(在线压缩工具 YUI Compressor)
12. GZIP压缩,是一种流行的文件压缩算法。
123456789101112
> 1. 避免使用@import,外部的css文件中使用@import会使得页面在加载时增加额外的延迟。
首先,使用@import引入css会影响浏览器的并行下载。使用@import引用的css文件只有在引用它的那个css文件被下载,解析之后,浏览器才会知道还有另外一个css需要下载,这时才去下载,然后下载后开始解析,构建render tree等一系列操作,这就导致浏览器无法并行下载 所需的样式文件。 其次,多个@import会导致下载顺序紊乱,在IE中,@import会引发资源文件的下载顺序被打乱,即排列在@import后面的js文件优先于@import下载,并且打乱甚至破坏@import自身的并行下载。 所以不要使用这一方法,使用link标签就行了。
> 2.避免过分重排
- 浏览器为了重新渲染部分或整个页面,重新计算页面元素位置和几何结构的进程叫做reflow
- 浏览器根据定义好的样式来计算,并将元素放到该出现的位置上,这个过程叫做reflow
- 页面上任何一个节点触发来reflow,会导致他的子节点和祖先节点重新渲染
- 导致reflow发生的情况
1. 改变窗口的大小
2. 改变文字的大小
3. 添加 删除样式表
4. 内容的改变 输入框输入内容也会
5. 伪类的激活
6. 操作class属性
7. 脚本操作dom js改变css类
8. 计算offsetWidth和offsetHeight
9. 设置style属性
10.改变元素的内外边距
12345678910
- 常见重排元素
1. 大小有关的 width,height,padding,margin,border-width,border,min-height
2. 布局有关的 display,top,position,float,left,right,bottom
3. 字体有关的 font-size,text-align,font-weight,font-family,line-height,white-space,vertical-align
4. 隐藏有关的 overflow,overflow-x,overflow-y
1234
- 减少reflow对性能的影响的建议
1. 不要一条条的修改dom的样式,预先定义好class,然后修改dom的classname
2. 不要修改影响范围较大的dom
3. 为动画元素使用绝对定位
4. 不要table布局,因为一个很小的改动会造成整个table重新布局
5. 避免设置大量的style属性,通过设置style属性改变节点样式的话,每一次设置都会触发一次reflow,所以最好使用class属性
6. 如果css里面有计算表达式,每次都会重新计算一遍,触发一次reflow
123456
> repaint
- 当一个元素的外观被改变,但是布局没有改变的情况
- 当元素改变的时候,不影响元素在页面中的位置,浏览器仅仅会用新的样式重绘此元素
- 常见的重绘元素
- 颜色 color,background
- 边框样式 border-style,outline-color,outline,outline-style,border-radius,box-shadow,outline-width
- 背景有关 background,backgound-image,background-position,background-repeat,background-size
123
> CSS动画
- css动画启用GPU加速,应用GPU的图形性能对浏览器中的一些图形操作交给GPU完成。canvas2D,布局合成,css3转换,css3d变换,webGL,视频
- 2d加速
- 3d加速
> 文件压缩
性能优化时最容易想到的,也是最常见的方法,就是文件压缩,这一方案往往效果显著 文件的大小会直接影响浏览器的加载速度,这一点在网络较差时表现尤为明显,构建工具webpack,gulp/grunt,rollup,压缩之后能够明显减少,可以大大降低浏览器的加载时间。
> 去除无用CSS
虽然文件压缩能够降低文件大小,但css文件压缩通常只会去除无用的空格,这样就限制来css文件的压缩比例。如果压缩后的文件仍然超过来预期的大小,可以试着找到并删除代码中无用的css。 一般情况下,会存在这两种无用的CSS代码:
- 不同元素或者其他情况下的重复代码,
- 整个页面内没有生效的CSS代码
> 有选择地使用选择器
css选择器的匹配是从右向左进行的,这一策略导致来不同种类的选择器之间的性能也存在差异。相比于 #markdown-content-h3,显然使用 #markdown.content h3时,浏览器生成渲染树所要花费的时间更多。因为后者需要先找到DOM中的所有h3元素,再过滤掉祖先元素不是.content的,最后过滤掉.content不是#markdown的。试想,页面中的元素更多,那么匹配所要花费的时间代价自然更高。 显得浏览器在这一方面做了很多优化,不同选择器的性能差别并不明显,甚至可以说差别甚微,此外不同选择器在不同浏览器中的性能表现也不统一,在编写css的时候无法兼顾每种浏览器,鉴于这两点,在使用选择器时,尽量记住以下几点:
1. 保持简单,不要使用嵌套过多过于复杂的选择器
2. 通配符和属性选择器效率最低,需要匹配的元素最多,尽量避免使用。
3. 不要使用类选择器和ID选择器修饰元素标签,如:h3#markdown-content,这一多此一举,还会降低效率
4. 不要为了追求速度而放弃可读性和可维护性
1234
TIPS:为什么css选择器是从右向左匹配的? css中更多的选择器是不会匹配的,所以在考虑性能问题时,需要考虑的是如何在选择器不匹配时提升效率,从右向左匹配就是为了达成这一目的的,通过这一策略能够使得css选择器在不匹配的时候效率更高。
> 减少使用昂贵的属性
在浏览器绘制屏幕时,所有需要浏览器进行操作或计算的属性相对而言都需要花费更大的代价,而页面发生重绘时,它们会降低浏览器的渲染性能。所以在编写css时,应该尽量减少使用昂贵属性,如: box-shadow, border-radius, filter, 透明度, :nth-child等 当然并不是不要使用这些属性,这些都是经常使用的属性,只是这里可以作为一个了解。当有其他方案可以选择的时候,可以优先选择没有昂贵属性或昂贵属性更少的方案,这一网站的性能会在不知不觉中得到一定的提升。
> 硬件加速的好坏
- 仅仅依靠GPU还是不行的,许多动画还是需要CPU的介入,连接cpu和GPU的总带宽不是无限的,所以需要注意数据在cpu和GPU之间的传输,尽量避免造成通道的拥挤,要一直注意像素的传输。
- 一个重点是了解创建的合成层的数量,每一个层都对应来一个GPU纹理,太多的层会消耗很多内存。
**chrome://flags/#composited-layer-borders**观察的地址。- 每一个dom元素的合成层都会被标记一个额外的边框,这一就可以验证是否有了很多层
- 另一个重点是保持GPU和CPU之间传输量达到最小值,也就是说,层的更新数量最好是一个理想的常量,每次层更新的时候,一堆新的像素就可能需要传输给GPU。
- 因为为了高性能,动画开始之后避免层的更新也是非常重要的,避免动画进行中其他层一直更新导致拥堵。
- 也就是使用这些css属性来实现动画:transformation, opacity, filter
- 使用性能工具检测优化的合理性,timeline检测优化是否合理,还需要实现自动操作来做性能回归测试。
- 检测层数和层更新次数是非常有用的。