HTML/CSS常见题,淦就完了

1,856 阅读10分钟

开头

这些题都是我们在面试中很常见到的题型,面试官也很喜欢问,反正不要畏惧不要慌,淦就完了,奥里给给!

HTML5新特性

  • 拖拽释放(Drag and drop) API Drag API详情参考这里

  • 语义化更好的内容标签(header,nav,footer,aside,article,section)

  • 音频、视频API(audio,video)

  • 画布(Canvas) API

  • 地理(Geolocation) API

  • 本地离线存储 localStorage 长期存储数据,浏览器关闭后数据不丢失;

  • sessionStorage 的数据在浏览器关闭后自动删除

  • 表单控件,calendardatetimeemailurlsearch

  • 新技术webWorker webSocketGeolocation

为什么使用语义化标签?

  • 去掉样式或者样式丢失时页面结构依然清晰分明
  • 阅读器会根据标签的语义自动解析,呈现更容易阅读的内容形式(无障碍阅读)
  • 搜索引擎优化
  • 便于后期开发和维护

CSS选择器优先级

  • !important 最高
  • 内联样式 1000
  • ID选择器 0100
  • 类选择器 / 属性选择器 /伪类选择器 0010
  • 元素选择器 / 伪元素选择器 0001
  • 关系选择器 / 通配符选择器 0000

常见行内元素、块级元素和行内块级元素

  • 块级元素:总是独占一行,可以设置高度和宽度。没有设置宽度时为100%。常见的块级元素有:h1-h6

    hr(水平分割线)divp(段落)ul(无序列表)ol(有序列表)form(表单)

  • 行内元素:和其它元素在一行,不可以设置高度、宽度和内边距。 宽高就是内容的高度,依靠自身字体大小和图形支撑结构,不可以改变 。可以设置paddingmargin-left以及margin-right(top和bottom无法设置)。常见行内元素有:spaninputab/strong(加粗)i/em(斜体)del(删除线)u(下划线)

  • 行内块级元素: 综合块级元素与行内元素的特性, 可以设置宽高(默认是内容宽高),也可以设置内外边距 。常见的有:imgbuttontextareaaudiovideo

盒模型

盒模型就是我们可以把元素看成一个盒子,它包括外边距(margin)、边框(border)、内边距(padding)、实际内容(content)

其中盒模型又分为标准盒模型IE盒模型(怪异盒模型),可以通过box-sizing来设置,它有两个属性可以分别设置这两种模型,content-box指定盒子模型为标准盒模型,border-box为IE盒子模型(怪异盒模型)。

我们再来说一下这两种模型的区别:

  • 标准盒模型:设置元素的高度和宽度实际上就是设置内容(content)的宽高,我们设置widthheight其实就是设置content的宽高,paddingborder的值其实是另外算的。 盒子总宽度=width+padding+border+margin
  • 怪异盒模型:设置元素的宽度和高度是同时设置contentpaddingborder这三者的总和,盒子内边距加边框和内容就等于我们设置的宽高。 盒子总宽度=width(包含padding+border)+margin

下面放张图可以对比一下两种模型的区别:

BFC的理解

BFC 全称为块级格式化上下文 (Block Formatting Context) 。一个BFC盒子是独立布局的,盒子里面的子元素布局不会影响到外面的元素。在同一个 BFC 中的两个毗邻的块级盒在垂直方向(和布局方向有关系)的 margin 会发生折叠

咋去触发BFC?

只要元素满足下面任一条件就能触发 BFC :

  • body根元素
  • 浮动元素(除none之外的属性)
  • 绝对定位元素(absolutfixed)
  • displayinline-blocktable-cellsflex
  • overflow 除了 visible 以外的值 (hidden、auto、scroll)

