css整理

30 阅读1小时+

如何理解HTML语义化

让人更容易读懂(增加代码可读性)

让搜索引擎更容易读懂 (SEO )

语义化是指根据内容的结构化(内容语义化),选择合适的标签(代码语义化)。通俗来讲就是用正确的标签做正确的事情。

语义化的优点如下:

  • 对机器友好,带有语义的文字表现力丰富,更适合搜索引擎的爬虫爬取有效信息,有利于SEO。除此之外,语义类还支持读屏软件,根据文章可以自动生成目录;
  • 对开发者友好,使用语义类标签增强了可读性,结构更加清晰,开发者能清晰的看出网页的结构,便于团队的开发与维护。
<header></header>  头部

<nav></nav>  导航栏

<section></section>  区块(有语义化的div)

<main></main>  主要区域

<article></article>  主要内容

<aside></aside>  侧边栏

<footer></footer>  底部

对盒⼦模型的理解

当对⼀个⽂档进⾏布局(layout)的时候,浏览器的渲染引擎会根据 CSS 盒模型

(CSS basic box model),将所有元素表示为⼀个个矩形的盒⼦(box)

⼀个盒⼦由四个部分组成: contentpaddingbordermargin

content ,即实际内容,显示⽂本和图像

boreder ,即边框,围绕元素内容的内边距的⼀条或多条线,由粗细、样式、颜⾊三部分组成

padding ,即内边距,清除内容周围的区域,内边距是透明的,取值不能为负,受盒⼦的 backgrou

nd 属性影响

margin ,即外边距,在元素外创建额外的空⽩,空⽩通常指不能放其他元素的区域

css隐藏元素的方法

overflow:hidden

opacity:0:设置透明度,但仍然占据位置,事件可响应

visibility:hidden:占据位置,但不响应事件

display:none:不占据位置

position:absolute

clip(clip-path):rect()/inset()/polygon()

z-index:-1000

transform:scaleY(0):占据位置,不响应事件

标准盒模型与怪异盒模型

对于标准盒模型,widthheight 指的是内容区域的宽度和高度。增加内边距、边框和外边距不会影响内容区域的尺寸,但是会增加元素框的总尺寸。

对于IE盒模型(怪异盒模型),widthheight 指的是内容区域+border+padding的宽度和高度。元素内容的宽度和高度是由已设定的宽度和高度分别减去边框和内边距后得到的。

下列box是一个怪异盒模型,可以看出,其content只有70px,加上padding和border才等于width: 100px

.box {
  height: 100px;
  width: 100px;
  margin: 10px;
  padding: 10px;
  border: 5px solid black;
  background-color: pink;
  box-sizing: border-box;
}

现代浏览器默认使用W3C的标准盒模型,但是在不少情况下怪异盒模型更好用,于是W3C在css3中加入box-sizing:

box-sizing: content-box // 标准盒模型

box-sizing: border-box // 怪异盒模型

一句话总结就是:

标准盒模型的大小就是content的大小,而ie盒模型的大小则是content+padding+border总的大小。

块级元素、行内元素、行内块元素区别

1. 块级元素 block

块级元素,顾名思义,该元素呈现“块”状,所以它有自己的宽度和高度,也就是可自定义 width 和 height。除此之外,块级元素比较霸道,它独自占据一行高度(float浮动除外),一般可以作为其他容器使用,可容纳块级元素和行内元素。

