全文主要参考如下github项目,在此基础上补充了一些自己的东西:

https://github.com/febobo/web-interview

项目网站:web前端面试 - 面试官系列

一个非常全面,细致的前端面试题库,十分的推荐,深刻体会到github的强大之处了。

说说css盒模型

浏览器在渲染html元素的时候,会把所有元素表示为一个一个矩形的盒子。

盒模型组成

  • content

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

  • padding

    即内边距,内边距是透明的,取值不能为负,背景图片可以扩展到padding。

  • border

    即边框,由粗细、样式、颜色三部分组成。例如border:1px solid black

  • margin

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

盒模型分类

  • w3c标准盒模型(content-box)

    width/height的范围只包括content,虽说是标准盒模型,怎么感觉没有ie盒模型好用捏。

  • ie盒模型(border-box)

    width/height的范围包括content,border,padding

1
box-sizing: content-box|border-box|inherit;//指定元素使用哪种盒模型来渲染,inherit表示继承父元素盒模型

说说em/px/rem/vh/vw区别

  • em

    是一个相对单位,和rem不同的是,相对的是父元素的字体大小

  • px

    1px即1个css像素,是绝对单位。

  • rem

    是一个相对单位,相对的是根元素html的字体大小。

    如果想要简化font-size的转化,我们可以修改html的字体大小。

    1
    html {font-size: 10px  }
  • vw/vh

    视口的宽高划分为100等份,1vw表示视口宽度的1/100,1vh表示视口高度的1/100,是一个相对单位,相对的是视口的宽/高,而百分比布局相对的是父元素的宽/高

    这里的视口,在PC端指的就是浏览器窗口,在移动端指的就是布局视口,一般就是设备屏幕

    1
    <meta name="viewport" content="width=device-width, initial-scale=1.0"> #指定布局视口宽度为设备宽度

设备像素、css像素、设备独立像素、dpr、ppi 之间的区别

  • css像素

    在web编程中,css代码中的像素,一般1px就是一个css像素

  • 设备像素

    设备像素(device pixels),又称为物理像素,指设备能控制显示的最小物理单位,就是显示屏上的一个一个像素点。

    从屏幕在工厂生产出的那天起,它上面的物理像素点就固定不变了。

    屏幕的分辨率通常为a×b的格式,分别指的是宽,高上的物理像素点的个数。

  • 设备独立像素

    设备独立像素指的是与设备无关的逻辑像素,以通过程序控制使用的虚拟像素,一个设备独立像素可能会对应多个设备像素

    我们在游戏中可以调节游戏的分辨率,实际就是在调节设备独立像素

    在屏幕未缩放情况下(100%),1css像素=1设备独立像素,我们也可以推断出缩放屏幕,其实就是在改变css像素设备独立像素的比例关系

  • dpr

    dpr = 设备像素/设备独立像素,在PC端,dpr = 1,在移动端,dpr>=1

    我们通常讨论的是不缩放的情况下,也就是1css像素就是1设备独立像素,因此dpr又可以被认等于设备像素/css像素

    当设备像素比为1:1时,使用1(1×1)个设备像素显示1个CSS像素

    当设备像素比为2:1时,使用4(2×2)个设备像素显示1个CSS像素

    当设备像素比为3:1时,使用9(3×3)个设备像素显示1个CSS像素

  • PPI

    pixel per inch每英寸像素点的个数,这个PPI越大,说明物理像素点的密度更大,像素点一般也更多,像素点大小也越小,能更细致的展现图像。

    比如,iPhone 3GS 和 iPhone 4/4s 的尺寸都是 3.5 寸,但 iPhone 3GS 的分辨率是 320x480,iPhone 4/4s 的分辨率是 640x960

    这意味着,iPhone 3GS 在上有320个物理像素,iPhone 4/4s 在上有 640 个物理像素,也就是说iPhone 4/4s的PPI更大

    如果我们按照真实的物理像素进行布局,比如说我们按照 320 物理像素进行布局,到了 640 物理像素的手机上就会有一半的空白,为了避免这种问题,就出现了虚拟像素单位

    我们统一 iPhone 3GS 和 iPhone 4/4s 都是 320 个虚拟像素,只是在 iPhone 3GS 上,最终 1 个虚拟像素换算成 1 个物理像素,在 iphone 4s 中,1 个虚拟像素最终换算成 2 个物理像素(DPR=2)

    可以看到光提高PPI还是不够的,为了解决空白问题吗,还要修改DPR

    我们思考一下,为什么原本能用1个物理像素表示的,为了解决空白问题就硬要用2个物理像素表示呢,就非得让屏幕中的所有像素点参与展示吗,这样不就等同于放大图片吗,放大图片不是会变模糊吗,因为图片本身没有这么多细节(分辨率<实际用来渲染的像素数目),所以对于PPI更高的设备,我们要准备分辨率更高的图片(分辨率越高的图片,文件大小越大,占用的物理像素点越多,和屏幕分辨率是一个概念),才能完美的解决空白问题。

    举个例子,我们有50x50分辨率(在PC端,DPR为1的设备,就是50x50px)的图片,放到iPhone 3GS上(DPR=1)会占用50x50像素(物理像素),放到iPhone4/4s上(DPR=2),会占用100*100像素(物理像素),因为图片分辨率 < 实际参与渲染的物理像素,所以会变模糊。

    如果我们放一个 100x100 分辨率(在PC端,DPR为1的设备,就是100x100px)图片,然后手动的把这个图片缩小为 50x50(css像素,即px),放到iPhone4/4s上,会占用100*100像素(物理像素),因为图片分辨率 = 实际参与渲染的物理像素,所以会被清晰的展示。

    所以一般情况下,我们认为PPI越大,图像越清晰,因为我们能用更多更小的像素来渲染图片。

如何实现元素隐藏

  • display:none
    • 能实现元素隐藏,而且元素不再占有原来的位置
    • 会触发页面的重排重绘
    • 元素对应的dom对象仍然存在,无法再响应点击事件
  • visibility:hidden
    • 能实现元素隐藏,而且元素占有原来的位置
    • 只会触发页面的重绘
    • 元素对应的dom对象仍然存在,无法再响应点击事件
  • opacity:0
    • 能实现元素隐藏,而且元素占有原来的位置
    • 元素对应的dom对象仍然存在,且能响应点击事件
    • 一般情况下也会引发重绘

总结

这三种方法都能实现元素隐藏,display:none会让元素不再占有原来的位置,而其他两种则会保留原来的位置。

添加了display:nonevisibility:hidden的元素都无法再响应点击事件,而添加了opacity:0的元素可以。

谈谈你对BFC的理解

什么是BFC

也叫块级格式化上下文,可以理解为css中的一种属性,开启了bfc的盒子,被视为一块独立的渲染区域,内部元素不会影响外部元素的布局,外部元素也不会影响内部元素的布局,这意味着在一个BFC中的元素,不会与该BFC之外的浮动元素重叠,并且它们之间的外边距也不会折叠。

如何开启BFC

  • html标签默认开启了BFC
  • overflow的值不为visible(默认值)的元素,比如我们经常使用overflow:hidden来清除浮动,本质就是开启了BFC。
  • 添加了绝对定位固定定位的元素
  • 开启了浮动的元素
  • 开启了flex布局或者grid布局的元素,这2种布局的内部元素布局方式确实独特,可以理解为开启了一块独立的渲染区域。

开启了BFC有什么作用

  • 可以用来清除浮动

    BFC盒子内部的浮动元素,也参与BFC盒子高度的计算,或者说BFC盒子会完全包裹内部的所有元素,包括浮动元素

    所以浮动元素,绝对定位元素,固定定位元素,不需要担心浮动元素不参与自身高度的计算 。

  • 开启了BFC的元素不会与浮动元素重叠

    这一点体现了布局互不影响的特点,比如浮动元素不会被浮动元素压住。

  • 可以用来解决边距塌陷问题

    如果两个相邻的盒子存在边距塌陷问题,只要让其中一个盒子包裹一个开启了BFC的盒子就能解决边距塌陷问题。