BFC的作用是啥子?

  • 利用BFC避免margin重叠。上面说到了,在同一个BFC盒子里的两个元素会发生上下边距重叠。想要避免外边距的重叠,可以将元素放在两个不同的 BFC 容器中。

  • 利用BFC做自适应的两栏布局,其实最简单的方式就是用flex去触发BFC然后实现两栏布局,一样的道理,三栏布局也是可以的。

  • 清除浮动,这是老生常谈的问题了,清除浮动的方法也有很多:

    • 额外标签法(在最后一个浮动标签后,新加一个标签,给其设置clear:both;)缺点是添加了无意义的标签,语义化太差,所以很少使用这个。

    • 父级添加overflow属性(父元素添加overflow:hidden;),缺点就是盒子里内容比较多的时候不会自动换行,溢出的内容会被隐藏掉

    • 使用after伪元素清除浮动 ,大概是介样子的,这种方式比较推荐使用,就是对低版本IE浏览器支持不太好(业界毒瘤,Vue3都放弃了,谁还管它)

      .clearfix:after{
              content: "";
              display: block;
              height: 0;
              clear:both;
              visibility: hidden;
          }
      
    • 使用before和after双伪元素清除浮动 ,这种方式也推荐使用。8过感觉现在大部分时候都用flex来布局了,大部分浏览器对flex也支持得很好了,实在要兼容一些低版本浏览器的时候才去用浮动布局。

      .clearfix:after,
      .clearfix:before{
          content: "";
          display: table;
      }
      
      .clearfix:after{
          clear: both;
      }
      

关于Rem和em

  • Rem(font-size-of-the-root-element): rem是相对于根元素<html>来设置字体大小的 ,看下下面的代码,我们改变根元素的font-size就可以对不同的移动设备进行字体大小的适配。

    //该模块实现移动端rem布局
    function remSize() {
      let deviceWidth = document.documentElement.clientWidth || window.innerWidth //获取屏幕宽度
      if (deviceWidth >= 750) {
        deviceWidth = 750  //pc端屏幕宽度如果大于750也直接设置成750
      }
      if (deviceWidth <= 320) {
        deviceWidth = 320  //移动端屏幕宽度不能小于320
      }
    
      //设计稿是750px
      //设置一半的宽度。就是375px
      //1rem = 100px的设计稿宽度
      //一半宽度rem就是 3.75rem
      document.documentElement.style.fontSize = (deviceWidth / 7.5) + 'px'
    
      //设置默认字体大小
      document.body.style.fontSize = 0.3 + 'rem'
    }
    
    remSize()
    
    window.onresize = function () {
      remSize()
    }
    
  • em: em是相对其父元素来设置字体大小,如果对于浏览器来说 1em = 16px,浏览器默认字体大小为16px。这个单位会有一些问题,比如某元素可能继承其父元素的字体大小,而父元素又继承其父元素的字体大小(套娃,套它🐒的)。 因此,以 em 为单位的元素字体大小可能会受到其任何父元素的字体大小影响。

让行内元素水平和垂直居中

给父元素设置text-alignline-height

div {
    width: 100px;
    height: 100px;
    text-align: center;
    line-height: 100px;
}

然后div里面的所有行内元素都可以水平垂直居中了

让块级元素垂直和水平居中

1.绝对定位+margin:auto

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    .parent {
      position: relative;
      width: 300px;
      height: 300px;
      background-color: hotpink;
    }

    .child {
      position: absolute;
      width: 100px;
      height: 100px;
      left: 0;
      right: 0;
      top: 0;
      bottom: 0;
      margin: auto;
      background-color: pink;
    }
  </style>
</head>

<body>
  <div class="parent">
    <div class="child"></div>
  </div>
</body>

</html>

2.绝对定位+transform

将上面css代码的child分别换成如下代码

.child {
  position: absolute;
  width: 100px;
  height: 100px;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  background-color: pink;
}

3.使用Flex布局

上面的css代码中的parent和child分别改成如下代码

.parent {
  width: 300px;
  height: 300px;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: hotpink;
}
.child {
  width: 100px;
  height: 100px;
  background-color: pink;
}

4.使用grid布局

上面的css代码中的parent和child分别改成如下代码,该方法目前浏览器兼容性还不是特别好

.parent {
  display: grid;
  width: 300px;
  height: 300px;
  background-color: hotpink;
}

.child {
  width: 100px;
  height: 100px;
  justify-self: center;
  align-self: center;
  background-color: pink;
}