块级元素有以下特点:

  • 每个块级元素都是独自占一行
  • 高度,行高,外边距(margin)以及内边距(padding)都可以控制;
  • 元素的宽度如果不设置的话,默认为父元素的宽度(父元素宽度100%;
  • 多个块状元素标签写在一起,默认排列方式为从上至下;
<address>  // 定义地址 
 <caption>  // 定义表格标题 
 <dd>      // 定义列表中定义条目 
 <div>     // 定义文档中的分区或节 
 <dl>    // 定义列表 
 <dt>     // 定义列表中的项目 
 <fieldset>  // 定义一个框架集 
 <form>  // 创建 HTML 表单 
 <h1>    // 定义最大的标题
 <h2>    // 定义副标题
 <h3>     // 定义标题
 <h4>     // 定义标题
 <h5>     // 定义标题
 <h6>     // 定义最小的标题
 <hr>     // 创建一条水平线
 <legend>    // 元素为 fieldset 元素定义标题
 <li>     // 标签定义列表项目
 <noframes>    // 为那些不支持框架的浏览器显示文本,于 frameset 元素内部
 <noscript>    // 定义在脚本未被执行时的替代内容
 <ol>     // 定义有序列表
 <ul>    // 定义无序列表
 <p>     // 标签定义段落
 <pre>     // 定义预格式化的文本
 <table>     // 标签定义 HTML 表格
 <tbody>     // 标签表格主体(正文)
 <td>    // 表格中的标准单元格
 <tfoot>     // 定义表格的页脚(脚注或表注)
 <th>    // 定义表头单元格
 <thead>    // 标签定义表格的表头
 <tr>     // 定义表格中的行
2. 行内元素 inline

行内元素不可以设置宽(width)和高(height),但可以与其他行内元素位于同一行,行内元素内一般不可以包含块级元素。行内元素的高度一般由元素内部的字体大小决定,宽度由内容的长度控制。 行内元素有以下特点:

  • 不会独占一行,相邻的行内元素会排列在同一行里,直到一行排不下才会自动换行,其宽度随元素的内容而变化;
  • 高宽无效,对外边距(margin)和内边距(padding)仅设置左右方向有效 上下无效;
  • 设置行高有效,等同于给父级元素设置行高;
  • 元素的宽度就是它包含的文字或图片的宽度,不可改变;
  • 行内元素中不能放块级元素,a 链接里面不能再放链接;
<a>     // 标签可定义锚 
 <abbr>     // 表示一个缩写形式 
 <acronym>     // 定义只取首字母缩写 
 <b>     // 字体加粗 
 <bdo>     // 可覆盖默认的文本方向 
 <big>     // 大号字体加粗 
 <br>     // 换行 
 <cite>     // 引用进行定义 
 <code>    // 定义计算机代码文本
 <dfn>     // 定义一个定义项目
 <em>     // 定义为强调的内容
 <i>     // 斜体文本效果
 <kbd>     // 定义键盘文本
 <label>     // 标签为 input 元素定义标注(标记)
 <q>     // 定义短的引用
 <samp>     // 定义样本文本
 <select> // 创建单选或多选菜单
 <small>     // 呈现小号字体效果
 <span>     // 组合文档中的行内元素
 <strong> // 加粗
 <sub>     // 定义下标文本
 <sup>     // 定义上标文本
 <textarea>     // 多行的文本输入控件
 <tt>     // 打字机或者等宽的文本效果
 <var>    // 定义变量
3. 行内块级元素 inline-block

行内块级元素,它既具有块级元素的特点,也有行内元素的特点,它可以自由设置元素宽度和高度,也可以在一行中放置多个行内块级元素。比如:input、img就是行内块级元素,它可设置高宽以及一行多个。 具体特点如下:

  • 高度、行高、外边距以及内边距都可以控制;
  • 默认宽度就是它本身内容的宽度,不独占一行,但是之间会有空白缝隙,设置它上一级的 font-size 为 0,才会消除间隙;
<button> 
<input>   
<textarea> 
<select> 
<img>
4. 元素类型转换 display

display:block ,定义元素为块级元素

display : inline ,定义元素为行内元素

display:inline-block,定义元素为行内块级元素

5. 总结

不管块级元素还是行内元素,区别:一是排列方式,二是宽高边距设置,三是默认宽度。

  • 块级元素会独占一行,而内联元素和内联块元素则会在一行内显示;
  • 块级元素和内联块元素可设置 width、height 属性,而内联元素设置无效;
  • 块级元素的 width 默认为 100%,而内联元素则是根据其自身的内容或子元素来决定其宽度;

而行内块级元素又同时拥有块级元素和行内元素的特点。

display属性值及其作用

display属性用于控制HTML元素的显示方式,它有多个取值。以下是常见的几种display属性取值及其作用:

  • block:将元素显示为块级元素,即占据整个父容器的宽度,可以设置宽度、高度、边距和填充等属性。默认情况下,HTML的大多数元素(如div、h1、p)都是块级元素。
  • inline:将元素显示为行内元素,即只占据必要的宽度,不可以设置宽度、高度和上下边距,但可以设置左右边距和填充等属性。默认情况下,HTML的一些元素(如a、span、img)都是行内元素。
  • inline-block:将元素显示为行内块级元素,即占据必要的宽度,同时可以设置宽度、高度、边距和填充等属性。行内块级元素可以像行内元素一样放置在一行内,但是可以像块级元素一样设置宽度和高度等属性。
  • none:元素不被显示,可以在DOM树中存在,但是不占据任何空间。通常用于JavaScript操作元素时,临时隐藏某个元素。
  • flex:将元素显示为弹性容器,用于设置子元素的排列方式,可以设置主轴方向、子元素对齐方式、空白间隔等属性。flex布局目前被广泛应用于响应式网页设计中。
  • grid:将元素显示为网格容器,用于设置子元素的排列方式,可以设置行列数、网格大小、子元素位置等属性。grid布局是最新的CSS布局方式,支持复杂的网格排列,可以方便地实现多列布局和响应式设计。

还有其他一些display属性的取值,如table、table-cell、table-row等,它们用于控制元素的表格布局。不同的display属性取值对应不同的元素布局方式,开发者可以根据需要选择最合适的display属性取值,实现理想的网页布局效果。

CSS选择器权重计算

CSS权重的计算分为四个等级a,b,c,d;

权重计算这个东西不麻烦,就是分 4 类:

  1. inlineStyle: 行内样式
  2. #ID: ID选择器
  3. .Class: 类,属性和伪类选择器
  4. Element: 标签和伪元素选择器

其中行内样式中定义的声明属于a级,id选择器属于b级,属性选择器、class类选择器和伪类选择器属于c级,标签选择器属于d级;

四级当中a级权重值最高,d级权重值最低。权重值根据每个级别出现的数量进行计数,每个等级出现1次,就计数1次。

注意事项:

  • !important声明的样式的优先级最高;
  • 如果优先级相同,则最后出现的样式生效;
  • 继承得到的样式的优先级最低;
  • 通用选择器(*)、子选择器(>)和相邻同胞选择器(+)并不在这四个等级中,所以它们的权值都为 0 ;
  • 样式表的来源不同时,优先级顺序为:内联样式 > 内部样式 > 外部样式 > 浏览器用户自定义样式 > 浏览器默认样式。

计算出具体的权重后就可以进行比较:当两个权值进行比较的时候,是从A到D逐级将等级位上的权重值(如 权值 1,0,0,0 对应--> A,B,C,D)来进行比较的,如果相同等级下的值PK出结果,就不会进行后面的比较了。如果相同等级的数字相同,则继续比较下级的数字大小。低等级的选择器,个数再多也不会越等级超过高等级的选择器的优先级的;

其中有些选择器是不参与优先级的计算,其中包括:通用选择器『*』号,,组合选择器中的子类选择器、相邻兄弟选择器、普通兄弟选择器。包含!important的CSS声明是特殊的存在,不参与权重值的计算,比a,b,c,d四个等级都高;在同时都包含!important时,又会根据选择器的匹配规则计算权重值。谁的权重值高,应用谁的样式。

选择器格式优先级权重
id选择器#id100
类选择器#classname10
属性选择器a[ref=“eee”]10
伪类选择器li:last-child10
标签选择器div1
伪元素选择器li:after1
相邻兄弟选择器h1+p0
子选择器ul>li0
后代选择器li a0
通配符选择器*0

推荐一个权重计算图

W3C 最新版的 选择器文档 中,行内样式已经从权重中移出了,权重变成了三类 [#ID, .Class, Element]

CSS中可继承与不可继承属性有哪些

可继承属性:
1.字体系列属性
font:组合字体
font-family:规定元素的字体系列
font-weight:设置字体的粗细
font-size:设置字体的尺寸
font-style:定义字体的风格
font-variant:偏大或偏小的字体
2.文本系列属性
text-indent:文本缩进
text-align:文本水平对刘
line-height:行高
word-spacing:增加或减少单词间的空白
letter-spacing:增加或减少字符间的空白
text-transform:控制文本大小写
direction:规定文本的书写方向
color:文本颜色
3.元素可见性
visibility
4.表格布局属性
caption-side定位表格标题位置
border-collapse合并表格边框
border-spacing设置相邻单元格的边框间的距离
empty-cells单元格的边框的出现与消失
table-layout表格的宽度由什么决定<automatic.fixed.inherit>
5.列表布局属性
list-style-type文字前面的小点点样式
list-style-position小点点位置
list-style以上的属性可通过这属性集合
6.引用
quotes设置嵌套引用的引号类型
7.光标属性
cursor:箭头可以变成需要的形状

不可继承属性
1.display
2.文本属性
vertical-align:垂直文本对齐
text-decoration:规定添加到文本的装饰
text-shadow:文本阴影效果
white-space:空白符的处理
3.盒子模型属性
width、height、margin 、margin-top、margin-right、margin-bottom、margin-left、border、border-style、border-top-style、border-right-style、border-bottom-style、border-left-style、border-width、border-top-width、border-right-right、border-bottom-width、border-left-width、border-color、border-top-color、border-right-color、border-bottom-color、border-left-color、border-top、border-right、border-bottom、border-left、padding、padding-top、padding-right、padding-bottom、padding-left
4.背景属性
background、background-color、background-image、background-repeat、background-position、background-attachment
5.定位属性
float、clear、position、top、right、bottom、left、min-width、min-height、max-width、max-height、overflow、clip、z-index

常见的CSS定位布局

segmentfault.com/a/119000004…

默认文档流

默认文档流,指的是就是元素排版布局过程中,元素会自动从左往右,从上往下地遵守这种流式排列方式,其中每一个块元素都独占一行,行内元素则在一行之内从左到右排列,直到在当前行遇到了边界后,换到下一行的起点起点继续排列。

脱离文档流,即将元素从普通的布局排版(普通文档流)中脱离出来,其他盒子在定位的时候,会当做没看到它,两者位置重叠都是可以的,但是依然在DOM树中存在。

定位实现

我们可以通过设置css中position属性的值来设定元素的定位类型。position的值分为以下几种:

  • static 默认(非定位元素)
  • inherit 从父元素继承 position 属性的值
  • relative 相对(定位元素)
  • absolute 绝对(定位元素)
  • fixed 固定(定位元素)
  • sticky 粘滞(定位元素)

定位元素的特点: 可以使用定位规则。通过top、right、bottom、left来设置偏移量。绝对定位和固定定位的块元素和行内元素会自动转化为行内块元素

1.相对布局 position: relative;

  • 不脱离文档流。
  • 相对于它原来的位置移动。

案例: 想要达到下图的偏移效果,该如何实现呢?

从代码看出,只要在紫色div的样式属性设置了 position:relative; 之后,就可以使用left和 top设置与原来文档布局位置的偏移量。


实现代码如下:

<!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">
    <title>Document</title>
    <style>
      .box {
        width: 500px;
        height: 500px;
        border: 2px solid black;
      }
      .box > div {
        width: 200px;
        height: 100px;
      }
      .one {
        background-color: blueviolet;

        position:relative;
        left: 50px;
        top: 50px;
      }
      .two {
        background-color: cyan;
      }
    </style>
  </head>
  <body>
    <div class="box">
      <div class="one"></div>
      <div class="two"></div>
    </div>
  </body>
</html>

2.绝对布局 position: absolute;

  • 脱离文档流
  • 相对于该元素的父类(及以上,如果直系父类元素不满足条件则继续向上查询)元素进行定位的,并且这个父类元素的position必须是非static定位的(static是默认定位方式),如果没有则以body为参照。(一般情况下,绝对定位元素都是嵌套在相对定位元素内容来使用)

案例: 我们将上述代码中的设置相对定位的代码改成绝对定位看看。

当设置紫色的div为绝对定位之后,发现蓝色的div不见了。
其实,蓝色的div并不是不见了,而是跟紫色的div重叠了。因为当紫色div被设置为绝对定位之后,就会脱离文档流布局,此时它就相当于漂浮了起来,而蓝色div的因为没有了紫色div的挤压,自然就上去与紫色div重叠在一起了。
接下来,让我们为紫色的div设置偏移量。

此时,我们发现紫色的div出现在了父元素外面,页面的左上角。这是因为它的父元素中没有定位元素,所以它的偏移量是相对于body来进行调整的。
接下来,我们将其父元素设置为相对定位,看看会发生什么?

这个时候我们看到紫色的div回到了它父元素中。

3.固定布局 position: fixed;

  • 脱离文档流。
  • 相对于浏览器窗口进行定位,相当于就是把这个元素钉在了浏览器窗口上了,无论我们怎么操作滚动条都无法改变他的位置。

我们继续使用上面的代码,将紫色div中的绝对布局改成固定布局,并将其父元素的高度变大。

从上述GIF中,我们可以看出无论我们怎么操作滚动条,紫色div都在整个浏览器页面的固定位置。

这种定位方式最适合用于放置广告。

4.粘滞布局 position: sticky;

  • 在没有达到阈值的时候是不脱离文档流(相对),达到阈值脱离文档流(固定),可以通过left、top、right、bottom来设定阈值。

了解了上述几种布局后,我们再来看看什么是粘滞布局。将一个定位元素设置为粘滞布局后,当我们没有到达设定的阈值后,它就像正常的文档流一样,显示在该出现的位置,一旦我们到达它设置的阈值后,他就会一直停留在我们设定好的位置上。效果图如下:


css代码如下:

.two {
        width: 100%;
        height: 100px;
        background-color: lightcoral;
        position: sticky;/* 设置为粘滞定位 */
        top: 0; /* 当该元素到达整个页面距离顶端0px的时候,他会一直停留在此位置 */
    }

定位元素层级 z-index
定位元素是浮动于正常的文档流上面的,我们可以通过z-index属性来设置元素的层级。
在哪些场景里我们会用到z-index这个属性呢?比如说,当我们做一个供用户输入登录信息的弹框时,我们希望当用户点击登录后,弹出的框不会被其他任何元素覆盖时,我们可以通过设置它的z-index属性,将其层级设置为最高即可。

下面这个案例将会帮助我们学习和理解z-index属性。

代码如下:

<!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">
    <title>Document</title>
    <style>
        .box {
            width: 400px;
            height: 600px;
            margin: 50px auto;
            border: 2px solid black;
            position: relative;
        }
        .box > div {
            width: 100px;
            height: 100px;
            position: absolute;
        }
        .one {
            background-color: red;
            top: 20px;
            left: 20px;
        }
        .two {
            background-color: orange;
            top: 40px;
            left: 40px;
        }
        .three {
            background-color: yellow;
            top: 60px;
            left: 60px;
        }
        .four {
            background-color: green;
            top: 80px;
            left: 80px;
        }
        .five {
            background-color: cyan;
            top: 100px;
            left: 100px;
        }
        .six {
            background-color: blue;
            top: 120px;
            left: 120px;
        }
        .seven {
            background-color: violet;
            top: 140px;
            left: 140px;
        }
    </style>
</head>
<body>
    <div class="box">
        <div class="one"></div>
        <div class="two"></div>
        <div class="three"></div>
        <div class="four"></div>
        <div class="five"></div>
        <div class="six"></div>
        <div class="seven"></div>
    </div>
</body>
</html>

我们可以看到从顶到底依次是:紫、蓝、青、绿、黄、橙、赤。
如果我们想要从顶到底依次是:赤、橙、黄、绿、青、蓝、紫的话,只需要在每个div中设置z-index属性,就可以轻松实现。如下图所示:

部分CSS代码如下:

.one {
    background-color: red;
    top: 20px;
    left: 20px;
    z-index: 7;
}
.two {
    background-color: orange;
    top: 40px;
    left: 40px;
    z-index: 6;
}
.three {
    background-color: yellow;
    top: 60px;
    left: 60px;
    z-index: 5;
}
.four {
    background-color: green;
    top: 80px;
    left: 80px;
    z-index: 4;
}
.five {
    background-color: cyan;
    top: 100px;
    left: 100px;
    z-index: 3;
}
.six {
    background-color: blue;
    top: 120px;
    left: 120px;
    z-index: 2;
}
.seven {
    background-color: violet;
    top: 140px;
    left: 140px;
    z-index: 1;
}

margin取负值会怎样

item1设置margin-top: -20px

item3设置margin-left: -20px;

item1设置margin-bottom: -20px

item3设置margin-right: -20px;

讲一下BFC

BFC是一块独立渲染区域,内部元素的渲染不会影响边界以外的元素。为一个元素创建BFC,可以包含内部浮动。排除外部浮动,阻止外边距重叠。

理解BFC

理解BFC(块级格式化上下文)之前,先看一下FC(格式化上下文)是什么意思:

格式化上下文是决定盒子之间如何布局的环境,不同的格式化上下文如何布局盒子由自身的规则来决定。正常文档流下,盒模型归属到格式化上下文。块级盒子参加块级格式化上下文

BFC块格式化上下文 是块盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域。因此BFC是一块独立渲染区域,内部元素的渲染不会影响边界以外的元素

理解BFC的本质:为一个元素创建BFC,可以包含内部浮动。排除外部浮动,阻止外边距重叠

BFC规则

内部盒子会在垂直方向排列

在同一个BFC中,垂直方向上,相邻两个盒子的margin会重叠,值取两者中较大的

BFC就是页面上的一个隔离的独立容器,里外互相不受影响

计算BFC元素的高度时,考虑BFC所包含的所有子元素,连浮动元素也要参与计算。

当元素不是BFC的子元素时,浮动元素高度不参与BFC计算(常见的盒子塌陷问题)

在一个BFC中,每个元素的左边缘都会紧贴着包含块的左边缘

BFC的区域不会与float box重叠。

BFC触发条件

  • 根元素html
  • 浮动元素(float不为none的元素)
  • 绝对定位元素(position为absolute或fixed)
  • overflow不为visible或clip的块级元素
  • 行内块元素(display为inline-block), 表格单元格(display为table-cell)
  • display值为table-caption, flex, inline-flex
  • display 值为 flow-root 的元素

使用 overflow: auto; 触发 BFC 的方法缺点在于不够直观,其次可能产生不必要的滚动条或剪切阴影等副作用。

因此mdn指出,使用 display: flow-root (或 display: flow-root list-item)将创建一个新的 BFC,而不会产生任何其他潜在的问题副作用。flow-root 关键字的意义是,创建的内容本质上类似于一个新的根元素(如 所做),并确定这个新的上下文如何创建及其流布局如何实现。

BFC应用1: 解决margin重叠

<head>
  <meta charset="UTF-8">
  <style>
    .box1 {
      width: 100px;
      height: 100px;
      background-color: green;
      margin-bottom: 30px;
    }
    .box2 {
      width: 200px;
      height: 100px;
      background-color: green;
      margin-top: 50px;
    }

  </style>
</head>
<body>
  <div class="box1">盒子1</div>
  <div class="box2">盒子2</div>
</body>

如下图所示,box1和box1此时同处于html的BFC中,并且box1和box2在垂直方向上相邻,所以会出现margin重叠,取两者其中较大的值50px

同⼀个 BFC 的俩个相邻的盒⼦的 margin 会发⽣重叠

那么如何解决呢?错误做法是直接给box1添加一个BFC,此时box1确实是已经形成了BFC(可以理解成box1内部形成了BFC),但是对于box1这个元素的本身,还是和box2同属于html的BFC中,所以还是会发生margin重叠

正确做法:要给box1套一层,然后给box1外层的盒子设置BFC

<head>
  <meta charset="UTF-8">
  <style>
    .box1 {
      width: 100px;
      height: 100px;
      background-color: green;
      margin-bottom: 30px;
    }
    .box2 {
      width: 200px;
      height: 100px;
      background-color: green;
      margin-top: 50px;
    }
    .container {
      overflow: hidden;
    }

  </style>
</head>
<body>
  <div class="container">
    <div class="box1">盒子1</div>
  </div>
  <div class="box2">盒子2</div>
</body>

此时成功解决上下margin塌陷问题

BFC应用2:解决浮动高度塌陷问题

考虑如下场景

当给container里面的box设置浮动的时候,该div元素会脱离文档流,此时container不会有高度。

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .container {
      background-color: yellowgreen;
      border: 2px solid black;
    }
    .box {
      border: 1px solid black;
      width: 100px;
      height: 100px;
      float: left;
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="box">盒子1</div>
  </div>
</body>

当元素不是BFC的子元素时,浮动元素高度不参与BFC计算(常见的盒子塌陷问题)

BFC能解决浮动元素塌陷问题的原因在于:BFC计算元素的高度时,考虑BFC所包含的所有子元素,连浮动元素也要参与计算。所以为container元素添加overflow属性来设置BFC,此时container是一个新的BFC,计算高度时会包含浮动的子元素,因此解决浮动塌陷问题。

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .container {
      background-color: yellowgreen;
      border: 2px solid black;
      overflow: hidden;
    }
    .box {
      border: 1px solid black;
      width: 100px;
      height: 100px;
      float: left;
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="box">盒子1</div>
  </div>
</body>

BFC应用3:自适应两栏布局

每个元素的左外边距与包含块的左边界相接触。即使元素浮动,也会同样。

<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <style>
    .left {
      width: 100px;
      height: 150px;
      float: left;
      background: gray;
    }

    .right {
      height: 300px;
      background: rgb(170, 54, 236);
      background: yellowgreen;
    }
  </style>
</head>
<body>
  <div class="left">LEFT</div>
  <div class="right">RIGHT</div>
</body>

创建一个新的BFC会排除外部浮动,因此为right创建BFC可以实现自适应两栏布局。为right元素添加overflow:hidden来创建一个新的BFC

.right {
  height: 300px;
  background: rgb(170, 54, 236);
  background: yellowgreen;
  overflow: hidden;
}

参考:

juejin.cn/post/711708…

fe.okki.com/post/622d99…

清除浮动的多种方法

当父容器自身没有高度时(高度为auto),且容器的内容中有浮动(float为left或right)的元素,在这种情况下,容器的高度不能自动伸长以适应内容的高度,使得内容溢出到容器外面而影响(甚至破坏)布局的现象。这个现象叫浮动溢出,为了防止这个现象的出现而进行的CSS处理,就叫CSS清除浮动。

清除浮动的本质就是清除浮动元素造成的影响。清除浮动之后,父级盒子会根据浮动的子盒子自动检测高度,父级盒子有高度后就不会影响下面的标准流。

额外标签法

在浮动元素的下面添加一个额外标签,并结合CSS属性clear来完成清除浮动的操作。需要注意空标签一定要是块级元素

在html中浮动元素后面加一个兄弟元素。clear 属性规定元素的哪一侧不允许其他浮动元素 。

<div class="wrapper">
    <div class="float"></div>
    <div class="clear"></div>
</div>

css

.wrapper {
    width: 500px;
    background-color: purple;
}

.son {
    float: left;
    width: 100px;
    height: 100px;
    background-color: blue;
}

.clear {
    clear: both;
    background-color: pink;
}

优点:通俗易懂,书写方便

缺点:添加许多无意义的标签,结构化较差

利用BFC父级添加overflow

给父级添加overflow属性,值可以为hidden、auto、scroll。本质相当于为父级元素创建了一个新的BFC。

BFC能解决浮动元素塌陷问题的原因在于:BFC计算元素的高度时,考虑BFC所包含的所有子元素,连浮动元素也要参与计算。所以为container元素添加overflow属性来设置BFC,此时container是一个新的BFC,计算高度时会包含浮动的子元素,因此解决浮动塌陷问题。

.news {
  background-color: gray;
  border: solid 1px black;
  overflow: hidden;
  *zoom: 1;
  }

.news img {
  float: left;
  }

.news p {
  float: right;
  }

<div class="news">
  <img src="news-pic.jpg" />
  <p>some text</p>
</div>

伪元素clearfix清除浮动

结合 :after 伪元素(注意这不是伪类,而是伪元素,代表一个元素之后最近的元素)和 IEhack ,可以完美兼容当前主流的各大浏览器,这里的 IEhack 指的是触发 hasLayout。

给浮动元素的父容器添加一个clearfix的class,然后给这个class添加一个:after伪元素实现元素末尾添加一个看不见的块元素(Block element)清理浮动。(本质和额外标签法类似)

.news {
  background-color: gray;
  border: solid 1px black;
  }

.news img {
  float: left;
  }

.news p {
  float: right;
  }

.clearfix:after{
  content: ""; 
  display: block; 
  height: 0; 
  clear: both; 
  visibility: hidden;  
  }

.clearfix {
  /* 触发 hasLayout */ 
  zoom: 1; 
  }

<div class="news clearfix">
<img src="news-pic.jpg" />
<p>some text</p>
</div>

在这里需要注意的是,.clearfix:after实际上是伪元素语法,CSS3中引入了.clearfix::after来将伪类和伪元素语法区分开,但是浏览器仍旧接受单冒号的写法。

双伪元素清除浮动

使用伪元素选择器,给浮动元素的父容器添加一个clearfix的class,然后给这个class添加一个:after伪元素实现元素末尾添加一个看不见的块元素(Block element)清理浮动。以及添加一个:before伪元素,在开头也插入一个看不见的块元素。并应用clear:both属性。

.clearfix:before,
.clearfix:after {
    content: ””;
    display: table;
}

.clearfix:after {
    clear: both;
}

.clearfix {
    zoom: 1;
}

这里display: table作用是:让after 和 before 插入的两个伪元素位于一行显示,实现包夹住中间浮动元素的效果

设置父元素浮动触发 BFC

将包裹浮动元素的父元素设置为浮动元素,从而触发 BFC

缺点:会产生新的浮动问题。这样会使其整体浮动,影响布局,不推荐使用。

本质上就有两类方法,一类是利用CSS的clear属性来排除浮动,另一类则是利用BFC来清除浮动。其他一些所谓的方法本质也不过是以上两种而已。

什么是外边距折叠?如何解决外边距重叠问题

icodex.me/docs/css/%E…

www.zhihu.com/question/19…

tech.youzan.com/css-margin-…

两个或者多个普通流中相邻盒子的边距在垂直方向上会发生折叠的这种现象叫做外边距折叠。外边距折叠分为父子外边距折叠及兄弟外边距折叠。例如第一个盒子的margin-bottom为50px,下面盒子的margin-top为30px,两盒子之间的距离最终为50px,这个现象就是外边距折叠。

第一种情况: 两个相邻元素的下边距和上边距折叠

<!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" />
    <title>相邻兄弟元素的外边距重叠</title>
    <style>
      .box {
        width: 600px;
        height: 100px;
        line-height: 50px;
        text-align: center;
        color: #333;
      }
      .box1 {
        background-color: #f60;
        margin-bottom: 100px;
      }
      .box2 {
        background-color: #a90;
        margin-top: 100px;
      }
    </style>
  </head>
  <body>
    <div class="box box1">box1</div>
    <div class="box box2">box2</div>
  </body>
</html>

第二种情况:父元素与子元素发生边距折叠:

<!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" />
    <title>父级与子级的外边距重叠</title>
    <style>
      .box {
        line-height: 50px;
        text-align: center;
        color: #333;
      }
      .parent {
        width: 600px;
        height: 100px;
        background-color: #f60;
        margin-top: 100px;
      }
      .child {
        width: 600px;
        height: 50px;
        background-color: #a90;
        margin-top: 50px;
      }
    </style>
  </head>
  <body>
    <div class="box parent">
      <div class="box child">child</div>
    </div>
  </body>
</html>

如果仅仅只看我们的代码的话,父级的 margin-top 为 100px ,子级的 margin-top 为 50px,,如果相加的话为 150px,但实际结果如下所示:

外边距重叠的计算规则如下:

两个正数的外边距取最大的边距作为外边距。

如果一个为正数,一个为负数,最终的外边距为两者之和。

如果两个值都是负数的话,最终的外边距取绝对值最大的值。

什么时候会发生外边距折叠

都是普通流中的元素且属于同一个 BFC

没有被paddingborderclearline box分隔开

两个或两个以上垂直方向的「相邻元素」(这里的相邻元素可能是兄弟节点也可能是父子节点)

  • 盒子的margin-top和它第一个普通流子元素的margin-top
  • 盒子的margin-bottom和它下一个普通流兄弟的margin-top
  • 盒子的margin-bottom和它父元素的margin-bottom
  • 盒子的top margin和bottom margin,且没有创建一个新的块级格式上下文,且有被计算为0的min-height,被计算为0或auto的height,且没有普通流子元素

第四种情况是下列这种方式:

.demo {
    height: 30px;
    background: red;
}
.margin-test {
    margin: 20px 0 30px;
}

<div class="container">  
    <div class="demo"></div>
    <div class="margin-test"></div>
    <div class="demo"></div>
</div>  

这个demo是上面的第四种情况,元素自身的外边距top和bottom发生折叠,我们可以看出.container的高度为90px,这里可以看到margin-test的top和bottom外边距发生了折叠。

如何避免外边距折叠

上面讲了外边距的叠加,那如何避免呢,其实只要破坏上面讲到的四个条件中的任何一个即可:毗邻属于同一个BFC普通流垂直方向

前面已经提到了触发外边距折叠的条件,如果要避免外边距折叠只需破坏掉触发的条件即可,比如

解决相邻元素重叠:

1.在解决相邻元素外边距重叠时,将其中一个元素用div包裹,并在外层创建新的 BFC

可以通过如下方式创建 BFC:

  • float 的值不为 none
  • overflow 的值不为 visible
  • position 的值不为 static 或者 relative
  • display 的值为 table-cell, table-caption, inline-block, flex 或 inline-flex 其中之一

2.底部元素设置为浮动 float:left;,float的元素和其他元素之间不会发生外边距折叠,

3.底部元素的position的值为absolute/fixed,position:absolute或者position:fixed的绝对定位元素其他元素之间不会发生外边距折叠

4.设置margin-top/margin-bottom时统一设置向上或向下

解决父子元素外边距折叠:

外层元素添加padding来将多个元素分隔开

外层元素添加 overflow:hidden等来创建新BFC,

外层元素添加透明边框 border:1px solid transparent来将元素分隔开。

内层元素绝对定位 postion:absolute:

内层元素 加float:left;或display:inline-block;

总之,解决外边距重叠大致可以分为通过创建BFC,以及设置浮动、绝对定位、固定定位等来脱离文档流,或者添加padding或border来将元素分隔开这三大类方法。

zoom:1的作用和原理

zoom属性是ie浏览器的专有属性,它可以设置或者检索对象的缩放比例。设置或者更改一个已被呈递的对象的此属性值将导致环绕对象的内容重新流动。

除了可以设置缩放比例,还可以触发ie的haslayout属性。这一点在清除浮动时很有用。

当浮动子元素导致父元素塌陷的时候,只要给父元素加上overflow: hidden;来解决,但是对于IE不行,需要触发其hasLayout属性才可以。 因此zoom:1常常用于处理清除浮动场景下,对IE浏览器做兼容性处理。

zoom在ie浏览器中常见作用总结

1、检查页面的标签是否闭合

2、样式排除法

3、模块确认法

4、检查是否清除浮动

5、检查ie下是否触发haslayout

6、边框背景调试法

CSS中clear属性的作用

clear 属性规定元素的哪一侧不允许其他浮动元素 。

clear语法:

clear : none | left | right | both

取值:

none : 默认值。允许两边都可以有浮动对象

left : 不允许左边有浮动对象

right : 不允许右边有浮动对象

both : 不允许有浮动对象

什么是响应式布局?响应式布局的基本原理是什么?如何做

juejin.cn/post/684490…

响应式布局指的是同一页面在不同屏幕尺寸下有不同的布局。传统的开发方式是PC端开发一套,手机端再开发一套,而使用响应式布局只要开发一套就够,网站的布局会根据视口来调整模块的大小和位置。缺点就是CSS比较重。

响应式设计与自适应设计的区别

响应式设计与自适应设计的区别:响应式开发一套界面,通过检测视口分辨率,针对不同客户端在客户端做代码处理,来展现不同的布局和内容;自适应需要开发多套界面,通过检测视口分辨率,来判断当前访问的设备是pc端、平板、手机,从而请求服务层,返回不同的页面。

响应式布局的实现方式

响应式设计的基本原理是通过媒体查询检测不同的设备屏幕尺寸做处理,重置浏览器窗口大小的过程中,页面也会根据浏览器的宽度和高度重新渲染页面。

为了处理移动端,页面头部必须有meta声明viewport

视口配置代码示例:

<meta
  name="viewport"
  content="initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, width=device-width, user-scalable=no"
/>

上述代码示例的指令说明:

  • width=device-width 表示自适应手机屏幕的尺寸宽度
  • maximum-scale 表示网页缩放比例的最大值
  • initial-scale 表示网页缩放的初始化比例
  • user-scalable 表示用户是否可以进行缩放操作

完整指令说明:

指令取值说明
width正整数定义布局视口的宽度,单位为像素
height正整数定义布局视口的高度,单位为像素(较少使用)
initial-scale[0, 10]初始缩放比例(1 表示不缩放)
minimum-scale[0, 10]网页最小缩放比例
maximum-scale[0, 10]网页最大缩放比例
user-scalableyes 或 no是否允许用户手动缩放页面(默认为 yes)

媒体查询

以媒体查询实现响应式布局是痛通过 CSS3 @media 规则设置不同分辨率下的样式属性,来适配不同尺寸的屏幕设备。

不管是移动端优先还是 PC 优先,都是依据当随着屏幕宽度增大或减小的时候,后面的样式会覆盖前面的样式。因此,移动端优先首先使用的是 min-width,PC 端优先使用的 max-width

用具体代码举例:@media only screen and (min-width: 375px) and (max-width: 413px): 当屏幕宽度介于375px和413px之间时,将html元素的字体大小设置为100px。这一区间通常适用于iPhone 6/7/8和iPhone X等设备。

/* iPhone 6 7 8 */
body {
  background-color: yellow;
}

/* iPhone 5 */
@media screen and (max-width: 320px) {
  body {
    background-color: red;
  }
}

/* iPhoneX */
@media screen and (min-width: 375px) and (-webkit-device-pixel-ratio: 3) {
  body {
    background-color: orange;
  }
}

/* iPhone6 7 8 Plus */
@media screen and (min-width: 414px) {
  body {
    background-color: blue;
  }
}
/* iPad */
@media screen and (min-width: 768px) {
  body {
    background-color: green;
  }
}

/* iPad Pro */
@media screen and (min-width: 1024px) {
  body {
    background-color: gray;
  }
}

/* PC */
@media screen and (min-width: 1100px) {
  body {
    background-color: black;
  }
}

代码示例说明:

屏幕计算大小判断屏幕机型命中样式
< 320pxiPhone5red
320px < x < 375px (默认)iPhone 6/7/8yellow
375px < x 414pxiPhoneXorange
414px < x < 768pxiPhone6/7/8 Plusblue
768px < x < 1024pxiPadgreen
1024px < x < 1100pxiPad Progray
< 1100pxPCblack

百分比布局

通过百分比单位 % 来实现响应式的效果。比如当浏览器的宽度或者高度发生变化时,通过百分比单位,可以使得浏览器中的组件的宽和高随着浏览器的变化而变化,从而实现响应式的效果。

heightwidth 属性的百分比依托于父标签的宽高,但是其他盒子属性则不完全依赖父元素:

  • 子元素的 top/left 和 bottom/right 如果设置百分比,则相对于直接非 static 定位(默认定位)的父元素的高度/宽度;
  • 子元素的 padding 如果设置百分比,不论是垂直方向或者是水平方向,都相对于直接父亲元素的 width,而与父元素的 height 无关;
  • 子元素的 margin 如果设置成百分比,不论是垂直方向还是水平方向,都相对于直接父元素的 width
  • border-radius 不一样,如果设置 border-radius 为百分比,则是相对于自身的宽度。
  • translatebackground-size等都是相对于自身的

有明显的以下两个缺点:

  • 计算困难,如果我们要定义一个元素的宽度和高度,按照设计稿,必须换算成百分比单位。
  • 可以看出,各个属性中如果使用百分比,相对父元素的属性并不是唯一的。比如width和height相对于父元素的width和height,而margin、padding不管垂直还是水平方向都相对比父元素的宽度、border-radius则是相对于元素自身等等,造成我们使用百分比单位容易使布局问题变得复杂。

rem布局

rem单位都是相对于根元素html的font-size来决定大小的,根元素的font-size相当于提供了一个基准,当页面的size发生变化时,只需要改变font-size的值,那么以rem为固定单位的元素的大小也会发生响应的变化。 因此,如果通过rem来实现响应式的布局,只需要利用媒体查询,在不同分辨率下给 元素的 font-size 赋值,根据视图容器的大小,动态的改变font-size即可(而em是相对于父元素的)。

rem响应式的布局思想:

  • 一般不要给元素设置具体的宽度,但是对于一些小图标可以设定具体宽度值
  • 高度值可以设置固定值,设计稿有多大,我们就严格有多大
  • 所有设置的固定值都用rem做单位(首先在HTML总设置一个基准值:px和rem的对应比例,然后在效果图上获取px值,布局的时候转化为rem值)
  • 除媒体查询外,也可以用js获取真实屏幕的宽度,让其除以设计稿的宽度,算出比例,把之前的基准值按照比例进行重新的设定,这样项目就可以在移动端自适应了

rem布局缺点:在响应式布局中,必须通过js来动态控制根元素font-size的大小,也就是说css样式和js代码有一定的耦合性,且必须将改变font-size的代码放在css样式之前

/*上述代码中将视图容器分为10份,font-size用十分之一的宽度来表示,最后在header标签中执行这段代码,就可以动态定义font-size的大小,从而1rem在不同的视觉容器中表示不同的大小,用rem固定单位可以实现不同容器内布局的自适应。*/
function refreshRem() {
    var docEl = doc.documentElement;
    var width = docEl.getBoundingClientRect().width;
    var rem = width / 10;
    docEl.style.fontSize = rem + 'px';
    flexible.rem = win.rem = rem;
}
win.addEventListener('resize', refreshRem);

视口单位

css3中引入了一个新的单位vw/vh,与视图窗口有关,vw表示相对于视图窗口的宽度,vh表示相对于视图窗口高度,除了vw和vh外,还有vmin和vmax两个相关的单位。各个单位具体的含义如下:

单位含义
vw相对于视窗的宽度,1vw 等于视口宽度的1%,即视窗宽度是100vw
vh相对于视窗的高度,1vh 等于视口高度的1%,即视窗高度是100vh
vminvw和vh中的较小值
vmaxvw和vh中的较大值

用视口单位度量,视口宽度为100vw,高度为100vh(左侧为竖屏情况,右侧为横屏情况)。例如,在桌面端浏览器视口尺寸为650px,那么 1vw = 650 * 1% = 6.5px

使用视口单位来实现响应式有两种做法:

仅使用vw

将设计稿的尺寸转换为 vw 单位,以适应不同视口宽度的设备。使用 Sass 函数编译,将设计稿的像素值转换为相应的 vw 单位值。

在 CSS 中,所有尺寸(如布局宽度、间距、字体大小等)都使用 vw 作为单位。这样,在不同尺寸的设备上,元素的大小和间距都会根据视口宽度进行自适应调整。

对于高清屏幕下的物理像素线,采用 transform: scaleY(0.5); 实现,使其在高清屏幕上显示为半个物理像素。

对于需要保持宽高比的图像,使用 padding-top 实现,保证图像的宽高比在不同设备上保持一致。

对于需要保持宽高比的图,应该用padding-top实现

.mod_banner {
    position: relative;
    padding-top: percentage(100/700); // 使用 padding-top
    height: 0;  // 设置高度为 0,使得内容区域没有高度
    overflow: hidden;  // 隐藏超出内容区域的内容
}

.mod_banner img {
    width: 100%;  // 图片宽度占满父容器
    height: auto;  // 图片高度自适应,保持原始宽高比
    position: absolute;  // 绝对定位,相对于其第一个非 static 祖先元素进行定位
    left: 0;  // 图片相对于父容器左侧定位
    top: 0;  // 图片相对于父容器顶部定位
}

.mod_banner 类是图片容器的样式,通过设置 position: relative; 实现相对定位,后续绝对定位的图片将相对于该容器进行定位。设置 padding-top: percentage(100/700); 实现了一个特殊的技巧,即利用 padding-top 属性的百分比值来保持容器的高度和宽度的比例关系。percentage(100/700) 表示容器高度与宽度的比例为 700:100,也就是高度是宽度的 7 倍。因为 padding-top 的百分比值是相对于父容器宽度来计算的,所以通过这种方式可以保持容器的宽高比。

height: 0; 和 overflow: hidden; 用于隐藏容器的内容区域,这样容器的高度就由 padding-top 的百分比值确定了,而不是由其中的内容撑开。

.mod_banner img 类是图片的样式,通过设置 width: 100%; 让图片的宽度占满父容器,同时设置 height: auto; 让图片的高度根据宽度自适应,保持图片的原始宽高比。然后使用 position: absolute; 将图片相对于父容器进行绝对定位,这样可以使图片完全覆盖整个容器,并且不影响其他元素的布局。最后,通过 left: 0; 和 top: 0; 让图片定位到父容器的左上角。

结合rem与vw

可以结合rem和vw来实现布局

  • 给根元素大小设置随着视口变化而变化的vw单位,这样就可以实现动态改变其大小
  • 限制根元素字体大小的最大最小值,配合body加上最大宽度和最小宽度
// rem 单位换算:定为 75px 只是方便运算,750px-75px、640-64px、1080px-108px,如此类推
$vm_fontsize: 75; // iPhone 6尺寸的根元素大小基准值
@function rem($px) {
     @return ($px / $vm_fontsize ) * 1rem;
}
// 根元素大小使用 vw 单位
$vm_design: 750;
html {
    font-size: ($vm_fontsize / ($vm_design / 2)) * 100vw; 
    // 同时,通过Media Queries 限制根元素最大最小值
    @media screen and (max-width: 320px) {
        font-size: 64px;
    }
    @media screen and (min-width: 540px) {
        font-size: 108px;
    }
}
// body 也增加最大最小宽度限制,避免默认100%宽度的 block 元素跟随 body 而过大过小
body {
    max-width: 540px;
    min-width: 320px;
}

图片实现响应式

图片响应式包括两个方面,一个就是大小自适应,这样能够保证图片在不同的屏幕分辨率下出现压缩、拉伸的情况;一个就是根据不同的屏幕分辨率和设备像素比来尽可能选择高分辨率的图片,也就是当在小屏幕上不需要高清图或大图,这样我们用小图代替,就可以减少网络带宽了。

使用max-width(图片自适应):

图片自适应意思就是图片能随着容器的大小进行缩放,可以采用如下代码:

img {
    display: inline-block;
    max-width: 100%;
    height: auto;
}

inline-block 元素相对于它周围的内容以内联形式呈现,但与内联不同的是,这种情况下我们可以设置宽度和高度。 max-width保证了图片能够随着容器的进行等宽扩充(即保证所有图片最大显示为其自身的 100%。此时,如果包含图片的元素比图片固有宽度小,图片会缩放占满最大可用空间),而height为auto可以保证图片进行等比缩放而不至于失真。如果是背景图片的话要灵活运用background-size属性。

那么为什么不能用width:100%呢?因为这条规则会导致它显示得跟它的容器一样宽。在容器比图片宽得多的情况下,图片会被无谓地拉伸。

使用srcset

<img srcset="photo_w350.jpg 1x, photo_w640.jpg 2x" src="photo_w350.jpg" alt="">

srcset 是 HTML 中 标签的一个属性,用于提供一组备选图像,让浏览器根据设备的像素密度选择合适的图像进行加载。

在这个属性中,每个备选图像都包含两部分:图像的 URL 和图像的密度描述符。密度描述符表示了图像的像素密度与屏幕的像素密度的比值。通常有两种取值:1x 表示图像的像素密度与屏幕的像素密度相等,2x 表示图像的像素密度是屏幕像素密度的两倍。在实际应用中,还可以使用其他倍数。

如果屏幕的dpi = 1的话则加载1倍图,而dpi = 2则加载2倍图,手机和mac基本上dpi都达到了2以上,这样子对于普通屏幕来说不会浪费流量,而对于视网膜屏来说又有高清的体验。

如果浏览器不支持srcset,则默认加载src里面的图片。

但是你会发现实际情况并不是如此,在Mac上的Chrome它会同时加载srcset里面的那张2x的,还会再去加载src里面的那张,加载两张图片。顺序是先把所有srcset里面的加载完了,再去加载src的。这个策略比较奇怪,它居然会加载两张图片,如果不写src,则不会加载两张,但是兼容性就没那么好。这个可能是因为浏览器认为,既然有srcset就不用写src了,如果写了src,用户可能是有用的。而使用picture就不会加载两张

使用background-image+媒体查询

.banner{
  background-image: url(/static/large.jpg);
}

@media screen and (max-width: 767px){
  background-image: url(/static/small.jpg);
}

在屏幕宽度小于或等于 767px 时,.banner 类就会应用 /static/small.jpg 作为背景图片,从而实现了在小屏幕设备上加载小尺寸的图片,以节省带宽和加快页面加载速度

使用picture标签

搭配picturefill.min.js :解决IE等浏览器不支持 的问题

<picture>
  <source srcset="banner_w1000.jpg" media="(min-width: 801px)">
  <source srcset="banner_w800.jpg" media="(max-width: 800px)">
  <img src="banner_w800.jpg" alt="">
</picture>

<!-- picturefill.min.js 解决IE等浏览器不支持 <picture> 的问题 -->
<script type="text/javascript" src="js/vendor/picturefill.min.js"></script>

picture必须要写img标签,否则无法显示,对picture的操作最后都是在img上面,例如onload事件是在img标签触发的,picture和source是不会进行layout的,它们的宽和高都是0。

另外使用source,还可以对图片格式做一些兼容处理:

响应式布局的成型方案

实际项目中我们可以直接使用这些新特性和框架来实现响应式布局。可以有以下选择方案:

  • 利用上面的方法自己来实现,比如CSS3 Media Query,rem,vw等
  • Flex弹性布局,兼容性较差
  • Grid网格布局,兼容性较差
  • Columns栅格系统,往往需要依赖某个UI库,如Bootstrap

在实际项目中,我们可能需要综合上面的方案,比如用rem来做字体的适配,用srcset来做图片的响应式,宽度可以用rem,flex,栅格系统等来实现响应式,然后可能还需要利用媒体查询来作为响应式布局的基础,因此综合上面的实现方案,项目中实现响应式布局需要注意下面几点:

  • 设置viewport
  • 媒体查询
  • 字体的适配(字体单位)
  • 百分比布局
  • 图片的适配(图片的响应式)
  • 结合flex,grid,BFC,栅格系统等已经成型的方案

px em rem rpx vw/vh 百分比%区别

px:绝对长度单位,来描述一个元素的宽高以及定位信息

rpx:微信小程序独有的、解决屏幕自适应的尺寸单位

em:相对单位,基准点为父节点字体的大小,如果自身定义了font-size按自身来计算(浏览器默认16px)em作为字体单位,相对于父元素字体大小;em作为行高单位时,相对于自身字体大小,整个页面内 1em 不是一个固定的值。

rem:相对单位,可理解为”root em”,相对根节点html的字体大小来计算,CSS3新加属性,rem作用于非根元素时,相对于根元素字体大小;rem作用于根元素字体大小时,相对于其出初始字体大小。rem布局的本质是等比缩放,一般是基于宽度,试想一下如果UE图能够等比缩放,那该多么美好啊

vw/vh:viewpoint width / viewpoint height,vw 相对于视窗的宽度,vh 相对于视窗的高度,1vw等于视窗宽度的1%

百分比:百分比%是百分比布局中的单位,heightwidth 属性的百分比依托于父标签的宽高,但是其他盒子属性则不完全依赖父元素。

px

绝对长度单位,根据维基百科解释:它是图像显示的基本单元,既不是一个确定的物理量,也不是一个点或者小方块,而是一个抽象概念。很多时候,px 也常被称为 CSS 像素,在 PC 中,通常认为 1px 的真实长度是固定的

那 px 真的是一个设备无关,跟长度单位米和分米一样是固定大小的吗?

一个像素表示了计算机屏幕所能显示的最小区域,像素分为两种类型:

CSS 像素:为 Web 开发者提供,在 CSS 中使用的一个抽象单位

物理像素:只与设备的硬件密度有关,任何设备的物理像素都是固定的

转换关系:CSS像素 = 物理像素/分辨率

假设PC 端:750 * 1134的视觉稿: 1 CSS像素 = 物理像素/分辨率 = 750 / 980 =0.76

假设移动端(iphone6为例),分辨率为375 * 667:1 CSS像素 = 物理像素 /分辨率 = 750 / 375 = 2

所以 PC 端,一个CSS像素可以用0.76个物理像素来表示,而iphone6中 一个CSS像素表示了2个物理像素。此外不同的移动设备分辨率不同,也就是1个CSS像素可以表示的物理像素是不同的

注意,当浏览器页面缩放时,px 并不能跟随变大。当前网页的布局就会被打破。

rpx

rpx是微信小程序独有的、解决屏幕自适应的尺寸单位

可以根据屏幕宽度进行自适应,不论大小屏幕,规定屏幕宽为 750rpx

通过 rpx 设置元素和字体的大小,小程序在不同尺寸的屏幕下,可以实现自动适配

rpx 和 px之间的区别:

在普通网页开发中,最常用的像素单位是px

在小程序开发中,推荐使用 rpx 这种响应式的像素单位进行开发

设计师在出设计稿的时候,出的都是二倍图,也就是说如果在这个设计稿上有一个宽高为 200px 的盒子,那么它最终画到页面上实际上是一个宽高为 100px 的盒子,那么再换算成 rpx 需要乘以 2 ,就又变成了 200rpx ,跟设计稿上的数字是一样的,所以我们可以保持数字不变,直接将单位 px 替换成 rpx

微信规定:屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px

em

相对长度单位,em只有与font-size属性搭配使用时,是相对于其父元素的 font-size 进行计算,如果当前元素未设置则相对于浏览器的默认字体尺寸。

用em设置其他属性单位的时候, 是相对于自身的字体属性大小,

<div class="a">A
    <div class="b">B
        <div class="c">C</div>
    </div>
</div>

<style>
	.a{ font-size:16px;}
	.b{ font-size:2em;} /* 相当于32px */
	.c{ font-size:1em;} /* 相当于32px */
</style>

rem

相对长度单位,CSS3 新增的一个相对单位,rem 是相对于根元素(html)的 font-size 进行计算,rem 不仅可设置字体大小,也可以设置元素宽高属性。

vw与vh

CSS3 特性 vh 和 vw:

vh 相对于视窗(网页视口高度)的高度,视窗高度是100vh

vw 相对于视窗(网页视口高度)的宽度,视窗宽度是100vw

这里是视窗指的是浏览器内部的可视区域大小,即 window.innerWidth/window.innerHeight 大小,不包含任务栏标题栏以及底部工具栏的浏览器区域大小。

百分比

通常认为子元素的百分比完全相对于直接父元素:


<div class="a">
    <div class="b"></div>
</div>
<style>
    .a{ width:200px; height:100px; background-color: aqua; } 
    .b{ width:50%; height:50%; background-color: blueviolet; }
</style>

需要注意的是,如果设置了top、margin、padding等:

  • 子元素的 top 和 bottom 如果设置百分比,则相对于直接非 static 定位(默认定位)的父元素的高度
  • 子元素的 left 和 right 如果设置百分比,则相对于直接非 static 定位(默认定位的)父元素的宽度
  • 子元素的 padding/margin 如果设置百分比,不论是垂直方向或者是水平方向,都相对于直接父亲元素的 padding/margin ,而与父元素的 height 无关。

CSS中的vw与vh

对于如下图,要准确区分几个概念,即网页视口高度、屏幕高度、body高度,

window.screen.height 表示 屏幕高度

window.innerHeight 表示网页视口高度

document.body.clientHeight 表示body元素的内容高度

vh 表示视口高度的百分比,其中 1vh 等于视口高度的1%

vw 表示视口宽度的百分比,其中 1vw 等于视口宽度的1%

vmax 取 vw 和 vh 中的较大值; vmin 取两者最小值

需要注意的是,如果设置了top、margin、padding等:

  • 子元素的 top 和 bottom 如果设置百分比,则相对于直接非 static 定位(默认定位)的父元素的高度
  • 子元素的 left 和 right 如果设置百分比,则相对于直接非 static 定位(默认定位的)父元素的宽度
  • 子元素的 padding/margin 如果设置百分比,不论是垂直方向或者是水平方向,都相对于直接父亲元素的 padding/margin ,而与父元素的 height 无关。

vw 与 %区别

vw、vh是相对于屏幕视口高度而言

vh 表示视口高度的百分比,其中 1vh 等于视口高度的1%

vw 表示视口宽度的百分比,其中 1vw 等于视口宽度的1%

%则是相对于直接父元素而言,子元素的百分比完全相对于直接父元素:

nth-child和nth-of-type的区别

nth-child(n)选择器匹配属于其父元素的第n个子元素,无论它的类型是什么,n可以是数字,关键词或公式。

nth-of-type(n)选择器匹配父元素中的特定类型的第n个子元素,它只考虑与给定类型匹配的子元素。n可以是数字,关键词或公式。

额外补充一点:nth-child会给所有子元素排序号,但是如果对应的元素和nth-child前面的标签不匹配,则无效。

<div class="content">
  <div>123</div>
  <p>1</p>
  <p>2</p>
  <p>3</p>
  <p>4</p>
  <p>5</p>
  <p>6</p>
  <p>7</p>
</div>

对于下列样式,p:nth-child(1)匹配到div,但是它不是p,所以这个不会起作用。改为.content p:nth-child(2)可以,因为第二个标签<p>1</p>确实是一个p元素。

.content p:nth-child(1) {
  background-color: blue;
}
.content p:nth-of-type(2) {
  background-color: pink;
}

p:nth-of-type(7) 选择的 p元素所在的父元素下的第7个P元素 即:

第7个p

p:nth-child(6) 选择的 p元素所在的父元素下的第6个子元素,且该元素是P元素 即:

第5个p

flex布局

什么是flex布局

Flex 是 Flexible Box 的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性。

任何一个容器都可以指定为 Flex 布局。

.box{
  display: flex;
}

行内元素也可以使用 Flex 布局。

.box{
  display: inline-flex;
}

Webkit 内核的浏览器,必须加上-webkit前缀。

.box{
  display: -webkit-flex; /* Safari */
  display: flex;
}

采用 Flex 布局的元素,称为 Flex 容器(flex container),简称"容器"。它的所有子元素自动成为容器成员,称为 Flex 项目(flex item),简称"项目"。

容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis)。主轴的开始位置(与边框的交叉点)叫做main start,结束位置叫做main end;交叉轴的开始位置叫做cross start,结束位置叫做cross end

项目默认沿主轴排列。单个项目占据的主轴空间叫做main size,占据的交叉轴空间叫做cross size

flex常见属性

容器属性

以下6个属性设置在容器上。

  • flex-direction:主轴的方向
  • flex-wrap:超出父容器的项目的排列方式
  • flex-flow:flex-direction和flex-wrap属性的简写
  • justify-content:项目在主轴的对齐方式
  • align-items:项目在交叉轴的对齐方式
  • align-content:多根轴线的对齐方式

flex-direction属性决定主轴的方向(即项目的排列方向)。主轴的方向不一定是水平的,这个属性就是设置主轴的方向,主轴默认是水平方向,从左至右,如果主轴方向设置完毕,那么交叉轴就不需要设置,交叉轴永远是主轴顺时针旋转 90°

.ele {
  flex-direction: row;                // 默认值,主轴为水平方向,起点在左端。
  flex-direction: row-reverse;        // 主轴为水平方向,起点在右端。
  flex-direction: column;             // 主轴为垂直方向,起点在上。
  flex-direction: column-reverse;     // 主轴为垂直方向,起点在下。
}

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

.box{
  flex-wrap: nowrap | wrap | wrap-reverse;
}

nowrap(默认):不换行。

wrap:换行,第一行在上方。

wrap-reverse:换行,第一行在下方。

flex-flow:属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap

.box {
  flex-flow: <flex-direction> || <flex-wrap>;
}

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

.box {
  justify-content: flex-start | flex-end | center | space-between | space-around;
}

它可能取5个值,具体对齐方式与轴的方向有关。下面假设主轴为从左到右。

  • flex-start(默认值):左对齐
  • flex-end:右对齐
  • center: 居中
  • space-between:两端对齐,项目之间的间隔都相等。
  • space-around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。

align-items属性定义项目在交叉轴上如何对齐。它可能取5个值。具体的对齐方式与交叉轴的方向有关,下面假设交叉轴从上到下。

  • flex-start:交叉轴的起点对齐。
  • flex-end:交叉轴的终点对齐。
  • center:交叉轴的中点对齐。
  • baseline: 项目的第一行文字的基线对齐。
  • stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。

align-content属性:定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。也可以理解为用于设置子项在交叉轴的排列方式,并且只能用于子项出现换行的情况,在单行下没有效果。

该属性可能取6个值。

  • flex-start:与交叉轴的起点对齐。
  • flex-end:与交叉轴的终点对齐。
  • center:与交叉轴的中点对齐。
  • space-between:与交叉轴两端对齐,轴线之间的间隔平均分布。
  • space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。
  • stretch(默认值):轴线占满整个交叉轴。

项目属性

以下6个属性设置在项目上。

  • order:定义项目排列顺序
  • flex-grow:定义项目的放大比例
  • flex-shrink:定义项目缩小比例
  • flex-basis:定义分配多余空间之前,项目占据的主轴空间
  • flex:flex-grow,flex-shrink,flex-basis的简写
  • align-self:用于设置单个项目有与其他项目不同的对齐方式

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

flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。

flex-shrink属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小。如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。

负值对该属性无效。

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

它可以设为跟widthheight属性一样的值(比如350px),则项目将占据固定空间。

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

该属性有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)。

建议优先使用这个属性,而不是单独写三个分离的属性,因为浏览器会推算相关值。

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

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

flex:1具体代表什么

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

flex:1 经常用作自适应布局,将父容器的 display:flex,侧边栏大小固定后,将内容区 flex:1,内容区则会自动放大占满剩余空间。

flex:1 其实是flex: 1 1 0%的简写。

flex-grow : 1;
flex-shrink : 1;
flex-basis : 0%;

翻阅MDN文档时写到,flex:1并不是只定义了flex-grow的值,而是同时定义了三个属性的值的一种简写方式。

flex单值语法,填写一个flex-grow的有效值时,简写会扩展为 flex: 1 0。

同时通过浏览器验证也可以得出:

当一个容器设置display:flex变成一个flex容器后,如果容器没有被占满,换言之有剩余空间,则flex-grow起作用。

相反,若空间不足,则flex-shrink起作用。

在计算放大或缩小比例时,要根据flex-basis的值来计算比例。

<div class="parent">
	<div class="item-1"></div>
	<div class="item-2"></div>
	<div class="item-3"></div>
</div>

<style type="text/css">
	.parent {
		display: flex;
		width: 600px;
	}
	.parent > div {
		height: 100px;
	}
	.item-1 {
		width: 140px;
		flex: 2 1 0%;
		background: blue;
	}
	.item-2 {
		width: 100px;
		flex: 2 1 auto;
		background: darkblue;
	}
	.item-3 {
		flex: 1 1 200px;
		background: lightblue;
	}
</style>

主轴上父容器总尺寸为 600px。

子元素的总基准值是:0% + auto + 200px = 300px,其中

0% 即 0 宽度

auto 对应取原尺寸即 100px

故剩余空间为600px - 300px = 300px

伸缩放大系数之和为2 + 2 + 1 = 5

每个项目的剩余空间分配如下

item-1 和 item-2 各分配 2/5,各得 120px
item-3 分配 1/5,得 60px

因此各项目最终宽度为:

item-1 = 0% + 120px = 120px
item-2 = auto + 120px = 220px
item-3 = 200px + 60px = 260px

当 item-1 基准值取 0% 的时候,是把该项目视为零尺寸的,故即便声明其尺寸为 140px,也并没有什么用,形同虚设。

而 item-2 基准值取 auto 的时候,根据规则基准值使用值是主尺寸值即 100px,故这 100px 不会纳入剩余空间。

flex属性的缩写规则

juejin.cn/post/696979…

developer.mozilla.org/zh-CN/docs/…

flex 为一个非负数字 n:该数字为 flex-grow 的值

flex :n;
/* 等同于: */
flex-grow :n;
flex-shrink1flex-basis0%

flex 为两个非负数字 n1,n2:

分别为 flex-grow 和 flex-shrink 的值

flex :n1 n2;
/* 等同于: */
flex-grow :n1;
flex-shrink :n2;
flex-basis0%

flex 为一个长度或百分比 L:

视为 flex-basis 的值

flex : L;
/* 等同于: */
flex-grow1flex-shrink1flex-basis :L;

flex 为一个非负数字 n 和一个长度或百分比 L:

分别为 flex-grow 和 flex-basis 的值

flex :n L;
/* 等同于: */
flex-grow:n;
flex-shrink1flex-basis:L;

可以发现,flex-grow 和 flex-shrink 在 flex 属性中不规定值则为 1,flex-basis 为 0%。

flex:1和flex:auto的区别

flex:1

flex-grow : 1;
flex-shrink : 1;
flex-basis : 0%;

flex:auto是提供的一种属性简写的方式,分别代表

flex-grow : 1;
flex-shrink : 1;
flex-basis : auto;

flex布局中 align-content和align-items的区别

align-items适用于单行情况下,只有上对齐,下对齐,居中和拉伸

align-comtent适应于换行(多行)的情况下(单行情况下无效),可以设置上对齐,下对齐,居中,拉伸以及平均分配剩余空间等属性

总结就是单行使用align-items,多行使用align-content

Grid布局

网格布局(Grid)是最强大的 CSS 布局方案。它将网页划分成一个个网格,可以任意组合不同的网格,做出各种各样的布局。

Grid 布局与 Flex 布局有一定的相似性,都可以指定容器内部多个项目的位置。但是,它们也存在重大区别。

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

基本概念

容器和项目:

采用网格布局的区域,称为"容器"(container)。容器内部采用网格定位的子元素,称为"项目"(item)。

<div>
  <div><p>1</p></div>
  <div><p>2</p></div>
  <div><p>3</p></div>
</div>

上面代码中,最外层的<div>元素就是容器,内层的三个

元素就是项目。

注意:项目只能是容器的顶层子元素,不包含项目的子元素,比如上面代码的

元素就不是项目。Grid 布局只对项目生效。

行和列:

容器里面的水平区域称为"行"(row),垂直区域称为"列"(column)。图中,水平的深色区域就是"行",垂直的深色区域就是"列"。

单元格:

行和列的交叉区域,称为"单元格"(cell)。

正常情况下,n行和m列会产生n x m个单元格。比如,3行3列会产生9个单元格。

网格线:

划分网格的线,称为"网格线"(grid line)。水平网格线划分出行,垂直网格线划分出列。

正常情况下,n行有n + 1根水平网格线,m列有m + 1根垂直网格线,比如三行就有四根水平网格线。

容器属性

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

3.1 display 属性

display: grid指定一个容器采用网格布局。

div {
  display: grid;
}

上图是display: grid效果

默认情况下,容器元素都是块级元素,但也可以设成行内元素。

div {
  display: inline-grid;
}

上面代码指定div是一个行内元素,该元素内部采用网格布局。

上图是display: inline-grid的效果

注意,设为网格布局以后,容器子元素(项目)的float、display: inline-block、display: table-cell、vertical-align和column-*等设置都将失效。

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

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

.container {
  display: grid;
  grid-template-columns: 100px 100px 100px;
  grid-template-rows: 100px 100px 100px;
}

上面代码指定了一个三行三列的网格,列宽和行高都是100px。

除了使用绝对单位,也可以使用百分比

.container {
  display: grid;
  grid-template-columns: 33.33% 33.33% 33.33%;
  grid-template-rows: 33.33% 33.33% 33.33%;
}

(1)repeat()

有时候,重复写同样的值非常麻烦,尤其网格很多时。这时,可以使用repeat()函数,简化重复的值。上面的代码用repeat()改写如下。

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

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

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

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

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

(2)auto-fill 关键字

有时,单元格的大小是固定的,但是容器的大小不确定。如果希望每一行(或每一列)容纳尽可能多的单元格,这时可以使用auto-fill关键字表示自动填充。

.container {
  display: grid;
  grid-template-columns: repeat(auto-fill, 100px);
}

上面代码表示每列宽度100px,然后自动填充,直到容器不能放置更多的列。

除了auto-fill,还有一个关键字auto-fit,两者的行为基本是相同的。只有当容器足够宽,可以在一行容纳所有单元格,并且单元格宽度不固定的时候,才会有行为差异:auto-fill会用空格子填满剩余宽度,auto-fit则会尽量扩大单元格的宽度。

(3)fr 关键字

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

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

上面代码表示两个相同宽度的列。

fr可以与绝对长度的单位结合使用,这时会非常方便。

.container {
  display: grid;
  grid-template-columns: 150px 1fr 2fr;
}

上面代码表示,第一列的宽度为150像素,第二列的宽度是第三列的一半。

4)minmax()

minmax()函数产生一个长度范围,表示长度就在这个范围之中。它接受两个参数,分别为最小值和最大值。

grid-template-columns: 1fr 1fr minmax(100px, 1fr);

上面代码中,minmax(100px, 1fr)表示列宽不小于100px,不大于1fr。

(5)auto 关键字

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

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

上面代码中,第二列的宽度,基本上等于该列单元格的最大宽度,除非单元格内容设置了min-width,且这个值大于最大宽度。

(6)网格线的名称

grid-template-columns属性和grid-template-rows属性里面,还可以使用方括号,指定每一根网格线的名字,方便以后的引用。

.container {
  display: grid;
  grid-template-columns: [c1] 100px [c2] 100px [c3] auto [c4];
  grid-template-rows: [r1] 100px [r2] 100px [r3] auto [r4];
}

上面代码指定网格布局为3行 x 3列,因此有4根垂直网格线和4根水平网格线。方括号里面依次是这八根线的名字。

网格布局允许同一根线有多个名字,比如[fifth-line row-5]。

(7)布局实例

grid-template-columns属性对于网页布局非常有用。两栏式布局只需要一行代码

.wrapper {
  display: grid;
  grid-template-columns: 70% 30%;
}

上面代码将左边栏设为70%,右边栏设为30%。

传统的十二网格布局,写起来也很容易。

grid-template-columns: repeat(12, 1fr);

3.3 grid-row-gap 属性, grid-column-gap 属性, grid-gap 属性

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

.container {
  grid-row-gap: 20px;
  grid-column-gap: 20px;
}

上面代码中,grid-row-gap用于设置行间距,grid-column-gap用于设置列间距。

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

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

因此,上面一段 CSS 代码等同于下面的代码。

.container {
  grid-gap: 20px 20px;
}

如果grid-gap省略了第二个值,浏览器认为第二个值等于第一个值。

根据最新标准,上面三个属性名的grid-前缀已经删除,grid-column-gap和grid-row-gap写成column-gap和row-gap,grid-gap写成gap。

3.4 grid-template-areas 属性

网格布局允许指定"区域"(area),一个区域由单个或多个单元格组成。grid-template-areas属性用于定义区域。

.container {
  display: grid;
  grid-template-columns: 100px 100px 100px;
  grid-template-rows: 100px 100px 100px;
  grid-template-areas: 'a b c'
                       'd e f'
                       'g h i';
}

上面代码先划分出9个单元格,然后将其定名为a到i的九个区域,分别对应这九个单元格。

多个单元格合并成一个区域的写法如下。

grid-template-areas: 'a a a'
                     'b b b'
                     'c c c';

上面代码将9个单元格分成a、b、c三个区域。

下面是一个布局实例。

grid-template-areas: "header header header"
                     "main main sidebar"
                     "footer footer footer";

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

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

grid-template-areas: 'a . c'
                     'd . f'
                     'g . i';

上面代码中,中间一列为点,表示没有用到该单元格,或者该单元格不属于任何区域。

注意,区域的命名会影响到网格线。每个区域的起始网格线,会自动命名为区域名-start,终止网格线自动命名为区域名-end。

比如,区域名为header,则起始位置的水平网格线和垂直网格线叫做header-start,终止位置的水平网格线和垂直网格线叫做header-end。

3.5 grid-auto-flow 属性

划分网格以后,容器的子元素会按照顺序,自动放置在每一个网格。默认的放置顺序是"先行后列",即先填满第一行,再开始放入第二行,即下图数字的顺序。

这个顺序由grid-auto-flow属性决定,默认值是row,即"先行后列"。也可以将它设成column,变成"先列后行"。

grid-auto-flow: column;

上面代码设置了column以后,放置顺序就变成了下图。

grid-auto-flow属性除了设置成row和column,还可以设成row densecolumn dense。这两个值主要用于,某些项目指定位置以后,剩下的项目怎么自动放置。

下面的例子让1号项目和2号项目各占据两个单元格,然后在默认的grid-auto-flow: row情况下,会产生下面这样的布局。

上图中,1号项目后面的位置是空的,这是因为3号项目默认跟着2号项目,所以会排在2号项目后面。

现在修改设置,设为row dense,表示"先行后列",并且尽可能紧密填满,尽量不出现空格。

grid-auto-flow: row dense;

上面代码的效果如下。

上图会先填满第一行,再填满第二行,所以3号项目就会紧跟在1号项目的后面。8号项目和9号项目就会排到第四行。

如果将设置改为column dense,表示"先列后行",并且尽量填满空格。

grid-auto-flow: column dense;

上面代码的效果如下。

上图会先填满第一列,再填满第2列,所以3号项目在第一列,4号项目在第二列。8号项目和9号项目被挤到了第四列。

3.6 justify-items 属性, align-items 属性, place-items 属性

justify-items属性设置单元格内容的水平位置(左中右),align-items属性设置单元格内容的垂直位置(上中下)。

.container {
  justify-items: start | end | center | stretch;
  align-items: start | end | center | stretch;
}

这两个属性的写法完全相同,都可以取下面这些值。

● start:对齐单元格的起始边缘。

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

● center:单元格内部居中。

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

.container {
  justify-items: start;
}

上面代码表示,单元格的内容左对齐,效果如下图。

.container {
  align-items: start;
}

上面代码表示,单元格的内容头部对齐,效果如下图。

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

place-items: <align-items> <justify-items>;

下面是一个例子。

place-items: start end;

如果省略第二个值,则浏览器认为与第一个值相等。

3.7 justify-content 属性, align-content 属性, place-content 属性

justify-content属性是整个内容区域在容器里面的水平位置(左中右),align-content属性是整个内容区域的垂直位置(上中下)。

.container {
  justify-content: start | end | center | stretch | space-around | space-between | space-evenly;
  align-content: start | end | center | stretch | space-around | space-between | space-evenly;  
}

这两个属性的写法完全相同,都可以取下面这些值。(下面的图都以justify-content属性为例,align-content属性的图完全一样,只是将水平方向改成垂直方向。)

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

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

center - 容器内部居中。

stretch - 项目大小没有指定时,拉伸占据整个网格容器。

space-around - 每个项目两侧的间隔相等。所以,项目之间的间隔比项目与容器边框的间隔大一倍。

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

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

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

place-content: <align-content> <justify-content>

下面是一个例子。

place-content: space-around space-evenly;

如果省略第二个值,浏览器就会假定第二个值等于第一个值。

3.8 grid-auto-columns 属性, grid-auto-rows 属性

有时候,一些项目的指定位置,在现有网格的外部。比如网格只有3列,但是某一个项目指定在第5行。这时,浏览器会自动生成多余的网格,以便放置项目

grid-auto-columns属性和grid-auto-rows属性用来设置,浏览器自动创建的多余网格的列宽和行高。它们的写法与grid-template-columns和grid-template-rows完全相同。如果不指定这两个属性,浏览器完全根据单元格内容的大小,决定新增网格的列宽和行高。

下面的例子里面,划分好的网格是3行 x 3列,但是,8号项目指定在第4行,9号项目指定在第5行。

.container {
  display: grid;
  grid-template-columns: 100px 100px 100px;
  grid-template-rows: 100px 100px 100px;
  grid-auto-rows: 50px; 
}

上面代码指定新增的行高统一为50px(原始的行高为100px)。

3.9 grid-template 属性, grid 属性

grid-template属性是grid-template-columns、grid-template-rows和grid-template-areas这三个属性的合并简写形式。

grid属性是grid-template-rows、grid-template-columns、grid-template-areas、 grid-auto-rows、grid-auto-columns、grid-auto-flow这六个属性的合并简写形式。

从易读易写的角度考虑,还是建议不要合并属性,所以这里就不详细介绍这两个属性了。

项目属性

下面这些属性定义在项目上面。

grid-column-start:定义项目左边框所在的垂直网格线

grid-column-end :定义项目右边框所在的垂直网格线

grid-row-start:上边框所在的水平网格线

grid-row-end:下边框所在的水平网格线

grid-column: grid-column-start和grid-column-end的合并简写形式

grid-row: grid-row-start属性和grid-row-end的合并简写形式

grid-area: 指定项目放在哪一个区域,也可以用作grid-row-start、grid-column-start、grid-row-end、grid-column-end的合并简写形式

justify-self:设置单元格内容的水平位置(左中右)

align-self:设置单元格内容的垂直位置(上中下)

place-self:align-self属性和justify-self属性的合并简写形式。

4.1 grid-column-start 属性, grid-column-end 属性, grid-row-start 属性, grid-row-end 属性

网格中的具体某一个项目的位置是可以指定的,具体方法就是指定项目的四个边框,分别定位在哪根网格线。

● grid-column-start属性:左边框所在的垂直网格线

● grid-column-end属性:右边框所在的垂直网格线

● grid-row-start属性:上边框所在的水平网格线

● grid-row-end属性:下边框所在的水平网格线

.item-1 {
  grid-column-start: 2;
  grid-column-end: 4;
}

上面代码指定,1号项目的左边框是第二根垂直网格线,右边框是第四根垂直网格线。

上图中,只指定了1号项目的左右边框,没有指定上下边框,所以会采用默认位置,即上边框是第一根水平网格线,下边框是第二根水平网格线。

除了1号项目以外,其他项目都没有指定位置,由浏览器自动布局,这时它们的位置由容器的grid-auto-flow属性决定,这个属性的默认值是row,因此会"先行后列"进行排列。读者可以把这个属性的值分别改成column、row dense和column dense,看看其他项目的位置发生了怎样的变化。

下面的例子是指定四个边框位置的效果。

.item-1 {
  grid-column-start: 1;
  grid-column-end: 3;
  grid-row-start: 2;
  grid-row-end: 4;
}

这四个属性的值,除了指定为第几个网格线,还可以指定为网格线的名字

.item-1 {
  grid-column-start: header-start;
  grid-column-end: header-end;
}

上面代码中,左边框和右边框的位置,都指定为网格线的名字。

这四个属性的值还可以使用span关键字,表示"跨越",即左右边框(上下边框)之间跨越多少个网格。

.item-1 {
  grid-column-start: span 2;
}

上面代码表示,1号项目的左边框距离右边框跨越2个网格。

这与下面的代码效果完全一样。

.item-1 {
  grid-column-end: span 2;
}

使用这四个属性,如果产生了项目的重叠,则使用z-index属性指定项目的重叠顺序。

4.2 grid-column 属性, grid-row 属性

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

.item {
  grid-column: <start-line> / <end-line>;
  grid-row: <start-line> / <end-line>;
}

下面是一个例子。

.item-1 {
  grid-column: 1 / 3;
  grid-row: 1 / 2;
}
/* 等同于 */
.item-1 {
  grid-column-start: 1;
  grid-column-end: 3;
  grid-row-start: 1;
  grid-row-end: 2;
}

上面代码中,项目item-1占据第一行,从第一根列线到第三根列线。

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

.item-1 {
  background: #b03532;
  grid-column: 1 / 3;
  grid-row: 1 / 3;
}
/* 等同于 */
.item-1 {
  background: #b03532;
  grid-column: 1 / span 2;
  grid-row: 1 / span 2;
}

上面代码中,项目item-1占据的区域,包括第一行 + 第二行、第一列 + 第二列。

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

.item-1 {
  grid-column: 1;
  grid-row: 1;
}

上面代码中,项目item-1占据左上角第一个网格。

4.3 grid-area 属性

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

.item-1 {
  grid-area: e;
}

上面代码中,1号项目位于e区域,效果如下图。

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

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

下面是一个例子

.item-1 {
  grid-area: 1 / 1 / 3 / 3;
}

4.4 justify-self 属性, align-self 属性, place-self 属性

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

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

.item {
  justify-self: start | end | center | stretch;
  align-self: start | end | center | stretch;
}

这两个属性都可以取下面四个值。

● start:对齐单元格的起始边缘。

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

● center:单元格内部居中。

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

下面是justify-self: start的例子。

.item-1  {
  justify-self: start;
}

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

place-self: <align-self> <justify-self>;

下面是一个例子。

place-self: center center;

如果省略第二个值,place-self属性会认为这两个值相等。

如何实现垂直水平居中

liuyib.github.io/2020/04/07/…(额外补充)

yanhaijing.com/css/2018/01…

github.com/sisterAn/bl…

不知道子元素宽高大小仍能实现水平垂直居中的方法有:

  • absolute定位+transform
  • flex布局
  • grid布局
  • table布局

行内元素: line-height + text-align

行内元素设置垂直水平居中:

line-height等于height值

text-align:center

absolute+负margin

为absolute元素设置 top: 50% + margin-top 负值,具体大小为该元素高度的一半。以及left: 50% + margin-left 负值。

<style>
  .outer {
    position: relative;
    width: 300px;
    height: 300px;
    background: red;
  }
  
  .inner {
    position: absolute;
    width: 100px;
    height: 100px;
    background: yellow;
    left: 50%;
    top: 50%;
    margin-left: -50px;
    margin-top: -50px;
  }
</style>
<div class="outer">
  <div class="inner">
    12345
  </div>
</div>

缺点:需要知道子元素的宽高

absolute + calc

子元素设置 position: absolute,子元素设置固定宽度、高度。

设置top和calc属性

top: calc(50% - 50px); /* 上边距为容器高度的一半减去元素高度的一半 */

left: calc(50% - 100px); /* 左边距为容器宽度的一半减去元素宽度的一半 */

.outer {
  position: relative;
  width: 300px;
  height: 300px;
  background: red;
}

.inner {
  position: absolute;
  width: 200px;
  height: 200px;
  background: yellow;
  left: calc(50% - 100px);
  right: calc(50% - 100px);
}

缺点: 兼容性依赖于calc,并且需要知道子元素的宽高

absolute+ margin auto(不需要知道元素宽高)

子元素设置 position: absolute,子元素设置固定宽度、高度;top、left、bottom、right都设置为0,margin设置为auto

<style>
		.outer {
			position: relative;
			width: 300px;
			height: 300px;
			background: red;
		}

		.inner {
			position: absolute;
			width: 200px;
			height: 200px;
			background: yellow;
			left: 0;
			right: 0;
			top: 0;
			bottom: 0;
			margin: auto;
  }
</style>
<div class="outer">
		<div class="inner">
			12345
		</div>
</div>

absolute + transform(不需要知道元素宽高)

子元素设置 position: absolute,top、left设置为50%,

设置transform: translate(-50%, -50%);

.outer {
  position: relative;
  width: 300px;
  height: 300px;
  background: red;
}

.inner {
  position: absolute;
  width: 200px;
  height: 200px;
  background: yellow;
  transform: translate(-50%, -50%);
  top: 50%;
  left: 50%;
}

无需知道子元素宽高

table(不需要知道元素宽高)

利用了CSS的表格布局特性,结合display: table-cell;、text-align: center;和vertical-align: middle;属性来实现垂直和水平居中。

display: table-cell;:将元素显示为表格单元格,这使得vertical-align: middle;属性能够生效。

text-align: center;:水平居中对齐元素内部文本或内联元素。

vertical-align: middle;:垂直居中对齐元素内部文本或内联元素。

.outer {
  width: 300px;
  height: 300px;
  background: red;
  display: table-cell;
  text-align: center;
  vertical-align: middle;
}
.inner {
  display: inline-block;
  width: 200px;
  height: 200px;
  background: yellow;
}

不需要知道子元素宽高

flex布局(不需要知道元素宽高)

父盒子设置属性:

方式一:

display:flex 定义flex容器

justify-content:center 设置主轴对齐方式为居中,默认是横轴

align-items:center 设置纵轴对齐方式为居中,默认是纵轴

.outer {
  display: flex;
  width: 300px;
  height: 300px;
  justify-content: center;
  align-items: center;
  background: red;
}

.inner {
  width: 100px;
  height: 100px;
  background: yellow;
}

方式二:

父元素设置display: flex,子元素设置margin: auto

.outer {
  display: flex;
}

.inner {
  margin: auto;
}

grid布局(不需要知道元素宽高)

方式一:

可以父盒子指定子元素的对齐方式来实现垂直水平居中。

display: grid;定义了一个网格容器

align-content: center;设置项目的垂直对齐方式为居中

justify-content: center;设置项目的水平对齐方式为居中。

justify-content属性是整个内容区域在容器里面的水平位置(左中右),align-content属性是整个内容区域的垂直位置(上中下)。

方式二:

也可以子元素自己指定对齐方式

父元素设置display:grid

子元素设置

align-self: center;

justify-self: center;

// 父元素指定子元素对齐方式
.outer {
  display: grid;
  align-content: center;
  justify-content: center;
  width: 300px;
  height: 300px;
  background: red;
}
.inner {
  width: 200px;
  height: 200px;
  background: yellow;
}

// 子元素自己指定对齐方式
.outer {
  display: grid;
  width: 300px;
  height: 300px;
  background: red;
}
.inner {
  width: 200px;
  height: 200px;
  align-self: center;
  justify-self: center;
  background: yellow;
}

方式三:

父元素设置为display:grid,垂直居中元素设置外边距 margin 为自适应 auto 即可

outer {
  border: 1px solid red;
  width: 300px;
  height: 200px;
  display: grid;
}
.inner {
  border: 1px solid blue;
  background-color: yellow;
  margin: auto;
}

writing-mode

writing-mode 可以改变文字显示方向,利用这一特性,为了居中元素,需要嵌套两层父元素。

使用了两个元素 .outer 和 .inner,分别设置了不同的 writing-mode 属性,以实现垂直和水平居中效果。

对于 .outer 元素:

  • 我们将其 writing-mode 属性设置为 vertical-lr,意味着文字从上到下,从左到右书写。
  • 同时,我们设置了 text-align: center;,使得内部文本在水平方向上居中。

对于 .inner 元素:

  • 我们将其 writing-mode 属性设置为 horizontal-tb,意味着文字从左到右,从上到下书写(即水平排列)。
  • 同样,我们也设置了 text-align: center;,使得内部文本在水平方向上居中。

这样一来,.outer 元素内的文本是垂直排列并水平居中的,而 .inner 元素内的文本是水平排列并水平居中的。通过组合不同的 writing-mode 属性和 text-align 属性,我们实现了垂直和水平居中效果。

<div class="outer">
  <div class="inner">
    <div class="content"></div>
  </div>
</div>
.outer {
  writing-mode: vertical-lr;
  text-align: center;
}

.inner {
  display: inline-block;
  width: 100%;
  height: auto;
  writing-mode: horizontal-tb;
  text-align: center;
}

.content {
  display: inline-block;
  text-align: left; /* 重置文字位置(如果需要) */
}

如何实现水平居中

下面介绍只适用于水平居中的方案:

  1. margin: auto
  2. text-align + inline-block
  3. fit-content + margin

行内元素:text-align: center

  <div class="parent">
    <span class="child">111</span>
  </div>

居中方法:给其父元素设置text-align: center;

margin: 0 auto(定宽)

宽度已知的情况下可以使用margin:0 auto,让元素水平居中。

该方案的原理是:元素被设置成块级后,会独占一行,如果其宽度没有占满横向空间,那么剩余的空间就处于待分配状态,此时设置 margin: auto; 意味着把剩余的空间分配给 margin,并且左右均分,所以就实现了水平居中。

<div id="parent">
    <div id="child">我是行内元素</div>
</div>
.parent {
  height: 300px;
  width: 400px;
  background:  #fcc;
}
.child {
  display: block; 
  height: 100px;
  width: 100px; //确保该块级元素定宽
  background: #f66;
  margin: 0 auto;
}

text:align + inline-block(不定宽)


/* 这里引用复用代码 */

.outer {
  text-align: center;
}

.inner {
  display: inline-block;
  text-align: left; /* 重置文字位置(如果需要) */
}

该方案的原理是:上面代码中的 text-align: center; 会使文本居中,但是对块级元素无效,如果将元素设置为 inline-block,该元素就会被当做文本对待,从而实现元素居中。

缺点:为了居中元素,使文本也居中了,因此可能需要重置文本位置。

优点:不需要固定居中元素的宽

fit-content + margin:auto

方式一:直接为父元素设置

/* 这里引用复用代码 */

.outer {
  width: fit-content;
  margin: auto;
}

outer 元素的宽度被限制为其内容的适合宽度,然后通过将左右外边距设置为 auto,实现了将该元素水平居中显示的效果。

方式二:直接应用于元素上,缺点:会使元素的宽度改变(同内容宽度)。

/* 这里引用复用代码 */

.inner {
  width: fit-content;
  margin: auto;
}

子元素设置为table + margin: 0 auto

先将子元素设置为块级表格来显示(类似),再将其设置水平居中display:table在表现上类似block元素,但是宽度为内容宽。

<div class="parent">
  <div class="child">我是块级元素</div>
</div>
.parent {
  height: 300px;
  width: 400px;
  background:  #fcc;
}
.child {
  display: table;
  background: #f66;
  margin: 0 auto;
}

absolute + 负margin

首先设置父元素为相对定位,再设置子元素为绝对定位,首先设置子元素的left:50%,然后通过向左移动子元素的一半宽度以达到水平居中。

对于absolute元素:left: 50% 以及margin-left取负值,大小为子元素宽度的一半

<style>
  .outer {
    position: relative;
    width: 300px;
    height: 300px;
    background: red;
  }
  
  .inner {
    position: absolute;
    width: 100px;
    height: 100px;
    background: yellow;
    left: 50%;
    margin-left: -50px;
  }
</style>
<div class="outer">
  <div class="inner">
    12345
  </div>
</div>

absolute + calc

子元素设置 position: absolute,子元素设置固定宽度、高度。

通过calc计算left属性的值为50% - 子元素宽度的一半

left: calc(50% - 100px); /* 左边距为容器宽度的一半减去元素宽度的一半 */

.outer {
  position: relative;
  width: 300px;
  height: 300px;
  background: red;
}

.inner {
  position: absolute;
  width: 200px;
  height: 200px;
  background: yellow;
  left: calc(50% - 100px);
}

absolute + margin: 0 auto(不需要知道子元素宽)

通过子元素绝对定位,设置left、right为0,外加margin: 0 auto来实现。

<div class="parent">
  <div class="child">我是块级元素</div>
</div>
.parent {
  height: 300px;
  width: 400px;
  position: relative;
  background:  #fcc;
}
.child {
  position: absolute;
  background: #f66;
  width: 200px;
  height: 100px;
  margin: 0 auto; /*水平居中*/
  left: 0; /*此处不能省略,且为0*/
  right: 0;/*此处不能省略,且为0*/
}

absolute + transform(不需要知道子元素宽)

首先设置父元素为相对定位,再设置子元素为绝对定位,首先设置子元素的left:50%,然后通过向左移动子元素的一半宽度以达到水平居中。

transform: translateX(-50%)

<div class="parent">
    <div class="child">我是块级元素</div>
</div>
.parent {
  height: 300px;
  width: 400px;
  position: relative;
  background:  #fcc;
}
.child {
  position: absolute;
  background: #f66;
  left: 50%;
  transform: translateX(-50%);
}

flex(不需要知道子元素宽)

使用flexbox布局,只需要给待处理的块状元素的父元素添加属性 display: flex、 justify-content: center

justify-content:center 设置主轴对齐方式为居中,默认是横轴

.parent {
  height: 300px;
  width: 400px;
  display: flex;
  justify-content: center;
  background:  #fcc;
}
.child {
  height: 100px;
  width: 100px;
  background: #f66;
}

如何实现垂直居中

行内元素:line-height等于height

使用padding实现子元素的垂直居中

给父元素设置相等的上下内边距,子元素自然是垂直居中的,当然这时候父元素是不能设置高度的,要让它自动被填充起来,除非设置了一个正好等于上内边距+子元素高度+下内边距的值,否则无法精确垂直居中。

<div id="box">
    <div id="child"></div>
</div>
#box {
    width: 300px;
    background: #ddd;
    padding: 100px 0;
}
#child {
    width: 200px;
    height: 100px;
    background: orange;
}