介绍一下flex弹性布局

开启Flex布局的元素(display:flex),称为flex容器container,其实也开启了BFC,它的所有子元素自动成为容器成员,称为flex项目item

容器属性

包括flex-directionflex-wrapflex-flowjustify-contentalign-itemsalign-content

  • flex-direction

    决定主轴的方向,主轴的方向决定了项目的排列方向

    1
    2
    3
    .container {   
    flex-direction: row | row-reverse | column | column-reverse;
    }
    • row(默认值):主轴为水平方向,起点在左端,从左到右摆放
    • row-reverse:主轴为水平方向,起点在右端,从右到左摆放
    • column:主轴为垂直方向,起点在上沿。从上到下摆放
    • column-reverse:主轴为垂直方向,起点在下沿,从下到上摆放

    既然主轴的方向可以通过flex-direction来控制,哪侧轴方向呢?貌似没有哪个属性用来指定侧轴的方向,其实我们可以认为,主轴的方向确定了,侧轴的方向也确定了,且默认是从左到右或者从上到下。

  • flex-wrap

    用来决定子元素一行放不下了是否换行

    1
    2
    3
    .container {  
    flex-wrap: nowrap | wrap | wrap-reverse;
    }
    • nowrap(默认值):默认不换行
    • wrap:换行,第一行在下方
    • wrap-reverse:换行,第一行在上方,有点逆天了。
  • flex-flow

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

    1
    2
    3
    .box {
    flex-flow: <flex-direction> || <flex-wrap>;
    }
  • justify-content

    定义了项目(子元素)在主轴上的对齐方式

    1
    2
    3
    .box {
    justify-content: flex-start | flex-end | center | space-between | space-around;
    }
    • flex-start(默认值):向开始处(start)对齐

    • flex-end:向结束处(end)对齐

    • center:居中对齐

    • space-between:两端对齐,项目之间的间隔都相等

    • space-around:两个项目两侧间隔相等

    1
    2
    3
    4
    5
    <div class="box">
    <div class="a">a</div>
    <div class="b">b</div>
    <div class="c">c</div>
    </div>
  • align-items

    定义子元素如何在侧轴上对齐(垂直于主轴),只适用于只有一根主轴线的时候(如果主轴为row,就是只有一行)

    1
    2
    3
    .box {
    align-items: flex-start | flex-end | center | baseline | stretch;
    }
    • flex-start:交叉轴的起点对齐
    • flex-end:交叉轴的终点对齐
    • center:交叉轴的中点对齐, 就是居中对齐
    • baseline: 项目的第一行文字的基线对齐
    • stretch(默认值,拉伸):如果项目未设置高度或设为auto,将占满整个容器的高度。
  • align-content

    定义多根主轴的对齐方式。如果项目只有一根主轴线(比如主轴是row的时候,只有一行子元素),该属性不起作用,所以说align-items属性和align-content属性不能同时使用。

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

    可以看到,这些属性值和justify-content的属性值是几乎一样的,如果主轴有多根,可以把每根主轴当作侧轴上的一个元素

容器成员属性

  • order

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

    默认情况,子元素的排列顺序是在html文档中的书写顺序,而指定order能改变这个顺序。

    1
    2
    3
    .item {
    order: <integer>;
    }
  • flex-grow

    定义了子元素的放大比例,默认为0,当容器设为flex-wrap: nowrap(默认值);即不换行的时候,如果一行没有占满:

    • flow-grow的值为0,如果一行没有占满,也不放大。

    • 如果子元素flow-grow的值不为0,无论是否指定宽度,都会根据flex-grow的值来分割剩余空间,也就是说flex-grow不会考虑是否指定了宽度。

    • 子元素flex-grow属性都为1,则它们将等分剩余空间。

  • flex-shrink

    定义了子元素的缩小比例(容器宽度<子元素总宽度,且不换行时如何收缩),默认为1

    如果所有子元素的flex-shrink属性都为1,当空间不足时,都将等比例缩小

    如果一个子元素的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    .box {
    width: 250px;
    height: 400px;
    display: flex;
    background-color: antiquewhite;
    }
    .a {
    width: 100px;
    height: 100px;
    background-color: aqua;
    }
    .b {
    width: 100px;
    height: 100px;
    background-color: red;
    }
    .c {
    width: 100px;
    height: 100px;
    background-color: gold;
    }

    可以看到即便子元素指定了宽度,如果一行放不下,也会等比例缩小。我们可以通过修改flex-shrink属性来修改具体的缩小规则。

  • flex-basis

    设置的是元素在主轴上的初始尺寸,所谓的初始尺寸,就是元素在flex-growflex-shrink生效前的尺寸。

    • auto: 默认值,这意味着项目将根据其内容,确定其初始大小,如设置了width/height则元素尺寸由width/height决定
    • 固定值:你可以指定一个具体的长度单位,如像素 (px)、百分比 (%) 等。这会设置项目的初始大小,不考虑内容的自然尺寸。
    • 0:完全依赖flex-grow 来分配多余的空间。这种方式常用于创建等分布局,如果令一个元素的flex-basis:0,由于flex-grow默认为0,此时无论是否指定宽度,在主轴上的宽度都为0
  • flex

    flex属性是flex-grow, flex-shrinkflex-basis的简写,默认值为0 1 auto,也是比较难懂的一个复合属性。

    我们通常的书写方式flex:1修改的是flex-grow的值,即规定了分割剩余空间时的权重或者份数。

  • align-self

    允许侧轴上的单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性,但是不能覆盖align-content的,

    默认值为auto,表示继承父元素的align-items属性。

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

介绍一下grid网格布局

通过display:grid/inline-grid就能开启网格布局

1
2
3
4
5
6
7
<div class="container">
<div class="item item-1">
<p class="sub-item"></p >
</div>
<div class="item item-2"></div>
<div class="item item-3"></div>
</div>

上述代码实例中,.container元素就是网格布局容器,.item元素就是网格的项目,由于网格元素只能是容器的顶层子元素,所以p元素并不是网格元素

同样,Grid 布局属性可以分为两大类:

  • 容器属性
  • 项目属性

容器属性

  • display

    • display:grid 则该容器是一个块级元素
    • display: inline-grid 则容器元素为行内元素
  • grid-template-columns/grid-template-rows

    grid-template-columns 属性设置列宽grid-template-rows 属性设置行高

    1
    2
    3
    4
    5
    6
    7
    8
    .wrapper {
    display: grid;
    /* 声明了三列,宽度分别为 200px 200px 200px */
    grid-template-columns: 200px 200px 200px;
    grid-gap: 5px;
    /* 声明了两行,行高分别为 50px 50px */
    grid-template-rows: 50px 50px;
    }

    以上表示固定列宽为 200px,行高为 50px

    上述代码可以看到重复写单元格宽高,通过使用repeat()函数,可以简写重复的值

    • 第一个参数是重复的次数
    • 第二个参数是重复的

    所以上述代码可以简写成

    1
    2
    3
    4
    5
    6
    .wrapper {
    display: grid;
    grid-template-columns: repeat(3,200px);
    grid-gap: 5px;
    grid-template-rows:repeat(2,50px);
    }

    除了上述的repeact关键字,还有:

    • auto-fill:示自动填充,让一行(或者一列)中尽可能的容纳更多的单元格,只能在repeat函数中使用,用来替代具体的重复次数,而不是宽度或者高度

      1
      2
      //表示列宽是 200 px,但列的数量是不固定的,只要浏览器能够容纳得下,就可以放置更多的列
      grid-template-columns: repeat(auto-fill, 200px)
    • fr:片段,为了方便表示比例关系,非常类似flex布局中的份数,用份数来替代具体的宽高。要注意的是1fr不可写成fr

      1
      2
      //表示第一个列宽设置为 200px,后面剩余的宽度分为两部分,宽度分别为剩余宽度的 1/32/3
      grid-template-columns: 200px 1fr 2fr
    • minmax:产生一个长度范围,表示长度就在这个范围之中都可以应用到网格项目中。第一个参数就是最小值,第二个参数就是最大值,用一个范围来替代具体的宽高。

      minmax(100px, 1fr)表示列宽不小于(>=)100px,不大于(<=)1fr

      1
      grid-template-columns:repeat(auto-fill,minmax(260px,1fr))
    • auto:由浏览器自己决定长度

      1
      2
      //表示第一第三列为 100px,中间由浏览器决定长度
      grid-template-columns: 100px auto 100px
  • gap

    定义宫格之间的间隔