上面几种就是比较常见的让元素水平和垂直居中方法了,他们的效果都是一样的,如下是效果图

两列布局

这种布局方式比较简单,但是面试也很常问。这里就说一下常见的几种方法吧,首先写好布局

<body>
    <div class="content">
        <div class="left">
            <p>left</p>
        </div>
        <div class="right">
            <p>right</p>
        </div>
    </div>
</body>

然后我们可以用几种方式去设置,在此之前我们要先设置

* {
    margin: 0;
    padding: 0;
}

下面说的几种布局方式都是左侧固定,右侧自适应的

1.使用float+margin-left

.left{
    background: pink;
    width: 200px;
    float: left;
}

.right{
    background: hotpink;
    margin-left: 210px;
}

2.双左浮动+calc

.left {
  float: left;
  width: 200px;
  background-color: pink;
}

.right {
  float: left;
  margin-left: 10px;
  width: calc(100% - 210px);
  background-color: hotpink;
}

3.使用绝对定位

.content{
    position: relative;
    width: 100%;
    height: 500px;
}

.left{
    background: pink;
    width: 200px;
    position: absolute;
}

.right{
    background: hotpink;
    position: absolute;
    left: 210px;
    right: 0;
}

3.使用flex布局

.content{
    width: 100%;
    height: 500px;
    display:flex;
}

.left{
    background: pink;
    width: 200px;
    margin-right:10px;
}

.right{
    background: hotpink;
    flex:1;
}

4.float和BFC

设置右侧overflow:hidden触发BFC

.left {
  float: left;
  width: 200px;
  background-color: pink;
}

.right {
  margin-left: 210px;
  overflow: hidden;
  background-color: hotpink;
}

我们可以看到以上几种的表现方式都是这样子的

[提醒:使用浮动的方式记得要清除浮动],我们在上面已经说过几种清除浮动的方式咯

三列布局

圣杯布局

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Document</title>
  <style>
    * {
      padding: 0;
      margin: 0;
    }

    .container {
      padding: 0 100px;
    }

    .middle,
    .left,
    .right {
      position: relative;
      float: left;
    }

    .left {
      width: 100px;
      height: 100px;
      background: red;
      margin-left: -100%;
      left: -100px;
    }

    .right {
      width: 100px;
      height: 100px;
      background: green;
      margin-left: -100px;
      right: -100px;
    }

    .middle {
      background: blue;
      width: 100%;
      height: 300px;
    }
  </style>
</head>

<body>
  <div class="container">
    <div class="middle"></div>
    <div class="left"></div>
    <div class="right"></div>
  </div>
</body>

</html>

另外两种版本分别是使用绝对定位和flex布局,这两种版本更好理解。下面贴出代码

绝对定位版:

<style>
  * {
    margin: 0;
    padding: 0;
  }

  .container {
    position: relative;
  }

  .left,
  .right {
    top: 0;
  }

  .middle {
    margin: 0 100px;
    height: 300px;
    background-color: hotpink;
  }

  .left {
    position: absolute;
    left: 0;
    width: 100px;
    height: 100px;
    background-color: pink;
  }

  .right {
    position: absolute;
    right: 0;
    width: 100px;
    height: 100px;
    background-color: pink;
  }
</style>

flex版本:

<style>
  * {
    margin: 0;
    padding: 0;
  }

  .container {
    display: flex;
    overflow: hidden;
  }

  .middle {
    flex: 1;
    height: 200px;
    background-color: hotpink;
  }

  .left {
    order: -1;
    flex-basis: 100px;
    height: 100px;
    background-color: pink;
  }

  .right {
    flex-basis: 100px;
    height: 100px;
    background-color: pink;
  }
</style>

效果图都是像下面这样滴

双飞翼布局

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      padding: 0;
      margin: 0;
    }

    .container {
      overflow: hidden;
    }

    .middle,
    .left,
    .right {
      float: left;
      height: 100px;
    }

    .left {
      width: 100px;
      background: pink;
      margin-left: -100%;
    }

    .right {
      width: 100px;
      background: pink;
      margin-left: -100px;
    }

    .middle {
      width: 100%;
      background: hotpink;
    }

    .inner {
      margin: 0 100px;
    }
  </style>