inline-block + line-height

元素的 height 和 line-height 相同的时候,会使其文本内容垂直居中。因此该方案利用了这一特点,不过文本内容虽然垂直居中了,但是元素并没有,因此再将元素设置为 inline-block,这样元素就会被当做文本对待了。同时由于具有了 inline 属性,vertical-align: middle; 也就可以生效了。

/* 这里引用复用代码 */

.outer {
  line-height: 300px;
}

.inner {
  line-height: initial; /* 重置 */
  vertical-align: middle;
  display: inline-block;
}

缺点:需要知道其父元素高度

优点:不需要固定居中元素的高。

inline-block + vertical-align

.outer::after {
  content: "";
  display: inline-block;
  vertical-align: middle;
  height: 100%;
}

.inner {
  display: inline-block;
  vertical-align: middle;
}

该方案的原理是:在居中元素的父元素上,使用一个伪元素,将这个伪元素设置为 inline-block 后,就好像它原来就是一个真正的 DOM 元素,存在于页面上。然后再将居中元素设置为 inline-block,根据 inline-block 的特性(多个相邻的 inline-block 元素会横向并排显示),居中元素会和伪元素横向并排显示。并且设置 vertical-align: middle; 后,它们会互相垂直对齐,最后将伪元素高度撑起来 height: 100%;,居中元素会对齐伪元素,从而实现了垂直居中。