容器成员属性

….

CSS如何画一个三角形

可以通过指定边框(border)样式实现。

1
2
3
4
5
6
.border {
width: 50px;
height: 50px;
border: 50px solid;
border-color: #96ceb4 #ffeead #d9534f #ffad60;
}

这样一个盒子的样式如下:

当盒子的宽高不断减小,那每个边框是不是就会变成一个三角形呢?

这样会得到四个三角形,但是我们只要一个,我们可以把其他边框的颜色变透明,但是这样隐藏的部分仍然占据部分高度

比如我们只要下面的三角形,那我们就可以让上边框的的宽度变为0,效果就是这样。

然后再让左右边框变为透明的就好了。

1
2
3
4
5
6
7
.border {
width: 0;
height: 0;
border-style: solid;
border-width: 0 50px 50px 50px;
border-color: transparent transparent #d9534f transparent;
}

如何实现元素水平居中,垂直居中

水平居中

  • 行内元素/行内块元素

    • 给父元素添加text-align:center

    • 给父元素添加flex布局

      1
      2
      display: flex; 
      justify-content: center;
    • 给自身添加绝对定位

      1
      2
      3
      position: absolute;
      left: 50%;
      transform: translateX(-50%);
  • 块级元素

    • 添加margin: 0 auto,要求块级元素的宽度确定

    • 给父元素添加flex布局

      1
      2
      display: flex; 
      justify-content: center;
    • 给自身添加绝对定位

      1
      2
      3
      position: absolute;
      left: 50%;
      transform: translateX(-50%);

垂直居中

  • 行内元素

    • 指定行内元素的行高line-height为父元素高度。

    • 给父元素添加flex布局

      1
      2
      display: flex; 
      align-items: center;
    • 给自身添加绝对定位

      1
      2
      3
      position: absolute;
      top: 50%;
      transform: translateY(-50%);
  • 行内块元素/块级元素

    • 给父元素添加flex布局

      1
      2
      display: flex; 
      align-items: center;
    • 给自身添加绝对定位

      1
      2
      3
      position: absolute;
      top: 50%;
      transform: translateY(-50%);

总结

绝对定位flex布局是万能的。margin:0 autotext-align:centerline-height:父元素高度,是一些特殊情况。

说说对CSS预处理语言的理解?有哪些区别?

背景

  • CSS代码看起来是没有逻辑性的,不方便维护及扩展,不利于复用css预处理语言在css的基础上,添加了变量混入嵌套等功能,让css代码看起来更有逻辑性,更容易维护和复用。

  • css预处理语言包括一套自定义的语法和一个解析器,解析器会把用自定义语法编写的代码转化成css代码

常见的css预编译语言

  • sass

    2007 年诞生,最早也是最成熟的 Css预处理器,拥有 Ruby 社区的支持和 Compass 这一最强大的 Css框架,目前受 LESS 影响,已经进化到了全面兼容 CssScss

    sass和scss的区别与联系

    • 是同一种css预处理语言(sass)的两种不同语法形式,它们都扩展了标准的 CSS,虽然有不同的自定义语法,但是使用同一个解析器(编译器)来处理
    • sass使用缩进来表示代码块,不使用大括号 {} 和分号 ;更接近 Python 的风格,强调简洁性和可读性。文件使用 .sass 扩展名
    • scss与 CSS 的语法几乎完全相同,所以更容易被现有开发者接受和使用。文件使用 .scss 扩展名
  • less

    2009年出现,受SASS的影响较大,但又使用 Css 的语法,让大部分开发者和设计师更容易上手,在 Ruby社区之外支持者远超过 SASS

    其缺点是比起 SASS来,可编程功能不够,不过优点是简单和兼容 Css,反过来也影响了 SASS演变到了Scss 的时代

常用特性

  • 嵌套

    二者的嵌套语法都是一致的,甚至连引用父级选择器的标记 & 也相同

    区别只是 Sass可以用没有大括号的方式书写(用缩进)

    1
    2
    3
    4
    5
    .a {
    &.b {
    color: red;
    }
    }
  • 变量

    变量的出现有效的提高了css代码复用性,减少了不必要的硬编码

    less声明的变量必须以@开头,后面紧跟变量名和变量值,而且变量名和变量值需要使用冒号:分隔开

    1
    2
    3
    4
    @red: #c00;
    strong {
    color: @red;
    }

    sass声明的变量跟less十分的相似,只是变量名前面使用$开头

    1
    2
    3
    4
    5
    $red: #c00;

    strong {
    color: $red;
    }
  • 作用域

    在css预处理语言中,变量是具有作用域的。

    sass中所有定义的变量都在全局作用域中,没有局部作用域。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    $color: black;
    .scoped {
    $bg: blue;
    $color: white;
    color: $color;
    background-color:$bg;
    }
    .unscoped {
    color:$color;
    }

    编译后

    1
    2
    3
    4
    5
    6
    7
    .scoped {
    color:white;/*是白色*/
    background-color:blue;
    }
    .unscoped {
    color:white;/*白色(无全局变量概念)*/
    }

    所以,在sass中最好不要定义相同的变量名,后面定义的会覆盖前面定义的。

    less的变量作用域跟javascript十分的相似,有局部变量全局变量之分。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @color: black;
    .scoped {
    @bg: blue;
    @color: white;
    color: @color;
    background-color:@bg;
    }
    .unscoped {
    color:@color;
    }

    编译后:

    1
    2
    3
    4
    5
    6
    7
    .scoped {
    color:white;/*白色(调用了局部变量)*/
    background-color:blue;
    }
    .unscoped {
    color:black;/*黑色(调用了全局变量)*/
    }
  • 混入

    Mixins可以将一部分样式抽出,作为单独定义的模块,被很多选择器重复使用,可以说是css预处理语言的精髓所在。

    less中的用法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    .alert {
    font-weight: 700;
    }
    //这不是在定义函数吗
    .highlight(@color: red) {
    font-size: 1.2em;
    color: @color;
    }

    .heads-up {
    .alert;
    //函数调用?
    .highlight(red);
    }

    编译后

    1
    2
    3
    4
    5
    6
    7
    8
    .alert {
    font-weight: 700;
    }
    .heads-up {
    font-weight: 700;
    font-size: 1.2em;
    color: red;
    }

    Sass声明mixins时需要使用@mixin,后面紧跟mixin的名,也可以设置参数,参数名为变量$声明的形式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    @mixin large-text {
    font: {
    family: Arial;
    size: 20px;
    weight: bold;
    }
    color: #ff0000;
    }

    .page-title {
    @include large-text;
    padding: 4px;
    margin-top: 10px;
    }
  • 代码模块化

    模块化就是将复杂的Css代码按某种规则划分为一个个文件,每个文件就是一个模块,模块可以通过@import引入

    scssless二者的使用方法都如下所示。

    1
    2
    3
    4
    @import './common';
    @import './github-markdown';
    @import './mixin';
    @import './variables';

    在原生css代码中,也能使用@import关键字导入其他css文件(无论是在css文件中还是在style标签中);url()是可加可不加的,要注意的是,结尾都要加上分号

    1
    @import url('./common');

