HTMLandCSS基础2

HTMLandCSS- Layout

The Box Model

在CSS中,一个很重要的概念就是Box Model,也就是当浏览器开始渲染的时候,。下图是一个简单的Box 模型。一共有4层:Content,Padding,Border和Margin。

我们随便写一个paragraph

1
2
3
<body>
<p>Lorem ipsum dolor sit amet.</p>
</body>

在浏览器里,我们可以看到这个paragraph的Box 模型

我们看到,这里只有content和margin是有内容的,padding和border都是没有内容的。Margin=16是 Chrome默认的值。现在我们可以用CSS来改变这些值,这里我为Box Model添加了padding和border两个值

1
2
3
4
p {
padding: 10px 20px 10px 20px;/*也可以写成 10px 20px;分别代表上下边距和左右边距*/
border: 5px solid gold;
}

我们发现,当我们设置了left padding=20px之后,这行文字总体向右移动了20px。

margin和padding之间的区别

也许我们会问:margin和padding都是设置文字和框的距离,那么这二者又有什么区别呢?我们举一个例子:

假设现在我们有两个 <p> 元素:

1
2
3
4
<body>
<p>Lorem ipsum dolor sit amet.</p>
<p>Lorem ipsum dolor sit amet.</p>
</body>

首先设置 padding =20px, margin = 0px;

绿色的边距就是padding,大小为20px,而且对于每个paragraph,都有20px的padding;

现在我们交换二者的值,padding = 0px 而 margin = 20px。黄色的代表margin,我们发现,现在两个paragraph共用一个margin,也就是它们之间的距离现在是20px。也就是说当两个paragraph相邻的时候,两个margin会合并成一个margin。

所以技术上来说,我们应该使用Margin来分隔元素,应该用padding增加content和border之间的距离

Sizing Elements

box-sizing属性

我们现在来定义一个100X100大小的正方体,并用css为其添加padding和border

1
2
3
4
5
6
7
.box {
width: 100px;
height: 100px;
background-color: gold;
padding: 20px;
border: 10px solid orange;
}

我们发现,本来是100X100的正方形,加了padding和border以后,变成了160X160的正方形,这是因为在每一边都加上了 20px的padding和10px的border。这和我们规定的100X100的相悖。

为了规避这种情况,我们可以在css中定义这个属性:box-sizing ,默认为content-box,也就是我们设置的大小其实是content的大小,现在我们将其设置为border-box,也就是我们设置的大小是带边框都算在内的 box 的大小。

1
2
3
4
5
6
7
8
.box {
width: 100px;
height: 100px;
background-color: gold;
padding: 20px;
border: 10px solid orange;
box-sizing: border-box;
}

Universal selector and pseudo element

如果我有很多的box,又不希望一直写这个属性。为了降低代码的重复性,我们可以使用全局选择器 *

但是这个 * 选择器并不适用于pseudo element,也就是 before , after 之类的元素。 为了囊括所有的元素,我们可以这样写:

1
2
3
4
5
*,
*::before,
*::after {
box-sizing: border-box;
}

span 元素与 display 属性

还有一个问题,就是 divspan之间的区别。我们之前说过 div是以块(block)呈现的而span是以行内(inline)格式呈现的。因此如果我将html中两个div元素改成span元素,虽然我规定了widthheight都为100px,结果却是这样:

如果我们要规避这个情况,我们可以修改display属性:对于span元素,display属性默认为inline;我们可以将其改成 inline-block,意思是 <span>元素仍然可以行内排列,而对于block使用的属性如widthheight也可以作用于其上。如下图所示:

1
2
3
4
5
6
.box {
width: 100px;
height: 100px;
background-color: gold;
display: inline-block;
}

Overflowing

overflow顾名思义就是溢出,在css中,当content的大小超过了我们规定的box的大小,这时候就会发生溢出。

1
2
3
4
5
.box {
border: 3px solid gold;
width: 150px;
height: 150px;
}

我规定了box的大小为150X150,但是字却很多,这时候就会发生溢出现象

这时候我们就可以在css中设置 overflow这个属性了:

默认为visible,也就是我们上面看到的情况。我们可以将其设置为hidden,也就是放不下的就直接隐藏掉了:

还可以设置为scroll,这时浏览器会渲染出两个滚动条,然而,在最近的mac版本,scroll是失效的:

或者设置为 auto,浏览器会自动检测是否出现overflow现象,如果出现了就会渲染两个滚动条,否则就不设置滚动条。

注意,overflow其实是 overflow-xoverflow-y二者的统一,为其赋值相当于在x和y轴都设置了值。如果我们希望对x和y分别设值,我们可以为overflow设置两个值:前者代表水平轴,后者代表垂直轴

如:overflow: hidden auto

Measurement Units

距离单位可以分为 Absolute 和 Relative两种, Absolute就是绝对的,固定的,比如说 px,in之类的单位。 Relative就是相对的。比如:

% Relative to the size of the container

vwvh ,Relative to the viewport

emrem Relative to the font size

对于Absolute measurement units,不管怎么调整我们的浏览器,它定义的对象的大小,都是不会变化的。这种单位常常用于顶端边框。这样边框的厚度就不会随着浏览器窗口的大小而变粗或者变细。

%

现在我们来看 relative value,首先我们看看 %,它让我们的元素属性是其父元素的百分之多少

这样来写css:已经知道body是div的父元素了

1
2
3
4
5
6
7
8
9
10
.box {
width: 50%;
height: 100px;
background-color: gold;
}

body {
margin: 10px;
width: 300px;
}

我们规定了 body的宽度,然后再把 width 设置为50%,这时候因为窗口的大小是被固定的:300px;因此box的宽度为150px。 当我们去掉 body的width属性之后,box的宽度就随着浏览器的宽度变化而变化了,且始终占据浏览器窗口边框长度的一半。

1
2
3
4
5
6
.box {
width: 50%;
height: 100px;
background-color: gold;
border-top: 3px solid orange;
}

vw vh

当我们把height 改成100%之后,神奇的事情发生了,按理说我们希望这个框框能占满窗口所有的垂直距离。但是事实上却出现了这种情况,我们发现框框消失了!这是为什么?

因为 我们的body并没有 height这一个属性,因此默认body的height属性为0,而%又是跟着父元素的对应属性走的,因此我们看到这个div的高度为0。

为了达到我们说的那种垂直占满窗口效果,我们可以使用 vh(viewport height)以及 vw(viewport weight)

比如我们这样来修改css:

1
2
3
4
5
6
.box {
width: 50vw;
height: 100vh;
background-color: gold;
border-top: 3px solid orange;
}

效果如下:

em,rem

em是相对于字体来说的一个单位,10em代表了 10倍的当前元素中字体的大小。这里div元素没有font-size属性,那么它就会去父元素中查找,如果一直没有,那么他就会默认使用HTML元素中的字体大小,也就是16px。

10em = 10 * 16px = 160px

1
2
3
4
5
6
.box {
width: 10em;
height: 10em;
background-color: gold;
border-top: 3px solid orange;
}

em有缺点,就是不太方便,因为如果当前元素没有定义 font-size的话,就要去它的父元素或者祖辈元素寻找,比较麻烦。这时候我们可以选用rem,也就是 root element,一般来说就是HTML元素的字体大小: 16px

1
2
3
4
5
6
7
8
9
10
body{
font-size: 62.5%;
}

.box {
width: 15rem;
height: 15rem;
background-color: gold;
border-top: 3px solid orange;
}

我们可以简单做一个计算题,现在body的font-size是 16px * 62.5% = 10px, div 的宽度为15px * 10 = 150px

我们可以在body中修改html元素中的字体,当然也可以直接在chrome的设置中修改字体的大小。

Positioning

这是我们的html,注意,每一个元素可以有多个class,它们之间用空格隔开。

1
2
3
4
5
6
7
<body>
<div class="boxes">
<div class="box box-one"></div>
<div class="box box-two"></div>
<div class="box-three"></div>
</div>
</body>

我的css如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

.boxes {
border: 3px solid lightgrey;
}

.box {
width: 5rem;
height: 5rem;
}

.box-one {
background: gold;
}

.box-two {
background: tomato;
}

.box-three {
background: blue;
}

现在,我们希望把第二个方块稍稍向右移动,怎么办? 我们需要用到 position属性

相对定位

  1. 当开启了元素的相对定位以后,而不设置偏移量时,元素不会发生任何变化
  2. 相对定位是相对于元素在文档流中原来的位置进行定位
  3. 相对定位的元素不会脱离文档流
  4. 相对定位不会改变元素的性质,块还是块,内联还是内联

当开启了元素的定位(position属性值是一个非static的值)时,可以通过left right top bottom四个属性来设置元素的偏移量

​ left:元素相对于其定位位置的左侧偏移量
​ right:元素相对于其定位位置的右侧偏移量
​ top:元素相对于其定位位置的上边的偏移量
​ bottom:元素相对于其定位位置下边的偏移

通常偏移量只需要使用两个就可以对一个元素进行定位, 一般选择水平方向的一个偏移量和垂直方向的偏移量来为一个元素进行定位

1
2
3
4
5
.box-two {
background: tomato;
position: relative;
left: 5rem;
}

这里我设置了left:5rem ,在中间方块的左边就会多出5rem的空白,如下图所示:

当然我们也可以设置 left为负值,这时候在原来方块的右边就会多出空白,而方块的一部分就会被挤到box外面去。

当然 left: -4rem;right: 4rem 是等价的,我们可以按照自己的喜好来定义。

还有 top bottom 这两个属性,用法同上。

z-index 属性

现在,红黄两个方块的堆叠方式如下:

但是我想修改这两个方块的前后顺序,想让黄色覆盖红色,怎么办?

我们可以使用 z-index,这也很好理解,窗口是一张画布,有了x、y轴,这个z轴就是画布的深度。 默认所有的元素z-index属性都是0,z-index 值越大,距离我们越近,反之则越远。我们只需要设置黄色方块的z-index为1,或者红色方块的z-index为-1 ,就能达到目的:

1
2
3
4
5
6
7
.box-two {
background: tomato;
position: relative;
left: 4rem;
bottom: 4rem;
z-index: -1;
}

绝对定位

绝对定位是相对于离他最近的开启了定位的祖先元素进行定位的(一般情况,开启了子元素的绝对定位都会同时开启父元素的相对定位)如果所有的祖先元素都没有开启定位,则会相对于浏览器窗口进行定位。 因此,在把第二个box的position设置成 absolute之前,我们首先要将container的position属性设置为relative。

原则:

  1. 开启绝对定位以后,如果不设置偏移量,则元素的位置不会发生变化
  2. 绝对定位会使元素提升一个层级
  3. 绝对定位会改变元素的性质, 内联元素变成块元素,块元素的宽度和高度默认都被内容撑开
1
2
3
4
5
6
7
.box-two {
background: tomato;
position: absolute;
right: 0;
bottom: 0;
z-index: 99999;
}

当我们设置了第二个箱子距离父元素的右下边框都为0时,发现其被移动到了box的右下角。而原来处在最下面的蓝色方框上移了一个框位。这是因为绝对定位会使元素提升一个层级,也就是说现在红色的框框和黄蓝色框框已经不是一层的了,而是和它的父元素是一个层级的。因此container中现在只有“两个”框了,红色框只是跟着container走,但并不属于container。

固定定位

固定定位也是一种绝对定位,它的大部分特点都和绝对定位一样 ,不同的是:

固定定位永远都会相对于浏览器窗口进行定位 ,固定定位会固定在浏览器窗口某个位置,不会随滚动条滚动,IE6不支持固定定位

固定定位常常用于导航栏,我们希望不管浏览器滚动到哪里,顶部始终是navigation bar,首先我们设置body的margin为200vh,这样就能让窗口始终存在滚动条。然后将第二个box的top属性设置为0。这样,不管怎么滚,这个box始终固定在浏览器窗口的最上位置

1
2
3
4
5
.box-two {
background: tomato;
position: fixed;
top: 0;
}

确定一个元素的长宽有两种方法,第一种是用 width和height,也是最直接的方法;第二种是利用 left,right,up和bottom,然后将width设置为auto,浏览器会根据left,right的值自动计算宽度。如下面这个例子:

我设置了 左右距离浏览器窗口都为2em长度,然后让width设置为auto,我们看到浏览器自动填充了这个box的宽度

1
2
3
4
5
6
7
8
9
.box-two {
background: tomato;
position: fixed;
top: 0;
left: 2em;
right: 2em;
width: auto;
z-index: 99;
}

Floating Elements

1
2
3
4
5
6
7
<body>
<article class="tweet">
<div class="avatar"></div>
<p>Lorem, ipsum dolor sit amet.</p>
<p>Lorem, ipsum dolor sit amet.</p>
</article>
</body>
1
2
3
4
5
.avatar{
width: 5rem;
height: 5rem;
background-color: gold;
}

如果我们的HTML文件和CSS文件向上面这样,那么结果如下图:文字会另起一行,因为<p>元素是block类型的元素。那么我们怎么做才能将文字放到方块旁边呢?

我们可以在 .avatar{}中设置 float元素,float: left;

当我们设置了 float为left的时候, 这个元素将会被放置到它后面所有元素的左边,如下图所示:

当文字很多的时候,这些文字就会围绕在格子的周围。上面格子和字体之间没有间隔,那么我们可以再加上 margin-right: 0.5rem,效果如下:

如果我把 left改成right,那么格子就会处于文字的右边

clear 属性

现在,我想把第二个paragraph移动到方格的下面,也就是跳脱出 float的影响,但是仍然保留第一个paragraph再方格的左边,我们可以这样写:

我们现在html中给 第二个 <p>元素加上一个clearclass属性,然后选中后令 clear的属性为both(这里是比较方便的做法,both包含了left和right,按道理说如果clear属性要和float属性保持一致)

1
2
3
4
5
6
7
8
9
10
11
.avatar {
width: 5rem;
height: 5rem;
background-color: gold;
float: left;
margin-right: 0.5rem;
}

.clear {
clear: both;
}

现在我们给article元素添加一个边框,然后删除第二个 <p>元素,我们惊喜地发现效果是这样的

现在边框之囊括了 article的子元素 p,但却并没有囊括子元素 div。这是因为 我们设置了 avatar为float element,默认情况下父元素是会忽略floated elements子元素的。因此这个div事实上并不在 article的作用范围之内。我们有好几种解决方法:

1 : 在 <p> 元素之后再加一个div,class属性设为clear

1
2
3
4
5
6
7
<body>
<article class="tweet">
<div class="avatar"></div>
<p>Lorem ipsum dolor sit amet.<p>
<div class = "clear"></div>
</article>
</body>

但这样只是单纯解决了问题,新添加的一行对搜索引擎的搜索工作是没有意义的

2:使用pseudo element

在css中新加上一段话,我们希望在tweet元素之后加上一个空白的content,但这个content默认是 inline的,因此我们还要设置其 display属性为 block, 最后将其clear属性设置为both。

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

也就是说我们利用css在html中加入了一个 div元素,但这样又不会污染我们的html语言,一举两得。

这种技巧是可以重复使用的,因此我们最好使用一个较为通用的 class名字,一般,这种class被叫做 clearfix,我们需要给article元素第二个class了

FlexBox

参考博客: http://caibaojian.com/flexbox-guide.html

FlexBox是 Flexible Box Layout 的缩写,中文叫弹性盒子 。旨在提供一个更加有效的方式来布置,对齐和分布在容器之间的各项内容,即使它们的大小是未知或者动态变化的。它比float更加好用。

我们的 HTML如下:

1
2
3
4
5
6
7
<body>
<div class="container">
<div class="box">A</div>
<div class="box">B</div>
<div class="box">C</div>
</div>
</body>
1
2
3
4
5
6
7
8
9
10
.container {
border: 3px solid lightgrey;
}

.box {
width: 5rem;
height: 5rem;
background: gold;
margin: 1rem;
}

direction

现在,我只要在 container中加一句 display: flex 就可以将三个框框由竖直排列转换为横向排列

有了flex,我们不用使用float,不用再定义margin种种。是一个很方便的工具。