优点:不需要固定居中元素的高。

使用 line-height 和 vertical-align 对图片进行垂直居中

对一张图片垂直居中,可以为父元素设置line-height等于height,图片设置vertical-align:middle来实现图片居中。

<div id="box">
    <img src="smallpotato.jpg">
</div>
#box{
    width: 300px;
    height: 300px;
    background: #ddd;
    line-height: 300px;
}
#box img {
    width: 200px;
    height: 200px;
    vertical-align: middle;
}

absolute + top/负margin-top

为absolute元素设置 top: 50% + margin-top 负值,具体大小为该元素高度的一半。

#box {
    width: 300px;
    height: 300px;
    background: #ddd;
    position: relative;
}
#child {
    width: 150px;
    height: 100px;
    background: orange;
    position: absolute;
    top: 50%;
    margin: -50px 0 0 0; 
}

absolute + calc

子元素设置 position: absolute,子元素设置固定宽度、高度。

利用calc计算top属性的值

top: calc(50% - 50px); /* 上边距为容器高度的一半减去元素高度的一半 */

absolute + margin: auto(不定宽高)

通过子元素绝对定位,设置top、bottom为0,外加margin: auto(此处写margin: 0 auto 不好使)来实现。

这种实现方式的两个核心是:把要垂直居中的元素相对于父元素绝对定位,top和bottom设为相等的值,我这里设成了0,当然也可以设为 99999px 或者 -99999px 无论什么,只要两者相等就行,这一步做完之后再将要居中元素的 margin 属性值设为 auto,这样便可以实现垂直居中了。