如何实现单行/多行文本溢出的省略样式?

对于文本的溢出,我们可以分成两种形式:

  • 单行文本溢出
  • 多行文本溢出

单行文本溢出显示

涉及的css属性有:

  • text-overflow
  • white-space
  • overflow

overflow设为hidden,普通情况用在块级元素的外层隐藏内部溢出元素,或者配合下面两个属性实现文本溢出省略

white-space:nowrap,作用是设置文本不换行,是overflow:hiddentext-overflow:ellipsis生效的基础

text-overflow属性值有如下:

  • clip:当对象内文本溢出部分裁切
  • ellipsis:当对象内文本溢出时显示省略标记(…)

text-overflow只有在设置了overflow:hiddenwhite-space:nowrap才能够生效。

多行文本溢出显示

多行文本溢出的时候,我们可以分为两种情况:

  • 基于高度截断

    就是把省略号作为伪元素,添加到容器,并使用绝对定位定位到行尾并遮住文字,再通过 overflow: hidden 隐藏多余文字。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    .demo {
    position: relative;
    line-height: 20px;
    height: 40px;
    overflow: hidden;
    }
    .demo::after {
    content: "...";
    position: absolute;
    bottom: 0;
    right: 0;
    padding: 0 20px 0 10px;
    }

如何从CSS入手提高页面性能

浏览器渲染流程

浏览器有一个固定的渲染流程——只有在布局(layout)完成后,才能绘制(paint)页面,而布局的前提是要生成渲染树(render tree),而渲染树的生成则需要 DOM树CSSOM 树的配合。

如果先让用户看到一个没有样式的页面,等 CSS 样式解析完后再重绘(repaint),这样的体验会很差。所以,浏览器会等到DOM树构建完毕,且首屏需要的CSS 加载解析完毕的时后,才开始渲染。

怎么做

  • 内联首屏关键CSS
  • 异步加载CSS
  • 资源压缩
  • 合理使用选择器
  • 不要使用@import

内联首屏关键css

  • 如何找出关键css代码

    有许多工具可以帮助自动生成和内联关键 CSS,例如:

    • Penthouse:一个 Node.js 库,用于生成关键路径 CSS。
    • Webpack 插件:如 critical-css-webpack-plugin,可以在构建过程中自动处理关键 CSS。
  • 如何内联

    将提取出的关键 CSS ,直接嵌入到 HTML 文件的 <head> 部分,使用 <style> 标签包裹。

  • 为什么内联关键css能提高首屏渲染速度

    内联css代码将成为html文件的一部分,会随着html文件的下载而被下载,能够使浏览器在下载完html后就能立刻渲染

    而如果使用link标签引用css代码,在解析html结构过程中,遇到link标签,才会开始下载css代码,再解析,再渲染。

    所以,内联CSS省去了加载css文件的时间,从而提高了首屏加载速度。

  • 那为什么不把全部css代码内联到html文件

    虽然内联关键 CSS 可以加速首屏渲染,但过大的内联样式可能会增加 HTML 文件的大小,反而影响加载速度。因此,应该尽量保持内联 CSS 的精简。

注意:内联的css样式解析完毕后会立即渲染(如果DOM)也构建完毕的话,不管是否存在link标签引入的其他css文件,所以可能存在样式闪烁问题。

异步加载css

我们再打包vue项目的时候,如果不使用路由懒加载,对于所有路由组件,使用的都是静态导入,那么最终打包后的css文件数目将会特别少,每个css文件的大小都会特别大,这是因为不同组件的css都打包到同一个css文件中了(其实对于js文件也是一样的),这意为这我们没有做代码分割,对于非首屏需要的css,我们还是被迫引入了,虽然这对于渲染首屏是不需要的,这就会导致加载,解析css文件时间变长,从而降低首屏加载速度。

但是如果我们使用了路由懒加载,就意味着使用了代码分割,对于那些首屏不需要的css样式,我们在需要的时候再引入它,也就是说,对于这些css样式,我们是异步引入的。

  • 利用媒体查询

    在link标签上添加media属性即可实现媒体查询,使得网页能够在不同的设备条件下加载不同的css代码。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <!-- 加载和解析 styles.css 会阻塞渲染,因为这个样式表在浏览器渲染过程中是要用到的,浏览器会等待它解析完再渲染 -->
    <link rel="stylesheet" href="styles.css" />

    <!-- 加载和解析 print.css 不会阻塞渲染,因为这个样式表在浏览器渲染过程中不会用到 -->
    <link rel="stylesheet" href="print.css" media="print" />

    <!-- 在大屏幕上,加载和解析 mobile.css 不会阻塞渲染,因为这个样式表在浏览器渲染过程中不会用到 -->
    <link
    rel="stylesheet"
    href="mobile.css"
    media="screen and (max-width: 480px)" />

    可以看出,css文件的下载和解析本身不会阻塞浏览器渲染,阻塞的原因是在等待需要用到的css文件解析完毕罢了

    设置一个当前浏览器不支持的值:

    this只的是link标签本身

    1
    <link rel="stylesheet" href="./index.css" media="print" onload="this.media='all'">

    在加载完毕之后,使用onload属性将link的媒体类型设置为all,然后便开始渲染。

    这样这个css文件的加载不会阻塞浏览器渲染,因为他加载的时候,被浏览器认为是不被需要的css文件,加载结束之后,变为浏览器渲染需要用到的css文件,于是开始解析(此时会阻塞渲染),解析完毕浏览器开始渲染。

  • 利用js插入link标签

    下面这个函数可以在任意时刻被执行,异步插入一个css文件。

    1
    2
    3
    4
    5
    6
    function loadCSS(url) {
    var link = document.createElement("link");
    link.rel = "stylesheet";
    link.href = url;
    document.head.appendChild(link);
    }
  • 使用预加载preload

    预加载最适合通常由浏览器较晚发现的资源,通过预加载某个资源,是在告知浏览器希望在浏览器发现该资源之前提前提取该资源,因为确定该资源对当前网页很重要

    现代浏览器在确定资源优先级方面已经非常出色,因此请务必谨慎使用 preload,并仅预加载最重要的资源。

    可以使用 rel="preload"link元素转换为预加载器,用于关键资源。

    1
    <link rel="preload" href="style.css" as="style" />

    preload,浏览器会尽快获取引用的资源,并将其存储在浏览器缓存中(它不会执行脚本或应用样式表,单纯只是下载),以便在后续代码中引用时,可以更快地使用它们。为了让用户体验尽可能流畅,我们应提前加载页面加载初期,用户会遇到的高优先级资源。

资源压缩

利用webpackgulp/gruntrollup等模块化工具,将css代码进行压缩,使文件变小,大大降低了浏览器的加载时间,这一点应该是比较好理解的。

合理使用css选择器

css匹配的规则是从右往左开始匹配,例如#markdown .content h3匹配规则如下:

  • 先找到h3标签元素
  • 然后去除祖先不是.content的元素
  • 最后去除祖先不是#markdown的元素

如果嵌套的层级更多,页面中的元素更多,那么匹配所要花费的时间代价自然更高。

所以最好不要嵌套使用过多复杂选择器。

不使用@import

css样式文件有两种引入方式,一种是link元素,另一种是@import

使用 @import 规则引入的 CSS 文件是串行加载的,打开开发者工具->网络,即可观察到这一现象。

1
2
3
4
5
6
/* styles.css */
@import url('reset.css');
@import url('layout.css');
@import url('theme.css');

body { /* ... */ }

在这个例子中,reset.csslayout.csstheme.css 是按顺序加载的,只有当前一个文件加载完成后才会开始加载下一个。如果这些文件都是渲染首屏需要的,那么这样导入css文件将会减缓首屏渲染速度。

