CSS

写在前面

最近看了两本书《CSS揭秘》和《CSS权威指南》恶补一下CSS(自己真是菜到天际),记录一些有意思的问题

CSS高度由什么决定?

块级元素

一个块级元素div的高度一般是与自身的CSS样式内部元素的高度总和有关

  • div设置了height后,整个盒模型的高度基本确定,其内部元素再高也无法改变div的高度
  • div不设置height时,其高度和内部文档流元素高度的总和有关
块级元素不设置高度,内有块级元素时

会被子元素的height、padding、border撑起来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<style>
*{
margin: 0;
padding: 0;
}
.parent{
outline: 5px solid red;
width: 300px;
}
.child{
height:400px;
border: 5px solid green;
}
</style>
<div class="parent">
<div class="child"></div>
</div>

如图,父级元素不设高度,高度为子元素height+border

image-20210930012419754
image-20210930012419754

子元素设置margin时

父元素高度无法被子元素垂直方向上margin撑开

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<style>
* {
margin: 0px;
padding: 0px;
}

.parent {
outline: 5px solid red;
width: 300px;
}

.child {
height: 400px;
border: 5px solid green;
margin: 20px;
}
</style>
<div class="parent">
<div class="child"></div>
</div>

image-20210930012419754
image-20210930012419754

解决方案:父元素设置border/padding/overflow:hidden

总结:父元素高度能被子元素的height、border、padding撑开,如果父元元素在垂直方向上有border,padding(只要在逻辑上存在,不论大小)以及overflow:hidden,都能被子元素的margin撑开,否则只能撑开父元素的宽度


CSS宽度由什么决定?

行内/行内块元素

行内元素/行内块的宽度是由它的内容决定的,行内元素不能设置宽高

块级元素

一个块级元素宽度当不设置样式时默认为父级元素的100%(这个100%是自适应的,并不相当于width:100%)


为什么margin-top/padding-top设置百分比基于父元素的宽度计算的?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<head>
<style>
.parent {
width: 300px;
height: 400px;
border: 5px solid red;
}
.child {
height: 200px;
margin-top: 50%;
background-color: green;
}
</style>
</head>
<body>
<div class="parent">
<div class="child"></div>
</div>
</body>

image-20211120194334386

这里利用margin-top:50%将子元素挤到最下方贴底,然而这里的百分比是相对于父级宽度计算的。

CSS权威指南中的解释:若是相对于父元素的高度计算会形成死循环。
“我们认为,正常流中的大多数元素都会足够高以包含其后代元素(包括外边距),如果一个元素的上下外边距是父元素的height的百分数,就可能导致一个无限循环,父元素的height会增加,以适应后代元素上下外边距的增加,而相应的,上下外边距因为父元素height的增加也会增加,形成无限循环。”

本质上是因为css中高度是可以自适应的,基于父级高度的百分比计算会导致无限循环的问题


CSS定位

static定位

staticposition属性的默认值。

static定位所导致的元素位置,是浏览器自主决定的,static定位下topbottomleftright这四个属性无效。

relative

relative表示,相对于默认位置(即static时的位置)进行偏移,即定位基点是元素的默认位置。

absolute

absolute表示,相对于祖先元素第一个非static的父元素进行偏移,若没有任何一个祖先元素符合,则根据html根元素进行偏移

fixed

fixed表示,相对于视口(viewport,浏览器窗口)进行偏移,即定位基点是浏览器视口。实现类似固定在网页上一样的效果

sticky

sticky布局类似relativefixed的结合:一些时候是relative定位(定位基点是自身默认位置),另一些时候自动变成fixed定位(定位基点是视口)。

它的具体规则是,当页面滚动,父元素开始脱离视口时(即部分不可见),只要与sticky元素的距离达到生效门槛,relative定位自动切换为fixed定位;等到父元素完全脱离视口时(即完全不可见),fixed定位自动切换回relative定位。


Flex布局

容器属性

flex-direction

flex-direction属性决定主轴的方向(即项目的排列方向)。

flex-wrap