被居中元素的宽高也可以不设置,但不设置的话就必须是图片这种自身就包含尺寸的元素,否则无法实现。

 <div class="parent">
    <div class="child">我是块级元素</div>
  </div>
  .parent {
    height: 300px;
    width: 400px;
    position: relative;
    background:  #fcc;
  }
  .child {
    position: absolute;
    background: #f66;
    width: 200px;
    height: 100px;
    top: 0;
    bottom: 0;
    margin: auto;
  }

absolute + transform(不定宽高)

子元素设置 position: absolute,top设置为50%,

设置transform: translateY(-50%);

<div class="parent">
    <div class="child">我是块级元素</div>
</div>
  .parent {
    height: 300px;
    width: 400px;
    position: relative;
    background:  #fcc;
  }
  .child {
    position: absolute;
    background: #f66;
    width: 200px;
    height: 100px;
    top: 50%;
    transform: translateY(-50%)
  }

flex布局(不定宽高)

使用flexbox布局,只需要给待处理的块状元素的父元素添加属性 display: flex、 justify-content: center

align-items: center;设置交叉轴对齐方式为居中,默认是纵轴

.parent {
  height: 300px;
  width: 400px;
  display: flex;
  align-items: center;
  background:  #fcc;
}
.child {
  height: 100px;
  width: 100px;
  background: #f66;
}