我们可以使用flex-direction 属性来操控排列的方向,默认为row,还有column,column-reverse(C格子排在最上面)和 row-reverse(如下图:)

  • row:横向从左到右排列(左对齐),默认的排列方式。
  • row-reverse:反转横向排列(右对齐,从后往前排,最后一项排在最前面。
  • column:纵向排列。
  • column-reverse:反转纵向排列,从后往前排,最后一项排在最上面。

justify-content(作用于父类容器上)

justify-content属性可以设置或检索弹性盒子元素在主轴方向上的对齐方式。 其中主轴的方向和direction有关,如上图所示。当弹性盒里一行上的所有子元素都不能伸缩或已经达到其最大值时,这一属性可协助对多余的空间进行分配。当元素溢出某行时,这一属性同样会在对齐上进行控制。

这里,我们使用direction : row 的情况来举例

  • flex-start:弹性盒子元素将向行起始位置对齐。该行的第一个子元素的主起始位置的边界将与该行的主起始位置的边界对齐,同时所有后续的伸缩盒项目与其前一个项目对齐。

1
2
3
4
5
6
7
8
.container {
border: 3px solid lightgrey;
display: flex;
flex-direction: row;
justify-content: center;
align-items: stretch;
height: 90vh;
}
  • flex-end:弹性盒子元素将向行结束位置对齐。该行的第一个子元素的主结束位置的边界将与该行的主结束位置的边界对齐,同时所有后续的伸缩盒项目与其前一个项目对齐。

  • center:弹性盒子元素将向行中间位置对齐。该行的子元素将相互对齐并在行中居中对齐,同时第一个元素与行的主起始位置的边距等同与最后一个元素与行的主结束位置的边距(如果剩余空间是负数,则保持两端相等长度的溢出)。

  • space-between:弹性盒子元素会平均地分布在行里。如果最左边的剩余空间是负数,或该行只有一个子元素,则该值等效于’flex-start’。在其它情况下,第一个元素的边界与行的主起始位置的边界对齐,同时最后一个元素的边界与行的主结束位置的边距对齐,而剩余的伸缩盒项目则平均分布,并确保两两之间的空白空间相等。简单来说就是两端顶牢,中间均分

  • space-evenly: 均分,也就是元素与元素之间的距离和元素与边框的距离相等。

  • space-around:弹性盒子元素会平均地分布在行里,两端保留子元素与子元素之间间距大小的一半。如果最左边的剩余空间是负数,或该行只有一个伸缩盒项目,则该值等效于’center’。在其它情况下,伸缩盒项目则平均分布,并确保两两之间的空白空间相等,同时第一个元素前的空间以及最后一个元素后的空间其他空白空间的一半

align-items(作用于父类容器上)

设置或检索弹性盒子元素在侧轴 方向上的对齐方式。

  • flex-start:弹性盒子元素的侧轴(纵轴)起始位置的边界紧靠住该行的侧轴(纵轴)起始边界。

  • flex-end:弹性盒子元素的侧轴(纵轴)结束位置的边界紧靠住父容器的侧轴结束边界。

  • center:弹性盒子元素在该行的侧轴(纵轴)上居中放置。(如果该行的尺寸小于弹性盒子元素的尺寸,则会向两个方向溢出相同的长度)。

  • baseline:如弹性盒子元素的行内轴与侧轴为同一条,则该值与’flex-start’等效。其它情况下,该值将参与基线对齐。

  • stretch:如果指定侧轴大小的属性值为’auto’,则其值会使项目的边距盒的尺寸尽可能接近所在行的尺寸,但同时会遵照’min/max-width/height’属性的限制。

flex-wrap(作用于父类容器上)

  • nowrap:当子元素溢出父容器时不换行。如下图所示,如果子元素太多,浏览器就会自动对子元素产生形变,以让其能在一排中放置

  • wrap:当子元素溢出父容器时自动换行。不会对子元素产生形变

  • wrap-reverse:反转 wrap 排列。

align-content

向上面两张图,设置为wrap以后,虽然子元素分成了两行,但是他们的排版方式还是比较不协调,第一排离上边框比较近,第二排离下边框比较近,两排间隔比较远。这时候就要用到 align-content来设置或检索弹性盒堆叠伸缩行的对齐方式

  • flex-start:各行向弹性盒容器的起始位置堆叠。弹性盒容器中第一行的侧轴起始边界紧靠住该弹性盒容器的侧轴起始边界,之后的每一行都紧靠住前面一行。

  • flex-end:各行向弹性盒容器的结束位置堆叠。弹性盒容器中最后一行的侧轴起结束界紧靠住该弹性盒容器的侧轴结束边界,之后的每一行都紧靠住前面一行。

  • center:各行向弹性盒容器的中间位置堆叠。各行两两紧靠住同时在弹性盒容器中居中对齐,保持弹性盒容器的侧轴起始内容边界第一行之间的距离与该容器的侧轴结束内容边界最后一行之间的距离相等。(如果剩下的空间是负数,则各行会向两个方向溢出的相等距离。)

  • space-between:各行在弹性盒容器中平均分布。如果剩余的空间是负数或弹性盒容器中只有一行,该值等效于’flex-start’。在其它情况下,第一行的侧轴起始边界紧靠住弹性盒容器的侧轴起始内容边界最后一行的侧轴结束边界紧靠住弹性盒容器的侧轴结束内容边界,剩余的行则按一定方式在弹性盒窗口中排列,以保持两两之间的空间相等。

  • space-around:各行在弹性盒容器中平均分布,两端保留子元素与子元素之间间距大小的一半。如果剩余的空间是负数或弹性盒容器中只有一行,该值等效于’center’。在其它情况下,各行会按一定方式在弹性盒容器中排列,以保持两两之间的空间相等,同时第一行前面最后一行后面的空间是其他空间的一半

  • stretch:各行将会伸展以占用剩余的空间。如果剩余的空间是负数,该值等效于’flex-start’。在其它情况下,剩余空间被所有行平分,以扩大它们的侧轴尺寸。

align-self (适用于弹性盒模型子元素)

现在我们相对单一的盒子进行操作,我们就可以用align-self属性。

1
2
3
4
5
6
7
<body>
<div class="container">
<div class="box box-one">A</div>
<div class="box box-two">B</div>
<div class="box box-three">C</div>
</div>
</body>
  • auto:如果’align-self’的值为’auto’,则其计算值为元素的父元素的’align-items’值,如果其没有父元素,则计算值为’stretch’。

这里,我对子元素 boxA进行操作,其父元素 container的align-items为center,因此这里继承了下来

  • flex-start:弹性盒子元素的侧轴(纵轴)起始位置的边界紧靠住该行的侧轴起始边界。

  • flex-end:弹性盒子元素的侧轴(纵轴)起始位置的边界紧靠住该行的侧轴结束边界。

  • center:弹性盒子元素在该行的侧轴(纵轴)上居中放置。(如果该行的尺寸小于弹性盒子元素的尺寸,则会向两个方向溢出相同的长度)。

  • baseline:如弹性盒子元素的行内轴与侧轴为同一条,则该值与’flex-start’等效。其它情况下,该值将参与基线对齐。

  • stretch:如果指定侧轴大小的属性值为’auto’,则其值会使项目的边距盒的尺寸尽可能接近所在行的尺寸,但同时会遵照’min/max-width/height’属性的限制。

flex-basis (适用于弹性盒模型容器子元素)

1
flex-basis: <length> | auto (default auto)

这个属性设置或检索弹性盒伸缩基准值,默认为auto

  • auto:无特定宽度值,取决于其它属性值
  • <length>:用长度值来定义宽度。不允许负值

  • <percentage>:用百分比来定义宽度。不允许负值

比如说当我设置 flex-basis: 10rem; 的时候,效果如下图所示

作用于宽度的前提是 direction 的值为row,如果direction的值为columns,那么flex-basis就作用域高度上了

flex-grow (适用于弹性盒模型容器子元素)

设置或检索弹性盒的扩展比率。 根据弹性盒子元素所设置的扩展因子作为比率来分配剩余空间

1
flex-grow: <number> (default 0)
  • <number>:用数值来定义扩展比率。不允许负值
  • flex-grow的默认值为0,如果没有显示定义该属性,是不会拥有分配剩余空间权利的。

比如说这里有3个boxes,box1的flex-grow = 2,box2、3的flex-grow为1

那么,整一个行的空间就会被均匀分成4份,两份给box1,box2和box3分别得到1份。

flex-shrink

根据弹性盒子元素所设置的收缩因子作为比率来收缩空间。

flex

flex就是上面三个属性 flex-grow,flex-shrink,flex-basis三者的集合

1
flex:none | [ flex-grow ] || [ flex-shrink ] || [ flex-basis ]
  • none:none关键字的计算值为: 0 0 auto
  • [ flex-grow ]:定义弹性盒子元素的扩展比率。
  • [ flex-shrink ]:定义弹性盒子元素的收缩比率。
  • [ flex-basis ]:定义弹性盒子元素的默认基准值。

Grid

参考博客: http://www.ruanyifeng.com/blog/2019/03/grid-layout-tutorial.html

Flex 布局是轴线布局,只能指定”项目”针对轴线的位置,可以看作是一维布局。Grid 布局则是将容器划分成”行”和”列”,产生单元格,然后指定”项目所在”的单元格,可以看作是二维布局。Grid 布局远比 Flex 布局强大。

一个网格常用的场景就是图片展示:

容器属性(父元素)

那么,grid类型的布局需要有哪些结构组成呢?我们可以这样来定义:

  • display:grid
  • grid-template-rows
  • grid-template-columns
grid-template-rows/columns

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

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

这里,我们就制作了一个3行2列的网格。

上面我们使用了绝对单位,事实上我们也可以使用相对单位 %,vh,vw之类的

当然还有一个属性是 grid-template, 可以这样写:

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

repeat()函数

有时候,我们重复写同样的值非常繁琐。这时候就可以使用 repeat()函数,简化重复的值.

repeat()接受两个参数,第一个参数是重复的次数,第二个参数是所要重复的值。

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

repeat()重复某种模式也是可以的。

1
grid-template-columns: repeat(2, 100px 20px 80px);

上面代码定义了6列,第一列和第四列的宽度为100px,第二列和第五列为20px,第三列和第六列为80px

fr()

为了方便表示比例关系,网格布局提供了fr关键字(fraction 的缩写,意为”片段”)。如果两列的宽度分别为1fr2fr,就表示后者是前者的两倍。

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

fr可以与绝对长度的单位结合使用,这时会比 %更加方便。因为 %是相对于整个 container而言的,而fr是相对于除去绝对长度后,剩余的空间而言的,因而不会发生溢出等现象

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

这里,第一列宽度为100px,第三列是第二列宽度的两倍。

auto关键词

auto关键字表示由浏览器自己决定长度。

1
grid-template-columns: 100px auto 100px;

上面代码中,第二列的宽度,基本上等于该列单元格的最大宽度,除非单元格内容设置了min-width,且这个值大于最大宽度。这样当浏览器窗口变化的时候,第一列和第三列都不会发生变化,但是第二列的宽度会随之变化。

justify-items align-items属性

justify-items属性设置单元格内容的水平位置(左中右),align-items属性设置单元格内容的垂直位置(上中下),都作用于父元素上和flexbox中有点类似

1
2
3
4
.container {
justify-items: start | end | center | stretch;
align-items: start | end | center | stretch;
}
  • start:对齐单元格的起始边缘。

二者都取 start的时候,效果如图:

  • end:对齐单元格的结束边缘。

二者取end时:

  • center:单元格内部居中。

  • stretch:拉伸,占满单元格的整个宽度(默认值)。

还有 place-items 属性,是二者的合并简写模式:

1
place-items: <align-items> <justify-items>;
justify-content align-content 属性

justify-content属性是整个内容区域在容器里面的水平位置(左中右)

align-content属性是整个内容区域的垂直位置(上中下)。

  • start 对齐容器的起始边框。

  • end 对齐容器的结束边框。

  • center 容器内部居中。

  • stretch 项目大小没有指定时(未设置长宽),拉伸占据整个网格容器。
  • space-around 每个项目两侧的间隔相等。所以,项目之间的间隔比项目与容器边框的间隔大一倍。

  • space-between 项目与项目的间隔相等,项目与容器边框之间没有间隔。

  • space-evenly项目与项目的间隔相等,项目与容器边框之间也是同样长度的间隔。

place-content属性则是align-content属性和justify-content属性的合并简写形式。

row-gap column-gap属性

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

1
2
3
4
5
6
.container {
display: grid;
grid-template: 100px auto 100px/30fr 70fr;
row-gap: 10px;
column-gap: 10px;
}

中间深颜色的区域就是各个grid之间的gap间隙。

gap属性是grid-column-gapgrid-row-gap的合并简写形式,语法如下。

1
gap: <row-gap> <column-gap>;

当然如果我们省略了第二个值,浏览器会默认第二个值等于第一个值

项目属性(子元素)

grid-column grid-row

grid-column属性是grid-column-startgrid-column-end的合并简写形式,grid-row属性是grid-row-start属性和grid-row-end的合并简写形式。

首先我们看dev-tool中的网格线。正常情况下,n行有n + 1根水平网格线,m列有m + 1根垂直网格线,比如三行就有四根水平网格线。

那么grid-columngrid-row中的两个值就代表了起始网格线和结束网格线。

1
2
3
4
.box-one {
grid-column: <start-line> / <end-line>;
grid-row: <start-line> / <end-line>;
}
1
2
3
4
5
6
7
8
9
10
11
.box-one {
grid-column: 1 / 3;
grid-row: 1 / 2;
}
/* 等同于 */
.box-one{
grid-column-start: 1;
grid-column-end: 3;
grid-row-start: 1;
grid-row-end: 2;
}

当然,也可以取负值, -1就代表最后一行,-2代表倒数第二行以此类推

1
2
3
.box-one{
grid-column: 1 / -1;
}

这两个属性之中,也可以使用span关键字,表示跨越多少个网格。

1
2
3
4
5
6
7
8
9
.box-one{
grid-column: 1 / 3;
grid-row: 1 / 3;
}
/* 等同于 */
.box-one {
grid-column: 1 / span 2;
grid-row: 1 / span 2;
}

grid-row 确定了这个子元素可以处于网格中的第几行

最后,斜杠以及后面的部分可以省略,默认跨越一个网格。

1
2
3
4
.box-one {
grid-column: 1;
grid-row: 1;
}
grid-area grid-template-areas

grid-area 属性指定项目放在哪一个区域。

但首先我们需要定义这些区域,这就需要用到 grid-template-areas这个属性了,这个属性作用于父元素,因此我们在container中定义

因为我们总共定义了一个3行2列的网格,因此在写 grid-template-areas的时候也要写3X2的样式。如下图所示。如果两个单元格的名字相同,那么当我们分配时就会自动将其连在一起。

1
2
3
4
5
6
7
8
9
10
11
12
.container {
display: grid;
grid-template: 100px auto 100px/30fr 70fr;
row-gap: 10px;
column-gap: 10px;
border: 3px solid lightgrey;
height: 90vh;
grid-template-areas:
"header header"
"sidebar main"
"footer footer" ;
}

上面代码中,顶部是页眉区域header,底部是页脚区域footer,中间部分则为mainsidebar

现在我们为格子A和D分配区域

1
2
3
4
5
6
.box-one {
grid-area: header;
}
.box-four {
grid-area: footer;
}

效果如下图所示:

如果某些区域不需要利用,则使用”点”(.)表示。

1
2
3
4
grid-template-areas: 
"header header"
"sidebar main"
". footer" ;

grid-area属性还可用作grid-row-startgrid-column-startgrid-row-endgrid-column-end的合并简写形式,直接指定项目的位置。

1
2
3
.item {
grid-area: <row-start> / <column-start> / <row-end> / <column-end>;
}

比如说我定义 grid-area: 2/2/3/3,那么A元素就会到第二行二列的那个格子去了

1
2
3
.box-one{
grid-area: 2/2/3/3
}

justify-self align-self

justify-self属性设置单元格内容的水平位置(左中右),跟justify-items属性的用法完全一致,但只作用于单个项目。

align-self属性设置单元格内容的垂直位置(上中下),跟align-items属性的用法完全一致,也是只作用于单个项目。

用法也一样,都是四种取值

1
2
3
4
.item {
justify-self: start | end | center | stretch;
align-self: start | end | center | stretch;
}

Hiding Elements

1
2
3
4
<body>
<div class = "box first">Box1</div>
<div class = "box">Box2</div>
</body>

现在我们有这样一个html文件,我想隐藏 第一个 <div>元素,怎么办?有两种方法,但二者有点区别

第一种是使用display属性

1
2
3
.first{
display: none;
}

这样写的结果就是第一个<div>元素所占的位置都会被隐藏,因此现在Second在第一排上。

第二种是设置visibility属性,将其设置为 hidden,与visible相对。虽然Box1看不见,但是其所在的div元素仍然保留着

1
2
3
.first {
visibility: hidden;
}

Media Queries

最后我们来讲Media Queries,这能让我们的HTML网页在不同的设备上显示不同的样式

首先我们要决定是以电脑页面优先还是移动设备页面优先,不同的项目有着不同的需求。一般来说,很多人喜欢先开发移动设备优先。因为如果线开发电脑页面,再移植到移动设备上需要调整很多很多东西

拿一个很小的例子来说,我们希望两块文字,在手机这类宽度比较窄的屏幕上显示为竖直排列,而在电脑,平板这类比较宽的屏幕上为水平排列。那么我们就需要设置一个 breakpoint,也就是说当宽度大于这个breakpoint的时候,div元素的排列会从原来的竖直排列转换为水平排列。

那么用CSS怎么实现这一点?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
.container {
display: flex;
flex-direction: column;
}
.box {
background: gold;
padding: 1rem;
}
.box:nth-of-type(2) {
background: dodgerblue;
}

@media screen and (min-width: 768px) {
.container {
display: flex;
flex-direction: row;
}
.box {
background: white;
}
}

在这里,我们使用 @media screen,and后面加上限定条件,需要用小括号,括号中使用min-width属性。 也就是说在花括号中写上当宽度大于min-width时的css样式。浏览器会自动检测,并在符合条件的时候将花括号中的CSS覆盖之前写的CSS。

效果:

参考标准如下:

我们还可以一直and+新的条件 ,下面意思是说当screen的大小在 768和 1000之间的时候,采用这段css

1
2
3
4
5
6
@media screen and (min-width: 768px) and (max-width: 1000px) {
.container {
display: flex;
flex-direction: row;
}
}

此外,我们还可以对打印机进行设置。因为显示器(screen)和打印机(printer)是两种差别很大的设备,所以从浏览器里看到的页面,打印出来也许和你看到的样子有很大的差距。

screen一般使用逻辑单位比如px,而打印机则应该使用物理单位比如cm或in。我们常见的A4纸张大小在不同DPI的显示器上显示的大小是不同的。因此如果要精确的控制打印效果就应该使用print
css,这是跨平台兼容的标准。

举例如下:

1
2
3
4
5
6
7
8
@media print{
body {
font-size:12pt;
}
.box{
padding: 0.5cm;
}
}

Summary

CheatSheet

Exercise

提示与要求

html文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./css/normalize.css" />
<link rel="stylesheet" href="./css/navbar.css" />

<title>Document</title>
</head>
<body>

<nav class="nav">
<ul> <li><a href="1">About</a></li>
<li><a href="2">Courses</a></li>
<li><a href="3">Forum</a></li>
<li><a href="4">Learning Paths</a></li>
<li><a href="5">Contact</a></li>
</ul>
</nav>
</body>
</html>

css如下:

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
34
35
36
37
38
39
40
41
html {
font-size: 62.5%;
}

body {
font-family: Arial, Helvetica, sans-serif;
font-size: 1.6rem;
}

nav {
background: #000;
padding: .7rem;
color: white;
}

nav ul {
display: flex;
flex-direction: column;
padding-left: 0;
text-align: center;
list-style-type: none;/*把列表的标识符(点)去掉*/
}

nav li {
margin: .5rem;
}

nav a{
color: white;
text-decoration: none;
}

@media screen and (min-width: 768px) {
nav ul {
flex-direction: row; /*当宽大于768px,排布变为横状*/
justify-content: flex-end;
}
nav li {
margin: 0 1rem;
}
}

效果图:

Html:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Photo Gallery</title>
<link rel="stylesheet" href="css/normalize.css" />
<link rel="stylesheet" href="css/styles.css" />
</head>
<body>
<div class="gallery">
<img src="https://source.unsplash.com/collection/190727/800x600?1" />
<img src="https://source.unsplash.com/collection/190727/800x600?2" />
<img src="https://source.unsplash.com/collection/190727/800x600?3" />
<img src="https://source.unsplash.com/collection/190727/800x600?4" />
<img src="https://source.unsplash.com/collection/190727/800x600?5" />
<img src="https://source.unsplash.com/collection/190727/800x600?6" />
<img src="https://source.unsplash.com/collection/190727/800x600?7" />
<img src="https://source.unsplash.com/collection/190727/800x600?8" />
<img src="https://source.unsplash.com/collection/190727/800x600?9" />
</div>
</body>
</html>

对于这题,我一开始想的思路是在最窄的时候使用flex,其余的时候用的是grid,其实没必要。都用grid就可以。此外,在div中可以直接引入<img> ,而一开始我想的是在<div>中填入<img>。所以css可以写的很简单:

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
.gallery {
display: grid;
grid-gap: 10px;
}

.gallery img {
object-fit: cover; /* 对图片进行剪切,保留原始比例 */
width: 100%; /* 宽度始终填满 */
border-radius: 5px;
}

@media screen and (min-width: 768px) {
.gallery {
grid-template-columns: repeat(2, 1fr); /* 两列,每列占一半*/
}
}

@media screen and (min-width: 1024px) {
.gallery {
grid-template-columns: repeat(3, 1fr); /* 三列 */
}
.gallery img:nth-of-type(3) {/*采用nth-child方法选择第三个img*/
grid-column: 2 / 4;
grid-row: 1 / 3;
}
}
-------------本文结束,感谢您的阅读-------------