1
2
3
4
5
<head>
<link rel="stylesheet" href="reset.css">
<link rel="stylesheet" href="layout.css">
<link rel="stylesheet" href="theme.css">
</head>

尽管 <link> 标签默认会阻塞页面渲染,但它允许浏览器并行加载多个 CSS 文件。这意味着虽然整个页面的渲染仍然会被延迟,但单个文件的加载不会影响其他文件的下载直到所有这些文件都解析完毕

@import和link标签引入css文件的区别

  • 范畴不同

    link是一个html标签,除了css文件(rel="stylesheet")还能引入其他类型的文件。而@import属于css语法范畴,只能引入css文件

  • 加载方式不同

    link标签引入的css文件是并行加载的,而使用 @import 规则引入的 CSS 文件是串行加载的

  • 是否支持动态插入

    正因为link是html标签,所以支持js控制link标签动态插入css样式表,而@import无法做到动态插入css文件。

  • 兼容性

    link标签是html标签,没有兼容性问题,而@import是css2.1之后推出的,所以对于部分浏览器不支持,兼容性较差。

说说css的层叠顺序

层叠上下文

有层叠上下文的元素,一般比普通元素(未开启定位的元素)层级高

如何产生层叠上下文

  • html元素默认有层叠上下文,称为“根层叠上下文”
  • 普通元素设置position属性为非static值,并设置z-index属性为具体数值(不为auto),产生层叠上下文。

如何查找

从父元素开始向上查找,直至查找到一个有层叠上下文的元素。

z-index

静态布局元素(postion:static)的z-index属性不会生效,只对定位元素有效。

默认值为auto,不会产生层叠上下文。

父元素的z-index权重可以理解为比子元素高(老爸比不过对面的,自己也就比不过),我们一般只在同一个层叠上下文中比较层叠优先级。

层叠顺序

层叠上下文 < 开启了层叠上下文,但是指定z-index:-1 < 未开启定位元素(块级水平盒子 < 浮动盒子 < 行内/行内块元素 ) < z-index:auto(开启定位,但是未指定z-index的元素,即未开启层叠上下文) = 开启定位并指定z-index=0的定位元素< 开启定位并指定z-index>0的定位元素

由此可知,浮动盒子的层叠优先级低于行内/行内块元素,但高于块级元素,所以浮动盒子不会压住后面的行内/行内块元素,会压住后面的块级元素。

开启了定位的元素(相对定位,绝对定位,固定定位)的,即便不指定z-index,层叠优先级也比行内/行内块元素高,当然也就比浮动元素高。如果指定了z-index为负值,优先级反而变的比它们低了。

怎么理解回流跟重绘?什么场景下会触发?

是什么

HTML中,每个元素都会被表示成一个盒子,在浏览器解析过程中,会涉及到回流重绘

  • 回流:布局引擎会根据各种样式计算每个盒子在页面上的大小位置简单的来说,回流的作用就是布局元素,即确定元素的位置和大小
  • 重绘:当计算好盒模型的位置、大小及其他属性后,浏览器根据每个盒子特性进行绘制简单的来说,就是更为细致的渲染盒子

具体的浏览器解析渲染机制如下所示:

  • 解析HTML,生成DOM树,解析CSS,生成CSSOM树
  • DOM树CSSOM树结合,生成渲染树(Render Tree),生成了渲染树才能确定每个元素的大小和布局方式,才能进行布局(layout)
  • Layout(回流):根据生成的渲染树,进行回流(Layout),得到节点的几何信息(位置,大小)
  • Painting(重绘):根据渲染树以及回流得到的几何信息,得到节点的绝对像素
  • Display:将像素发送给GPU,展示在页面上

在页面初始渲染阶段,回流不可避免的触发,可以理解成页面一开始是空白的元素,后面添加了新的元素使页面布局发生改变

当我们对 DOM 的修改引发了 DOM几何尺寸的变化(比如修改元素的宽、高或隐藏元素等)时,浏览器需要重新计算元素的几何属性,然后再将计算的结果绘制出来

当我们对 DOM的修改导致了样式的变化(colorbackground-color),却并未影响其几何属性时,浏览器不需重新计算元素的几何属性、直接为该元素绘制新的样式,这里就仅仅触发了重绘。

如何触发回流

那么当页面布局或者几何信息发生变化的时候,就需要回流,如下面情况:

  • 添加或删除可见的DOM元素
  • 元素的位置发生变化
  • 元素的大小发生变化
  • 内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代,字体大小的改变有可能触发重排,如果当它影响到了元素的布局结构时。
  • 页面一开始渲染的时候(这避免不了)
  • 浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的,这个依据变了,就难免要重新计算)
  • 获取元素特定的属性,比如client,scroll,offset开头的布局属性,这些属性有一个共性,就是需要通过即时计算得到。因此浏览器为了获取这些值,也会进行回流。

如何触发重绘

  • 触发回流一定会触发重绘

除此之外还有一些其他引起重绘行为:

  • 颜色的修改
  • 文本方向的修改
  • 阴影的修改

总的来说,如果修改了css样式,但是没改变元素的位置和大小,那就只会触发重绘。

浏览器的优化机制

由于每次重排都会造成额外的计算消耗,因此大多数浏览器都会通过队列化修改并批量执行来优化重排过程。浏览器会将修改操作放入到队列里,直到过了一段时间或者操作达到了一个阈值,才清空队列。

当你获取布局信息的操作的时候,会强制队列刷新,包括前面讲到的offsetTop等方法都会返回最新的数据

因此浏览器不得不立即清空队列,触发回流重绘来返回正确的值。

编码过程中该如何优化

其实在我们编码的过程中,借鉴队列化,批处理的的思想也能减少回流和重绘。

  • 通过类名批量修改css样式:

    1
    2
    3
    4
    5
    const container = document.getElementById('container')
    container.style.width = '100px'
    container.style.height = '200px'
    container.style.border = '10px solid red'
    container.style.color = 'red'
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    <style>
    .basic_style {
    width: 100px;
    height: 200px;
    border: 10px solid red;
    color: red;
    }
    </style>
    <script>
    const container = document.getElementById('container')
    container.classList.add('basic_style')
    </script>

    前者每次单独操作,都去触发一次渲染树更改(新浏览器不会),从而导致相应的回流与重绘过程,合并之后,等于我们将所有的更改一次性发出

  • 我们还可以通过设置元素属性display: none,将其从页面上去掉(完全从渲染树中移除),然后再进行后续操作,这些后续操作也不会触发回流与重绘,当设置display:block时,浏览器会重新计算所有累积的样式修改,触发全局回流和重绘。

    要注意的是,对于其他隐藏的元素(visibility:hiddenopacity:0)修改几何属性仍然会触发回流,修改非几何属性也会触发重绘。

  • 避免多次访问布局属性,因为访问布局属性会强制触发回流

  • 对于那些复杂的动画,对其设置 position: fixed/absolute,尽可能地使元素脱离文档流,从而减少对其他元素的影响

css选择器有哪些?优先级?哪些属性可以继承?

选择器

CSS选择器是CSS规则的第一部分。就是选择符合匹配规则的元素,给它们应用相应的样式规则。