grid布局(不定宽高)

可以父盒子指定子元素的对齐方式来实现垂直水平居中。

display: grid;定义了一个网格容器

align-content: center;设置项目的垂直对齐方式为居中

  <div class="parent">
    <div class="child">我是块级元素</div>
  </div>
.parent {
    height: 300px;
    width: 400px;
    background:  #fcc;
    display: grid;
    align-content: center;
  }
.child {
  background: #f66;
  width: 200px;
  height: 100px;
}

也可以通过子元素自己指定对齐方式

父元素设置display:grid

子元素设置align-self: center;、

align-self: center;:使用align-self属性将.child元素垂直居中。align-self属性用于覆盖其父网格容器中的align-items属性,并使子元素在交叉轴(垂直方向)上居中。

  .parent {
    height: 300px;
    width: 400px;
    background:  #fcc;
    display: grid;
  }
  .child {
    background: #f66;
    width: 200px;
    height: 100px;
    align-self: center;
  }

table布局+vertical-align(不定高)

/* 这里引用复用代码 */

.outer {
  display: table-cell;
  vertical-align: middle;
}

flex布局可以设置item子元素顺序吗

可以,通过flex布局中的项目属性order来控制flex容器中项目的顺序。默认情况下,项目order值为0,可以为项目设置一个正数或负数的order来改变它们的顺序。较小order的项目会排在前面。