</head>

<body>
  <div class="container">
    <div class="middle">
      <div class="inner"></div>
    </div>
    <div class="left"></div>
    <div class="right"></div>
  </div>
  </head>

</body>

</html>

flex版本:

<style>
  * {
    padding: 0;
    margin: 0;
  }
  .container {
    display: flex;
  }
  .middle,
  .left,
  .right {
    height: 100px;
  }
  .middle {
    flex: 1;
    background-color: hotpink;
  }
  .left {
    order: -1;
    flex-basis: 100px;
    background-color: pink;
  }
  .right {
    flex-basis: 100px;
    background-color: pink;
  }
</style>

两者区别

两者都是为了不让左右俩个东西遮住middle,经典圣杯布局通过父亲padding给左右俩腾位置从而不会遮住middle内容,而双飞翼是middle设置margin,限制内部内容区域,从而左右俩遮的地方不会影响到middle内容

对于三栏布局,最优解其实还是flex布局,当然用grid布局也行,只是兼容性没那么好,这两种方式都可以轻松实现多列布局,也可以控制顺序,middle依然可以先渲染,不管IE浏览器的话,最优解还是flex布局(业界毒瘤IE)

重绘和重排(回流)

  • 重绘:给元素设置一些CSS样式,但不改变形状。比如说visibilitycolorbackground-coloroutline这些之类的就会触发重绘,重绘不会重新布局。重绘不一定重排

  • 重排:元素发生形状的变化,位置的变化,渲染树需要重新计算就会触发重排。像设置display:none; 页面首次渲染 激活伪类元素如:hover增删DOM元素移动元素位置改变窗口大小这些都会发生重排。重排必定重绘。

如何优化?

  • 减少重绘和重排的发生次数:比如我们修改元素的样式,可以将多次修改合并成一次修改

    const el = document.querySelector('.test')
    el.style.margin = '5px'
    el.style.paddingTop = '2px'
    el.style.paddingBottom = '5px'
    
    

    这里对DOM元素进行了多次的样式修改,每一次修改都会触发重排(现代浏览器已经做过优化,会合并成一次重排。但是旧的浏览器还是会触发多次)。所以我们就需要进行合并处理

    const el = document.querySelector('.test')
    el.style.cssText += 'margin: 5px; padding-top: 2px; padding-bottom: 5px;'
    
    

    或者直接给el添加一个新的样式类

    const el = document.querySelector('.test')
    el.className += ' test2'
    
    
  • 批量对DOM元素进行修改:

    1.先让元素脱离文档流,然后display:none隐藏元素,对DOM元素进行修改,然后display: block重新显示。这里隐藏和显示DOM元素会触发重排,但是对DOM元素修改的过程并不会,这样可以减少重排次数

    2.使用文档片段document.createDocumentFragment()

    const ul = document.querySelector("ul")
    const fragment = document.createDocumentFragment()
    for (let i = 0; i < 20; i++) {
        let li = document.createElement("li")
        li.innerHTML = "index: " + i
        fragment.appendChild(li)
    }
    ul.appendChild(fragment);
    
    
  • 对于复杂动画,可以将其设置为绝对定位,脱离文档流,不然会引起它的父元素和后续元素进行频繁的重排

  • CSS优化:

    1.避免使用table布局

    2.避免设置内联样式

    3.少用calc表达式,会频发触发重排

    4.将动画设置到脱离文档流的元素上面

  • 使用CSS3的硬件加速:可以触发硬件加速的属性有:transform(过渡)opacity(透明度)filters(滤镜)will-changewill-change属性参考

z-index什么时候会失效

  • 父标签的position设置为relative
  • 父标签的z-index设置得特别小的时候
  • 问题标签没有设置position(除了static)以外的属性
  • 问题标签设置了浮动

总结

大部分公司都是喜欢一开始先来问几道CSS的题,所以我们还是要注重这一块,这里的题都是常见题,有必要好好去掌握