默认情况下,项目都排在一条线(又称”轴线”)上。flex-wrap属性定义,如果一条轴线排不下,如何换行。

justify-content

justify-content属性定义了项目在主轴上的对齐方式。

align-items

align-items属性定义项目在副轴上如何对齐。

align-content

align-content属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。

1
2
3
.box {
align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}

项目属性

order

order属性定义项目的排列顺序。数值越小,排列越靠前,默认为0。

flex

flex属性是flex-grow, flex-shrinkflex-basis的简写,默认值为0 1 auto。后两个属性可选。

flex:1

flex:x 相当于 flex-grow: x,flex-shrink:1,flex-basis:0%;

flex-grow: 定义项目的放大比例,0为不放大

flex-shrink: 定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。

flex-basis: 定义了在分配多余空间之前,项目占据的主轴空间。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。

``` 的含义是分配**主轴**方向上的剩余空间!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

所以对于竖直的两栏布局,只需要改变一下主轴方向即可

```html
<style>
body {
height: 100%;
width: 100%;
}
.f-box {
display: flex;
flex-direction: column;
border: 5px solid gray;
height: 100%;
}

.top {
height: 100px;
background-color: red;
}

.bot {
flex: 1;
background-color:blue;
}
</style>

<body>
<div class="f-box">
<div class="top"></div>
<div class="bot"></div>
</div>
</body>
align-self

align-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch

1
2
3
.item {
align-self: auto | flex-start | flex-end | center | baseline | stretch;
}

alt text


Grid布局

Grid 布局的属性分成两类。一类定义在容器上面,称为容器属性;另一类定义在项目上面,称为项目属性

容器属性

display: grid

指定网格布局

grid-template-columns 属性,grid-template-rows 属性

容器指定了网格布局以后,接着就要划分行和列。grid-template-columns属性定义每一列的列宽,grid-template-rows属性定义每一行的行高。

1
2
3
4
5
.container {
display: grid;
grid-template-columns: 100px 100px 100px;
grid-template-rows: 100px 100px 100px;
}

用repeat改写如下:

1
2
3
4
5
.container {
display: grid;
grid-template-columns: repeat(3, 33.33%);
grid-template-rows: repeat(3, 33.33%);
}

用fr改写如下:

1
2
3
4
.container {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
}

fr还可以与绝对长度的单位结合使用

1
2
3
4
.container {
display: grid;
grid-template-columns: 150px 1fr 2fr; // 类似flex 1flex 2这样分配剩余空间
}
grid-row-gap、grid-column-gap、grid-gap 属性

grid-row-gap属性设置行与行的间隔(行间距),grid-column-gap属性设置列与列的间隔(列间距)。

1
2
3
4
.container {
grid-row-gap: 20px;
grid-column-gap: 20px;
}

项目属性


display:none,visibility:hidden,opacity:0 的区别

display: none;

  1. DOM 结构:浏览器不会渲染 display 属性为 none 的元素,不占据空间;
  2. 事件监听:无法进行 DOM 事件监听;
  3. 性能:动态改变此属性时会引起重排,性能较差;
  4. 继承:不会被子元素继承,毕竟子类也不会被渲染;
  5. transition:transition 不支持 display。

visibility: hidden;

  1. DOM 结构:元素被隐藏,但是会被渲染不会消失,占据空间;
  2. 事件监听:无法进行 DOM 事件监听;
  3. 性 能:动态改变此属性时会引起重绘,性能较高;
  4. 继 承:会被子元素继承,子元素可以通过设置 visibility: visible; 来取消隐藏;
  5. transition:visibility 会立即显示,隐藏时会延时

opacity: 0;

  1. DOM 结构:透明度为 100%,元素隐藏,占据空间;
  2. 事件监听:可以进行 DOM 事件监听;
  3. 性 能:提升为合成层,不会触发重绘,性能较高;
  4. 继 承:会被子元素继承,且,子元素并不能通过 opacity: 1 来取消隐藏;
  5. transition:opacity 可以延时显示和隐藏