background-size有哪些属性

juejin.cn/post/684490…

background-size用于指定背景图片的大小,可以接受如下值:

auto: 默认值,保持背景图片的原始尺寸

<length>:可以使用长度单位来指定背景图片的宽度和高度,不能为负值。

<percentage>: 可以使用百分比来指定背景图片的宽度和高度,相对于背景区域的百分比。

cover: 将背景图片缩放,使其完全覆盖背景区域,同时保持宽高比不变。如果背景图片和背景区域的宽高比不同,那么背景图片会被裁减以适应背景区域

contain: 将背景图片缩放,使其完全适应背景区域,同时保持宽高比不变,如果背景图片和背景区域的宽高比不同,背景区域会被留白。

伪元素和伪类的区别

伪元素和伪类都是CSS中的选择器,它们允许在不改变HTML结构的情况下为特定元素或元素的一部分应用样式。

伪类:用于根据元素的状态来选择元素并添加特殊效果,例如鼠标悬停状态:hover,选中状态:checked或是否被访问过 :visited等,伪类通常用于为元素添加一些交互效果。

伪元素:用于创建一些不在文档树中的元素,并为它们应用样式。可以使用::before::after伪元素来在指定元素内容的前后插入新内容。或者使用::first-letter::first-line伪元素来为文本的首字母或首行设置特殊样式。