关于css属性选择器常用的有:

  • id选择器(#box),选择id为box的元素,id选择器选择唯一的元素,每个元素的id应该是唯一的。

  • 类选择器(.one),选择类名为one的所有元素

  • 标签选择器(div),选择标签为div的所有元素

  • 后代选择器(#box div),选择id为box元素内部所有的div元素,只要是box后代div元素就行。

    1
    a.className a 

    这是一个有效的选择器。它会选择带有类名className的a标签之下的另一个a标签。但是从html角度考虑,a标签不能套接a标签

    而且它的权重比.className a要高。

  • 子选择器(.one>one_1),选择父元素为.one的所有.one_1的元素

  • 相邻同胞选择器(.one+.two),选择紧接在.one之后的所有.two元素

  • 群组选择器(div,p),选择div、p的所有元素,这两类元素使用相同的css规则。

还有一些使用频率相对没那么多的选择器:

  • 伪类选择器

    1
    2
    3
    4
    5
    6
    :link :选择未被访问的链接,常见的使用场景是和a标签绑定的,即a:link
    :visited:选取已被访问的链接,常见的使用场景是和a标签绑定的,即a:visited
    :active:选择活动链接,就是点击a标签不松手时的样式。常见的使用场景是和a标签绑定的,即a:active
    :hover :鼠标指针浮动在上面的元素
    :focus :选择具有焦点的
    :nth-child(n)、:first-child:last-child 等:基于元素在其父级中的位置选择元素。

    注意:上述与a标签有关的书写顺序应该是,a:link->a:hover->a:visited->a:active,书写顺序越靠后,优先级越高,这样书写才能保证相应的样式会如期生效。

    :nth-child(n)和:nth-of-type(n)的区别

    :nth-child(n)是先根据顺序查找元素,再匹配类型,:nth-of-type(n)是先根据元素类型筛选元素,再根据顺序查找元素。

    1
    2
    3
    4
    5
    6
    7
    <div class="container">
    <h2>标题</h2>
    <p>段落一。</p>
    <p>段落二。</p>
    <h2>另一个标题</h2>
    <p>段落三。</p>
    </div>
    1
    2
    3
    .container :nth-child(3) {
    background-color: yellow;
    }选中的是 <p>段落二。</p>这个元素
    1
    2
    3
    .container p:nth-child(4) {
    background-color: yellow;
    }选中的是第四个元素,且要求它的类型是p,但是第四个元素类型是h2,所以这个css规则不会生效
    1
    2
    3
    .container p:nth-of-type(3) {
    background-color: lightblue;
    }//选中的是内部所有的p元素中的第三个,也就是第五个元素<p>段落三。</p>
  • 伪元素选择器

    伪元素通常以双冒号 :: 开头,这是为了区分伪类选择器,但在一些较老的浏览器中,单冒号 : 也被支持。

    1
    2
    3
    4
    ::first-letter :用于选取指定选择器的首字母
    ::first-line :选取指定选择器的首行
    ::before : 选择器在被选元素的内容前面插入内容
    ::after : 选择器在被选元素的内容后面插入内容

    伪元素的好处就是可以在不改变页面结构的前提下,往页面中插入内容

    伪元素选择器还可以用来清除浮动

    1
    2
    3
    4
    5
    .clearfix::after {
    content: "";
    display: block;//让伪元素独占一行
    clear: both;//确保左右两边没有浮动元素
    }

    clear属性的解释

    指明某个元素周围不能出现浮动元素,通常借助伪元素来清除浮动,属性值为 none | left | right | both所以说,周围最多是指的左右两边(both)。

  • 属性选择器

    1
    2
    3
    4
    5
    [attribute] 选择带有attribute属性的元素
    [attribute=value] 选择所有使用attribute=value的元素
    /*选择attribute属性包含value的元素,匹配的是整个单词,它不能匹配部分字符串,比如不能匹配valueof 但是能匹配value of*/
    [attribute~=value]
    [attribute|=value]:选择attribute属性以value开头的元素

CSS3中新增的选择器有如下:

  • 层次选择器(p~ul),选择前面有p元素的每个ul元素

  • 伪类选择器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    :first-of-type 表示一组同级元素中其类型的第一个元素
    :last-of-type 表示一组同级元素中其类型的最后一个元素
    :only-of-type 表示没有同类型兄弟元素的元素
    :only-child 表示没有任何兄弟的元素
    :nth-child(n) 根据元素在一组同级中的位置匹配元素
    :nth-last-of-type(n) 匹配给定类型的元素,基于它们在一组兄弟元素中的位置,从末尾开始计数
    :last-child 表示一组兄弟元素中的最后一个元素
    :root 设置HTML文档
    :empty 指定空的元素
    :enabled 选择可用元素
    :disabled 选择被禁用元素
    :checked 选择选中的元素
    :not(selector) 选择与 <selector> 不匹配的所有元素
  • 属性选择器

    1
    2
    3
    [attribute*=value]:选择attribute属性值包含value的所有元素
    [attribute^=value]:选择attribute属性开头为value的所有元素
    [attribute$=value]:选择attribute属性结尾为value的所有元素

优先级

相信大家对CSS选择器的优先级都不陌生:

内联 > ID选择器 > 类选择器 > 标签选择器

到具体的计算层⾯,优先级是由 A 、B、C、D 的值来决定的,其中它们的值计算规则如下:

  • 如果存在内联样式,那么 A = 1, 否则 A = 0
  • B的值等于 ID选择器出现的次数
  • C的值等于类选择器属性选择器伪类 出现的总次数,也就是说,属性选择器类选择器伪类选择器的优先级是相同的。
  • D 的值等于 标签选择器伪元素 出现的总次数,也就是说标签选择器伪元素选择器的优先级是相同的。

这里举个例子:

1
#nav-global > ul > li > a.nav-link

套用上面的算法,依次求出 A B C D 的值:

  • 因为没有内联样式 ,所以 A = 0
  • ID选择器总共出现了1次, B = 1
  • 类选择器出现了1次, 属性选择器出现了0次,伪类选择器出现0次,所以 C = (1 + 0 + 0) = 1
  • 标签选择器出现了3次, 伪元素出现了0次,所以 D = (3 + 0) = 3

上面算出的ABCD 可以简记作:(0, 1, 1, 3)

知道了优先级是如何计算之后,就来看看比较规则

  • 左往右依次进行比较 ,较大者优先级更高
  • 如果相等,则继续往右移动一位进行比较
  • 如果4位全部相等,则后面的会覆盖前面的,也就是说,书写顺序能决定同优先级的选择器的优先级。

经过上面的优先级计算规则,我们知道内联样式的优先级最高,如果外部样式需要覆盖内联样式,就需要使用!important,示例

1
2
3
.box{
font-size:12px !important /*这个样式的优先级最高*/
}

继承属性

css中,继承是指的是给父元素设置一些属性,后代元素会自动拥有这些属性

关于继承属性,可以分成:

  • 字体系列属性

    简单来说,就是font开头的属性,所有字体属性。

    1
    2
    3
    4
    5
    6
    font:组合字体
    font-family:规定元素的字体系列
    font-weight:设置字体的粗细
    font-size:设置字体的尺寸
    font-style:定义字体的风格
    font-variant:偏大或偏小的字体
  • 文本系列属性

    1
    2
    3
    4
    5
    6
    7
    8
    text-indent:文本缩进
    text-align:文本水平对齐
    line-height:行高
    word-spacing:增加或减少单词间的空白
    letter-spacing:增加或减少字符间的空白
    text-transform:控制文本大小写
    direction:规定文本的书写方向
    color:文本颜色
  • 元素可见性visibility

    这就意味着,给一个父元素添加visibility:hidden,他的子元素也都会被隐藏。

  • 表格布局属性

    1
    2
    3
    4
    5
    caption-side:定位表格标题位置
    border-collapse:合并表格边框
    border-spacing:设置相邻单元格的边框间的距离
    empty-cells:单元格的边框的出现与消失
    table-layout:表格的宽度由什么决定
  • 列表属性

    1
    2
    3
    list-style-type:文字前面的小点点样式
    list-style-position:小点点位置
    list-style:以上的属性可通过这属性集合
  • 引用

    1
    quotes:设置嵌套引用的引号类型
  • 光标属性

    1
    2
    cursor:箭头可以变成需要的形状
    cursor: url("/img/ania_link.cur"),default;/*如果第一个资源不可用,就使用默认样式*/

继承中比较特殊的几点:

  • a 标签的字体颜色不会继承父元素的字体颜色
  • h1-h6标签字体的大小也不会继承父元素的字体大小

无继承的属性

  • display
  • 文本属性:vertical-align、text-decoration
  • 盒子模型的属性:宽度、高度、内外边距、边框等
  • 背景属性:背景图片、颜色、位置等
  • 定位属性:浮动、清除浮动、定位position等
  • 生成内容属性:content、counter-reset、counter-increment
  • 轮廓样式属性:outline-style、outline-width、outline-color、outline
  • 页面样式属性:size、page-break-before、page-break-after

CSS3新增了那些特性

是什么

css,即层叠样式表(Cascading Style Sheets)的简称,是一种标记语言,由浏览器解释执行用来使页面变得更美观

css3css这种标记语言的最新标准,是向后兼容的,CSS1/2的特性在CSS3 里都是可以使用的

CSS3 也增加了很多新特性,为开发带来了更佳的开发体验,让页面变得更为美观

新增选择器

新增样式

  • 边框

    • border-radius:创建圆角边框

      值可以是绝对单位px也可以是百分比单位。

      如果是绝对单位,比如为10px,则从盒模型每个角的顶点开始,往两条边的方向分别延伸10px,然后在这两个点的位置做一条垂直的边,确定交点,然后再以这个焦点为圆心做一个圆,然后在舍去这个圆截取的部分 ,就得到了圆角模型。

      如果单位是百分比,则先转化为绝对单位,相对的是每个角对应的两条边。

      1
      2
      3
      4
      5
      6
      .box {
      width: 300px;
      height: 50px;
      border-radius: 10px;
      background-color: pink;
      }

      图中圆的半径为10px

      1
      2
      3
      4
      5
      6
      .box {
      width: 300px;
      height: 50px;
      border-radius: 50%;
      background-color: pink;
      }

      图中的红线只是辅助线,可以看到当令 border-radius: 50%时就能得到一个椭圆,如果盒子的宽高相等就是一个圆形。

      50%border-radius能取得的最大值,再增加也不会有效果。

    • box-shadow:为元素添加阴影

      设置属性如下:

      • 水平阴影(x轴)
      • 垂直阴影(y轴)
      • 模糊距离(z轴)
      • 阴影尺寸(影子大小)
      • 阴影颜色
      • 内/外阴影
      1
      box-shadow: 3px 3px 4px;

      如果第一个属性值(x)为正数,则阴影就会出现在盒模型的右边 ,值越大右边阴影越,反之则出现在盒模型的左边

      如果第二个属性值(y)为正数,则阴影就会出现在盒模型的下边 ,值越大下边阴影越,反之则出现在盒模型的上边

      如果第三个属性值(z)表示盒模型距离视口的距离,一般为正值,这个值增大可以看到盒模型仿佛在贴近屏幕,阴影就变越来越模糊了。

      第四个值为阴影的尺寸,其实修改第一,二个属性的值就能控制阴影的大小了,这个值存在的意义就是在原有的大小上再添加。

    • border-image:使用图片来绘制边框

      1
      2
      3
      4
      5
      6
      7
      //添加border-image
      .box {
      width: 300px;
      height: 50px;
      border: 40px solid black;
      background-color: pink;
      }
      1
      2
      3
      4
      5
      6
      7
      8
      //添加border-image
      .box2 {
      width: 300px;
      height: 50px;
      border: 40px solid black;
      border-image: url("C:/Users/35194/Desktop/hexo/myblog/source/images/cover/江南.png");
      background-color: pink;
      }

      看起来好像很鸡肋啊。

  • 背景

  • 颜色

  • transition过渡

    transition属性可以为指定的一个或多个CSS属性添加过渡效果,让样式改变看起来更自然,多个属性之间用逗号进行分隔,必须规定两项内容:css属性持续时间

    1
    2
    transition: CSS属性,花费时间,效果曲线(默认ease),延迟时间(默认0)
    transition: all 0.4s #给所有样式添加过渡 花费0.4s

    详细介绍见下文《css新增动画》

  • transform转换

    transform属性允许你平移缩放旋转指定元素

    详细介绍见下文《css新增动画》

  • animation 动画

    详细介绍见下文《css新增动画》

  • 渐变

    • linear-gradient:线性渐变

      线性渐变创建了一条沿直线前进的颜色带,这条直线的方向角度是可以自定义的。

      基础线性渐变

      1
      2
      3
      .simple-linear {
      background: linear-gradient(blue, pink);//注意是background属性,不能是background-color
      }

      改变渐变方向

      默认情况下,线性渐变的方向是从上到下,你可以指定一个值来改变渐变的方向,我们把这个值放到第一个参数的位置,值的类型可以是关键字,也可以是具体的角度。

      1
      2
      3
      .horizontal-gradient {
      background: linear-gradient(to right, blue, pink);
      }
      1
      2
      3
      .diagonal-gradient {
      background: linear-gradient(to bottom right, blue, pink);
      }

      设置渐变角度

      在使用角度的时候,0deg 代表渐变方向为从下到上,90deg 代表渐变方向为从左到右,诸如此类正角度都属于顺时针方向。而负角度意味着逆时针方向。

      1
      2
      3
      .angled-gradient {
      background: linear-gradient(45deg, blue, pink);
      }

      控制渐变的进程

      默认情况下,渐变在两个相邻的色标之间都是均匀推进的,两个色标之间的中点是颜色值的中点,也可以控制在哪个位置才开始均匀推进。

      1
      2
      3
      4
      5
      .box{
      width: 100px;
      height: 100px;
      background: linear-gradient(blue 50px, pink);//可以是px,也可以是相对单位。
      }

      如图所示,前50px的部分的颜色都是blue

      堆叠渐变

      你可以将渐变与其他的渐变堆叠起来。只要顶部的渐变不是完全不透明的,那么下面的渐变就会依然可见。

      顶部的渐变就是最先声明的渐变,就是书写位置最靠前的渐变。

      1
      2
      3
      4
      5
      6
      7
      .a {
      width: 100px;
      height: 100px;
      //渐变的声明顺序不能乱。
      background: linear-gradient(to bottom, transparent 10px, #fff),
      linear-gradient(to right, blue, pink);
      }

      其实多个背景图片也是按照这种规则来堆叠的:

      1
      2
      3
      4
      5
      .box {
      width: 400px;
      height: 400px;
      background: url('../images/w3logo.png') center/contain no-repeat, url('../images/0.png') center/contain no-repeat;
      }

      效果如图:

    • radial-gradient:径向渐变

      径向渐变类似于线性渐变,除了是从一个中心点向外辐射的。你可以指定中心点的位置。你还可以使其为圆形或者是椭圆形

      更多内容参考:使用 CSS 渐变 - CSS:层叠样式表 | MDN

  • flex布局与grid布局

    有文章介绍,不赘述。

CSS3新增动画

css实现动画的方式,有如下几种,都是css3新增的

  • transition:实现渐变动画
  • transform:转变动画
  • animation:实现自定义动画

transition

transition的属性如下:

  • property:填写需要变化的css属性,我们一般直接填写all
  • duration:完成过渡效果需要的时间单位(s或者ms)
  • timing-function:完成效果的速度曲线
  • delay:动画效果的延迟触发时间

time-function的所有值如下

注意:虽然为了方便,我们经常使用all,表示给所有属性添加过渡,但并不是所有的属性都能使用过渡的,如display:none<->display:block,而visibility:hidden<->visibility:visible却可以,所以不是显示与隐藏的问题,就是display:none<->display:block不能。

transform

一般配合transition过渡使用,不影响其他盒子的位置。元素会在视觉上发生位置变化,但实际位置没变,这一点和相对定位相同。

注意的是,transform不支持inline元素(因为无法指定宽高(也无法指定垂直外边距)),使用前把它变成block

包含四个常用的功能:

  • translate:位移

    1
    transform:translate(15px,15px) //向右向下平移15px

    传入的单位也可以是百分比,相对的是元素自身的宽/高

  • rotate:旋转

    1
    transform:rotate(45deg

    正值表示为顺时针旋转45度

    1
    transform-origin: x y

    设置平面转换中心点,默认是元素中心,x y可以是像素(px),也可以是百分比,相对的也是元素自身的宽高,比如transform-origin: 50% 50%;指定的转换中心点就是盒子中点。也可以是方位名词,所有组合方式只能表示9个点。

  • scale:缩放

    1
    transform:scale(x,y) 

    里面的数字不跟单位,就是倍数的意思,分别表示宽高缩放为原来的多少倍。

  • skew:倾斜

transform-origin

transform-origin 是 CSS 中的一个属性,用于定义应用变换(如旋转、缩放、倾斜等)的原点位置。默认情况下,变换的中心点是元素的中心(即 50% 50%

值的数量

transform-origin 可以接受一到三个值。

如果指定一个值,就是在指定x轴的位置,Y 轴默认为 50%

如果指定两个值,分别指定 X 轴和 Y 轴的位置。在支持 3D 转换的情况下,可以指定 X 轴、Y 轴和 Z 轴的位置。

可能的值

  • 百分比:例如 0%, 50%, 100% 等。0% 0% 表示左上角,100% 100% 表示右下角。
  • 关键字
    • 水平方向:left, center, right
    • 垂直方向:top, center, bottom
  • 长度单位:如 px, em, cm 等具体数值。

animation

先通过@keyframes定义动画,再通过animation属性使用动画

定义动画

CSS 动画只需要定义一些关键的帧,而其余的帧,浏览器会根据计时函数插值计算出来

通过 @keyframes 来定义关键帧

比如,如果我们想要让元素旋转一圈,只需要定义开始结束两帧即可:

1
2
3
4
5
6
7
8
9
10
11
@keyframes rotate{
//开始样式
from{
//在大括号内具体描述每个时刻对应的样式
transform: rotate(0deg);
}
//结束样式
to{
transform: rotate(360deg);
}
}

from 表示最开始的那一帧,to 表示结束时的那一帧。rotate表示自定义的动画名。

也可以使用百分比刻画生命周期:

1
2
3
4
5
6
7
8
9
10
11
12
@keyframes rotate{
0%{
//在大括号内具体描述每个时刻对应的样式
transform: rotate(0deg);
}
50%{
transform: rotate(180deg);
}
100%{
transform: rotate(360deg);
}
}

使用动画

定义好动画,我们就可以直接使用了,使用动画涉及到了许多属性,记忆起来较为困难。

animation是其他8个属性的简写,当使用 animation 简写属性时,按顺序来书写值是很重要的。如果你省略了某些中间的属性,必须确保后续属性仍然按照正确的顺序给出。参考下面书写的顺序。

属性描述属性值
animation-name指定 @keyframes 动画的名称
animation-duration指定动画完成一个周期所需要时间,单位秒(s)或毫秒(ms),默认是 0
animation-timing-function指定动画计时函数,即动画的速度曲线,默认是 “ease”linear、ease、ease-in、ease-out、ease-in-out
animation-delay指定动画延迟时间,即动画何时开始,默认是 0
animation-iteration-count指定动画播放的次数,默认是 1具体次数,infinite(无限多次)
animation-direction 指定动画播放的方向默认是 normalnormal、reverse、alternate、alternate-reverse
animation-fill-mode定义动画在播放之前或之后如何影响元素的样式。默认是 noneforwards、backwards、both
animation-play-state指定动画播放状态,正在运行或暂停。默认是 runningrunning、pauser

什么是响应式设计?响应式设计的基本原理是什么?

是什么

响应式网站设计(Responsive Web design)是一种页面设计布局,页面的设计与开发,应当根据用户行为以及设备环境(系统平台、屏幕尺寸、屏幕定向等)进行相应的响应和调整

描述响应式界面最著名的一句话就是“Content is like water”

大白话便是“如果将屏幕看作容器,那么内容就像水一样”

响应式网站常见特点:

  • 同时适配PC + 平板 + 手机等
  • 标签导航在接近手持终端设备时改变为经典的抽屉式导航
  • 网站的布局会根据视口来调整模块的大小和位置

如何实现

响应式设计的基本原理是通过媒体查询检测不同的设备屏幕尺寸从而做对应处理,

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

1
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no”>
  • width=device-width:布局视口的宽度等于设备宽度。
  • maximum-scale:是缩放比例的最大值
  • inital-scale:是缩放的初始化
  • user-scalable:值为布尔值,决定用户是否可以进行缩放操作。

实现响应式布局的方式有如下:

  • 像素单位使用相对单位:

    • 百分比

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

      子元素的top/leftbottom/right如果设置百分比,则相对于最近的定位元素(position非static)的宽高(补充一下,dom元素的offsetTop和offsetLeft属性相对的也是最近的定位元素)

      子元素的内外边距(padding和margin)如果设置百分比,不论是垂直方向或者是水平方向,都相对于直接父元素width,而与父元素的height无关。

    • vw/vh

      有文章介绍,不赘述

    • rem

      有文章介绍,不赘述

  • 媒体查询

    媒体查询是css3中引入的功能,作用类似js中的if-else语句,通过媒体查询,可以通过给不同分辨率的设备编写不同的样式来实现响应式的布局。即便我们使用了相对单位,也只能解决同一类型设备的响应式问题,比如在PC端设计的网页,即便使用了相对单位,在移动端展示的效果也是宽大于高的矩形,展示效果不佳,此时就需要借助媒体查询来解决这个问题。

    基本语法

    1
    2
    3
    @media [not|only] media-type and (media-feature) {
    /* CSS样式规则 */
    }
    • @media:用于定义一个媒体查询。
    • [not|only]:可选关键字,not排除特定条件,only用来指定仅在满足条件时应用样式(主要用于避免旧浏览器解析媒体查询)。
    • media-type:指定媒体类型,例如screen(屏幕)、print(打印机)等。如果省略,则默认为all,即适用于所有类型的媒体。
    • and:逻辑运算符,用来连接多个媒体特性条件。
    • (media-feature):媒体特性条件表达式,例如(max-width: 600px),注意不要写成(max-width=600px)

    示例

    根据屏幕大小确定字体大小

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    /* 当屏幕宽度小于等于600px时 */
    @media screen and (max-width: 600px) {
    body {
    font-size: 18px;
    }
    //后续还可以写更多选择器
    }
    /* 当屏幕宽度大于等于768px且小于1200px时 */
    @media screen and (min-width: 768px) and (max-width: 1199px) {
    body {
    font-size: 20px;
    }
    }
    /* 当屏幕宽度大于等于1200px时 */
    @media screen and (min-width: 1200px) {
    body {
    font-size: 24px;
    }
    }

    根据屏幕方向调整布局

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    /* 适用于竖屏设备 */
    @media screen and (orientation: portrait) {
    .container {
    flex-direction: column;
    }
    }

    /* 适用于横屏设备 */
    @media screen and (orientation: landscape) {
    .container {
    flex-direction: row;
    }
    }

    媒体查询不仅可以使用在css代码中,还能再link标签中使用,比如下面的代码可转化成:

    1
    2
    3
    4
    5
    6
    @media screen and (max-width: 600px) {
    body {
    font-size: 18px;
    }
    //后续还可以写更多选择器
    }
    1
    <link rel="stylesheet" media="screen and (max-width: 600px)" href="test.css"></link>
    1
    2
    3
    4
    //test.css
    body {
    font-size: 18px;
    }

    这样就能实现在不同尺寸的设备上,使用不同的样式表,从而试下响应式布局的效果。