总之,伪类和伪元素的主要区别在于它们选择的对象不同,伪类选择的是已经存在于文档树中的元素,伪元素则是创建了一些新元素。

什么是伪类?有什么作用

伪类用于根据元素的状态来选择元素并添加特殊效果,例如鼠标悬停状态:hover,选中状态:checked或是否被访问过 :visited等,伪类通常用于为元素添加一些交互效果。

常见的伪类按照功能,可划分为以下几类:

  • 动态伪类::visited、:focus、:hover等

  • 状态伪类::disabled、:empty、:required 等

  • 结构伪类::first-child、:nth-of-type等

  • 其他伪类::target、:lang、:not()等

下面的表格详细记录了各种伪类及其描述:

伪类描述兼容性
:active元素处于活动状态时
:focus元素已获取焦点时
:hover元素处于悬浮状态时
:link链接未访问时
:visited链接已访问时
:first-child元素是首个子元素时
:last-child元素是最后一个子元素时
:nth-child()元素是第 n 个子元素时
:nth-last-child()元素是倒数第 n 个子元素时
:only-child元素是唯一子元素时
:first-of-type元素是首个特定类型的子元素时
:last-of-type元素是最后一个特定类型的子元素时
:nth-of-type()元素是第 n 个特定类型的子元素时
:nth-last-of-type()元素是倒数第 n 个特定类型的子元素时
:only-of-type元素是唯一的特定类型的子元素时
:not不满足指定条件时
:target元素 id 匹配到哈希值时
:root元素是文档树的根元素时
:lang()匹配到指定语言时
:empty元素处于没有子元素状态时
:invalid 和 :valid表单项是否有效
:required 和 :optional表单项是否必填
:in-range和 :out-of-range表单项是否超出范围
:read-only和 :read-write表单项是否只读
:enabled和 :disabled表单项是否禁用
:fullscreen当前处于全屏显示模式时⚠️
:blank输入框处于输入为空状态时
:dir()匹配到特定文字书写方向时

上表中的兼容性表示:

  • 代表主流浏览器都支持(至少 95% 以上)
  • 代表大部分主浏览器都不支持(仅 20% 以下浏览器实现该特性)
  • ⚠️ 代表部分浏览器支持(可能需要加前缀,例如 :webkit-或 :-moz-等)

什么是伪元素?有什么作用

伪元素用于创建一些不在文档树中的元素,并为它们添加特殊效果。

常见的伪元素选择器如下:

伪元素选中或创建出来的元素兼容性
::first-letter选中块状元素中的首字母
::first-line选中首行
::before在之前创建一个不在文档树中的元素
::after在之后创建一个不在文档树中的元素
::placeholder选中表单元素的占位文本
::file-selector-button选中类型为 file 的 input 里面的 button
::selection选中被用户高亮的部分⚠️
::backdrop选中视觉聚焦元素后面的背景元素⚠️
::marker选中 list 的 marker⚠️

如果用js修改元素位置,推荐使用requestAnimationFrame这个API

line-height如何继承

line-height有三种方式可以赋值,具体数值、比例、百分比

line-height为具体数值,如 30px,则继承该值(比较好理解 )

line-height为比例,如 2/1.5,则继承该比例,用子元素自己的font-size * 比例(比较好理解 )

line-height为百分比,如 200%,则继承计算出来(父元素font-size*百分比)的值(考点 )

具体数值:如果line-height直接写具体数值,如15px,则直接继承。

<style type="text/css">
  body {
    font-size: 20px;
    line-height: 15px;
  }
  p {
    background-color: #ccc;
    font-size: 16px;
  }
</style>

<body>
  <p>一行文字</p>
</body>

如果line-height具体的值是一个比例,如2,那么直接继承该比例

<style type="text/css">
  body {
    font-size: 20px;
    line-height: 2;
  }
  p {
    background-color: #ccc;
    font-size: 16px;
  }
</style>

<body>
  <p>一行文字</p>
</body>

所以p的line-height为32px,16px * 2

如果line-height是一个百分比,如200%,则继承根据父元素计算出来的值

<style type="text/css">
  body {
    font-size: 20px;
    line-height: 200%;
  }
  p {
    background-color: #ccc;
    font-size: 16px;
  }
</style>

<body>
  <p>一行文字</p>
</body>

所以p元素的line-height等于40px,即 20px * 200%

如何实现两栏布局

双栏布局非常常见,往往是以一个定宽栏和一个自适应的栏并排展示存在。假设左边栏固定,右边栏自适应。

left浮动+right部分margin-left

实现思路也非常的简单:

  • 使用 float 左浮左边栏
  • 右边模块使用 margin-left 撑出内容块做内容展示
  • 为父级元素添加BFC,防止下方元素飞到上方内容
<style>
    .box{
        overflow: hidden; 添加BFC
    }
    .left {
        float: left;
        width: 200px;
        background-color: gray;
        height: 400px;
    }
    .right {
        margin-left: 210px;
        background-color: lightgray;
        height: 200px;
    }
</style>
<div class="box">
    <div class="left">左边</div>
    <div class="right">右边</div>
</div>

left浮动+right部分overflow:hidden

实现思路:

  • 使用 float 左浮左边栏
  • 右边模块添加新的BFC

这种方法不需要为right部分添加margin-left外边距

<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <style>
    .left {
      width: 100px;
      height: 150px;
      float: left;
      background: gray;
    }

    .right {
      height: 300px;
      background: rgb(170, 54, 236);
      background: yellowgreen;
    }
  </style>
</head>
<body>
  <div class="left">LEFT</div>
  <div class="right">RIGHT</div>
</body>

absolute定位设置好两个盒子的位置

利用绝对定位算好宽高固定好两个盒子的位置。(通过设置top left right来固定盒子位置)

<style>
  .container {
    position: relative;
  }
  .left {
    position: absolute;
    left: 0;
    top: 0;
    height: 400px;
    width: 200px;
    background-color: gray;
  }
  .right {
    position: absolute;
    top: 0;
    right: 0;
    left: 200px;
    height: 300px;
    background-color: pink;
  }
</style>
</head>
<body>
  <div class="container">
    <div class="left">左边</div>
    <div class="right">右边</div>
  </div>
</body>

缺点:

脱离文档流

固定宽度元素的 width 需要与自适应元素的反方向值对应,如 left

flex布局实现

<style>
  .container {
    display: flex;
    align-items: flex-start;
  }
  .left {
    height: 400px;
    width: 200px;
    background-color: gray;
  }
  .right {
    height: 300px;
    background-color: pink;
    flex: 1;
  }
</style>
</head>
<body>
  <div class="container">
    <div class="left">左边</div>
    <div class="right">右边</div>
  </div>
</body>

注意的是,flex容器的一个默认属性值:align-items: stretch;

这个属性导致了列等高的效果。 为了让两个盒子高度自动,需要设置: align-items: flex-start

grid布局

通过设置父容器为grid布局,并设置columns。

<style>
    .container {
      display: grid;
      grid-template-columns: 200px auto;
      width: 100%;
    }
    .left {
      height: 200px;
      background-color: gray;
    }
    .right {
      height: 400px;
      background-color: pink;
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="left">左边</div>
    <div class="right">右边</div>
  </div>
</body>

如何实现三栏布局

实现三栏布局中间自适应的布局方式有:

  • 左中右使用float,中间部分使用calc计算宽度
  • 左右使用 float,中间使用 margin(中间内容放在html结构最后)
  • 左右使用 absolute,中间使用 margin
  • 圣杯布局
  • 双飞翼布局
  • flex实现
  • grid网格布局

左中右float,中间部分calc计算宽度

left、middle设置左浮动,right设置右浮动。中间部分通过calc计算宽度来实现自适应。

<style>
        div {
          height: 100px;
        }
        .left {
            float: left;
            width: 200px;
            background-color: red;
        }
        .middle {
            float: left;
            width: calc(100% - 400px);
            background-color: green;
        }
        .right {
            float: right;
            width: 200px;
            background-color: blue;
        }
       
    </style>
</head>
<body>
    <div class="container">
        <div class="left">左边</div>
        <div class="middle">中间</div>
        <div class="right">右边</div>
    </div>    
</body>

左右使用 float,中间使用 margin

左右两栏使用 float 浮动到相应位置

中间栏通过 margin 属性进行撑开,注意:中间部分要在HTML结构的最后

<style>
  .box {
    /* 应用浮动记得清除浮动 */
    overflow: hidden;
  }
  .left {
    float: left;
    width: 200px;
    height: 200px;
    background-color: gray;
  }
  .right {
    float: right;
    width: 200px;
    height: 200px;
    background-color: pink;
  }
  .middle {
    margin-left: 210px;
    margin-right: 210px;
    background-color: green;
    height: 300px;
  }
</style>
</head>
<body>
  <div class="box">
    <div class="left">左边</div>
    <div class="right">右边</div>
    <div class="middle">中间</div>
  </div>    
</body>

flex布局

容器弹性布局 display: flex

两侧栏设置固定宽度 width

中间栏设置占主轴空间 flex: 1

<style>
  .container {
    display: flex;
  }
  .left {
    float: left;
    width: 200px;
    height: 200px;
    background-color: red;
  }
  .middle {
    float: left;
    height: 200px;
    flex: 1;
    background-color: green;
  }
  .right {
    float: right;
    width: 200px;
    height: 200px;
    background-color: blue;
  }

</style>
</head>
<body>
  <div class="container">
    <div class="left">左边</div>
    <div class="middle">中间</div>
    <div class="right">右边</div>
  </div>    
</body>

grid布局

容器布局 display: grid

容器分栏,两侧固定,中间自适应 grid-template-columns: width auto width

<style>
  .container {
    display: grid;
    grid-template-columns: 200px auto 200px;
  }
  .left {
    float: left;
    height: 200px;
    background-color: red;
  }
  .middle {
    float: left;
    height: 200px;
    background-color: green;
  }
  .right {
    float: right;
    height: 200px;
    background-color: blue;
  }

</style>
</head>
<body>
  <div class="container">
    <div class="left">左边</div>
    <div class="middle">中间</div>
    <div class="right">右边</div>
  </div>    
</body>

圣杯布局

圣杯布局,中间元素优先渲染。实现思路如下:

左中右三部分均设置float浮动(记得清除浮动)

container外层采用padding来为left、right预留空间

left盒子:margin-left: -100% + 相对定位right: 自身宽度

right盒子:margin-right: 负的自身宽度

<style>
  .header {
    background-color: gray;
  }
  .container {
    padding-left: 200px;
    padding-right: 150px;
  }
  .clearfix::after {
    content: "";
    height: 0;
    display: block;
    clear: both;
    visibility: hidden;
  }
  .center {
    float: left;
    width: 100%;
    background-color: red;
  }
  .left {
    float: left;
    width: 200px;
    margin-left: -100%;
    position: relative;
    right: 200px;
    background-color: pink;
  }
  .right {
    float: left;
    width: 150px;
    margin-right: -150px;
    background-color: yellow;
  }
  .footer {
    background-color: goldenrod;
  }
</style>
</head>
<body>
  <div class="header">header</div>
  <div class="container clearfix">
    <div class="center">center</div>
    <div class="left">left</div>
    <div class="right">right</div>
  </div>
  <div class="footer">footer</div>
</body>

双飞翼布局

双飞翼布局也是中间元素优先渲染,实现思路:

  • 内容部分包含center(外层包裹一个div)、left、right
  • 三部分均设置float布局
  • 中间部分的子元素设置margin来为left、right预留空间
  • left盒子:margin-left: 负100%
  • right盒子:margin-left: 负的自身宽度
<style>
  .container {
  }
  .clearfix::after {
    content: "";
    height: 0;
    display: block;
    clear: both;
    visibility: hidden;
  }
  .center {
    float: left;
    width: 100%;
    height: 200px;
    background-color: red;
  }
  .center-wrap {
    height: 200px;
    margin-left: 200px;
    margin-right: 150px;
  }
  .left {
    float: left;
    width: 200px;
    height: 200px;
    background-color: pink;
    margin-left: -100%;
  }
  .right {
    float: left;
    width: 150px;
    height: 200px;
    background-color: yellow;
    margin-left: -150px;
  }
</style>
</head>
<body>
  <div class="container clearfix">
    <div class="center">
      <div class="center-wrap">
        center
      </div>
    </div>
    <div class="left">left</div>
    <div class="right">right</div>
  </div>
</body>