「2024」前端高频面试题之HTML&CSS篇

2,119 阅读31分钟

[TOC]

『前言』: 近期在梳理前端相关的高频面试题,参考文献:高程3、高程4、w3c、MDN等,分享出来一起学习。如有问题,欢迎指正。持续更新中~

内容共分为:html、css、js、ES6、ts、vue、小程序、git、网络请求相关,本篇内容是: 2024」前端高频面试题之HTML&CSS篇

前端面试题系列文章:

持续更新中~

1,面试题之HTML篇

1,!DOCTYPE (文档类型)的作用

DOCTYPE的全称是Document Type,对应中文:文档类型

<!DOCTYPE>必须声明在html文档的第一行

它的目的是告诉浏览器(解析器)以什么样(html或xhtml)的文档类型定义来解析文档

浏览器渲染页面有两种模式:标准模式、混杂模式。可以通过document.compatMode获得

  • 标准模式(CSS1Compat):也是默认模式,浏览器使用W3C的标准解析渲染页面,标准模式中,浏览器以其支持的最高标准呈现页面
  • 混杂模式(BackCompat):也是怪异模式,浏览器使用自己的怪异模式解析渲染页面,怪异模式中,浏览器以一种宽松的向后兼容的方式显示

2,HTML meta viewport属性

meta是元数据元素,用来表示那些不能由其他html元相关元素表示的元数据信息。比如:link、script、title标签

HTML meta viewport属性是用于控制网页在移动设备上的显示方式的,它可以通过设置不同的值来调整网页的缩放比例、布局和视口大小,以适应不同设备的屏幕尺寸和分辨率

常见的meta viewport属性值包括:

1width: 设置视口的宽度,可以使用具体的像素值比如width=600,也可以使用特定的关键字比如width=device-width表示视口宽度等于设备屏幕的宽度
2,initial-scale: 设置初始缩放比例,可以使用具体的数字值比如initial-scale=2.0,或者使用特性的关键值比如initial-scale=1.0表示不进行缩放
3,minimum-scale和maximum-scale:设置允许用户进行缩放的最小和最大比例
4,user-scalable:设置用户是否可以手动缩放网,可以设置为yes或no,通过设置不同的meta viewport属性值,开发者可以实现响应式设计,使网页在不同设备上呈现出最佳的显示效果

3,对 HTML 语义化 的理解?语义元素有哪些?语义化的优点

语义 = 意义, 语义元素 = 有意义的元素

  • 根据内容来选择合适的标签

  • 语义元素:

    1.<article>内容区域</article>
    2.<section>区块</section>
    3.<main>主要区域</main>
    4.<aside>侧边栏</aside>
    5.<dialog>定义对话框</dialog>
    6.<header>头部</header>
    7.<nav>导航</nav>
    8.<footer>页脚</footer>
    
  • 语义化的优点

    • 代码结构清晰:没有css的情况下,也能呈现出很好的内容结构
    • 增加可读,开发者能清晰的看出网页的结构,便于团队的开发和维护
    • 有利于SEO:方便浏览器爬虫更好的识别内容

4,HTML中 title 、alt 属性的区别

  • alt属性 用在img标签,当图片不显示的时候会出现 alt属性里面的内容,当图片显示的时候不会显示
  • title属性 用在除了htmlheadscriptmetabasebasefont之外的所有标签,title属性是当鼠标放在标签上的时候,会出现一些提示信息

5, src、href 、url 之间的区别

  • 1,含义
    • src 引用资源替代当前元素,在imgscriptiframe中使用
    • href 是超文本引用,指向网络资源所在位置,建立和当前元素或者锚点或者当前文档之间的链接
    • url 是统一资源定位符,一般来说,对于同一服务器上的文件,应该总是使用相对url用于资源定位
".": 表示目前所在的目录,相对路径
"D:/aaa/": 表示根目录,绝对路径
  • 区别
    • a、link标签使用 href, href用于在涉及的文档和外部资源之间建立一个关系 ,href 指向网络资源所在位置,建立和当前元素(锚点)或当前文档(链接)之间的联系
    • img、script、iframe标签使用src, 在可替换的元素上使用src ,在请求 src 资源时会将其指向的资源下载并应用到文档中,比如 JavaScript 脚本,img 图片
    • url 是统一资源定位符,一般来说,对于同一服务器上的文件,应该总是使用相对url用于资源定位

6,script标签中的 async、defer 的区别

我们知道当浏览器加载html的时候一旦遇到了script标签,就会停下来先把script标签里面的内容给执行掉,如果script标签引入的是外部文件,那就必须等待下载和执行完才会继续往下加载,如果外部文件刚好是在一个网络情况较差的服务器上,这样整个网页的加载都会受到很大的影响,这就是同步带来的阻塞弊端。

async 异步 defer 推迟, 他们两个都是异步加载js,不同的是async是js一加载完就会马上执行,不管html有没有解析完毕,所以它有可能阻塞html解析。而defer要等到html解析完毕之后才执行,所以不会阻塞html解析

async和defer属性只有在script标签有src属性的时候才有效

小问题:

let script = document.createElement('script');
script.src = 'xxxxx';
// 以上这种形式创建的js是async还是defer呢?创建的script标签会默认设置async为true

7, 行内元素、块级元素、空(void)

  • 行内:abspaninputimgselectstrong

  • 块级:pdivh1ulollidldtdd

  • 空:<hr><br><img><input><link><meta>

8, Html5新特性

html5不是一种编程语言,而是一种描述性的标记语言,用于描述超文本中的内容和结构

1, 语义标签
header头部区域
footer底部区域
nav导航
article文章
aside内容之外的内容比如侧边栏
section文档中的节
2, 表单功能增强

2.1,新增表单类型

邮箱标签: <input type="email">
数字标签: <input type="number">
滑动条标签: <input type="range">
搜索框标签: <input type="search">
日期框: <input type="date">
星期框: <input type="week">
月份框: <input type="month">
颜色框: <input type="color">
网址框: <input type="url">
<input type="submit">
<input type="reset">

2.2,新增表单属性

placehoder 输入框默认提示文字
required   要求输入的内容是否可为空
pattern    描述一个正则表达式验证输入的值
min/max    设置元素最小/最大值
step       为输入域规定合法的数字间隔
height/wdith 用于image类型<input>标签图像高度/宽度
autofocus  规定在页面加载时,域自动获得焦点
multiple   规定<input>元素中可选择多个值

2.3,新增表单事件

oninput 每当input里的输入框内容发生变化都会触发此事件

oninvalid 当验证不通过时触发此事件

3,新增了音频和视频
4,新增 canvas 绘图

canvas是在页面中设定一个区域,就可以通过 js 动态的在这个区域中绘制图形

// canvas用法
<canvas id="draw" width="300" height="300">当浏览器不支持 canvas 标签的时候会显示这行文字</canvas>

let draw = document.querySelector("#draw");
console.log(draw);
// 判断是否支持canvas元素
if (draw.getContext) {
  let context = draw.getContext("2d"); // 通过getContext("2d") 获取 2d 的上下文对象
  context.fillStyle = "#fc5531";
  context.fillRect(10, 10, 300, 300); 
  // 通过fillRect方法绘制的矩形用指定的fillStyle颜色填充,四个参数分别是矩形的x、y坐标、宽、高
}
5,新增 svg 绘图

svg 和 canvas 的区别:

  • canvas 可以随时使用js绘制 2D 图形
  • svg 是基于xml的,意味着可以操作DOM,渲染速度较慢
  • 在 svg 中每个形状都被当作是一个对象,如果 svg 发生改变,页面会发生重绘
  • canvas 事1像素1像素的渲染,如果改变某一个位置,整个画布会重绘
// svg用法
<svg>   // text元素添加文本,x、y定义文本的起点和终点
  <text x="0" y="10">svg text</text>
</svg>

<svg>  // cx、cy分别表示新坐标  r是半径 fill是图形的颜色
  <circle cx="20" xy="50" r="100" fill="#00b96b" />
</svg>

<svg>  // x, y 是起始坐标,width 和 height 是图形的宽高
  <rect x="0" y="0" width="100" height="100" fill="#00b96b" />
</svg>

<svg height="300" width="300">
    <path d="M 100 100 L 200 200 H 10 V 20" fill="#1cbbb4"  />
</svg>
/  
	d 包含方向命令。这些命令以命令名和一组坐标开始:
	M 表示移动,它接受一组 x,y 坐标 
	L 表示直线将绘制到它接受一组 x,y 
	H 是一条水平线,它只接受 x 坐标 
	V 是一条垂直线,它只接受 y 坐标 Z 表示关闭路径,并将其放回起始位置
/
6,地理定位
  • 使用 getCurrentPosition() 方法来获取用户的位置
  • 可以基于此实现计算位置距离
7,拖放API
  • 设置元素为可拖放:为了使元素可拖动,把 draggable 属性设置为 true
<p>把图片拖放到矩形中:</p>
<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
<br />
  <img
id="drag1"
src="https://img-home.csdnimg.cn/images/20240218021830.png"
draggable="true"
ondragstart="drag(event)"
/>
  
function allowDrop(ev) {
  ev.preventDefault();
}

function drag(ev) {
  ev.dataTransfer.setData("Text", ev.target.id);
}

function drop(ev) {
  ev.preventDefault();
  var data = ev.dataTransfer.getData("Text");
  ev.target.appendChild(document.getElementById(data));
}

/*
	dragstart 事件在用户开始拖动元素或被选择的文本时调用
	dragover 事件在可拖动的元素或者被选择的文本被拖进一个有效的放置目标时(每几百毫秒)触发
	dragenter 事件在可拖动的元素或者被选择的文本进入一个有效的放置目标时触发
	dragleave 事件在拖动的元素或选中的文本离开一个有效的放置目标时被触发
	dragend 事件在拖放操作结束时触发(通过释放鼠标按钮或单击 escape 键)
	drag 事件在用户拖动元素或选择的文本时,每隔几百毫秒就会被触发一次
	drop 事件在元素或文本选择被放置到有效的放置目标上时触发。为确保 drop 事件始终按预期触发,应当在处理 dragover 事件的代码部分始终包含 preventDefault() 调用
*/
8, Web Worker

Web Worker 是在主线程之外运行的

用于解决JS单线程中,持续较长的计算,而影响用户的交互

主要用法: 提供主线程和新线程之间数据交换的接口:postMessage、onmessage

// 01.html主线程
var workder = new Worker("./01.js"); // 创建指向工具js的实例对象
workder.postMessage("我是主线程发送的信息"); // 通过postMessage发送主线程的信息
workder.onmessage = function (evt) {
  //接收worker.js传过来的数据函数
  console.log("worker.js发送来的数据=====", evt.data); //输出worker.js发送来的数据
};


// 01.js
onmessage = function (evt) {
  var data = evt.data; //通过evt.data获得发送来的数据
  postMessage(`${data}哈哈哈哈`); //将获取到的数据发送会主线程
};

9, Web Storage

Web Storage API 提供了浏览器可以存储键/值对的机制,其方式比使用 cookie 更直观

Web Storage 包含如下两种机制:

sessionStorage 为每一个给定的源(origin)维持一个独立的存储区域,该存储区域在页面会话期间可用(即只要浏览器处于打开状态,包括页面重新加载和恢复)。

  • 仅为会话存储数据,这意味着数据将一直存储到浏览器(或选项卡)关闭。
  • 数据永远不会被传输到服务器。
  • 存储限额大于 cookie(最大 5MB)

localStorage 做同样的事情,但即使浏览器关闭并重新打开也仍然存在。

  • 存储的数据没有过期日期,只能通过 JavaScript、清除浏览器缓存或本地存储的数据来清除。
  • 存储限额是两者之间的最大值

这两种机制是通过 Window.sessionStorageWindow.localStorage 属性使用,调用其中任一对象会创建 Storage 对象,通过 Storage 对象,可以设置、获取和移除数据项。对于每个源 sessionStoragelocalStorage 使用不同的 Storage 对象——独立运行和控制

sessionStorage 、 localStorage 可使用的API相同如下:

保存数据:localStorage.setItem(key,value)
读取数据:localStorage.getItem(key)
删除单个数据:localStorage.removeItem(key)
删除所有数据:localStorage.clear()
得到某个索引的key:localStorage.key(index)
10, WebSocket

WebSocket 是一种在单个 TCP 连接上进行 全双工 通讯的协议(双向通信协议)

什么是全双工:

是通信传输的一个术语,通信允许数据在两个方向上同时传输,在能力上相当于两个单工通信方式的结合。全双工指可以同时进行信号的双向传输(A→B且B→A,)即A→B的同时B→A,是瞬时同步的

与双工通信对应的是单工通信,单工通信就是在只允许A向B发送信息,而乙方不能向甲方传送 。在全双工和单工之间,还有一种通信方式叫“半双工”,是指一个时间段内只允许A向B发送信息,另一个时间段内只允许B向A发送信息,也就是说A和B通过时间段的组合完成双向通信。

列举现实中的例子可以帮助我们更容易理解这些通信方式。
我们日常使用的移动电话、固定电话以及各种远程工作的会议系统都是全双工通信的方式,半双工的通信工具比较典型的是对讲机,某些调度系统也还在使用半双工的方式。单工通信依然非常普遍,例如广播(FM)、电视等

WebSocket 实现客户端和服务端之间的双向通信,允许服务端主动向客户端推送数据,在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输。

WebSocket 和 HTTP 的区别:

他们都是基于TCP的传输协议, WebSocket 可以双向发送和接受数据,而 HTTP 是单向的(HTTP通信只能由客户端发起,不具备服务器主动推送的能力), WebSocket 的使用,需要先进行一次客户端和服务器的握手,两者建立连接后才可以正常双向通信,而HTTP是一个主动的请求对应一个被动的响应

WebSocket 的协议标识符?

如果服务器网址是 HTTP 那么 WebSocket 对应的是 ws

如果服务器网址是 HTTPS 加密的 那么 WebSocket 对应的是 wss

WebSocket 是为了能够实现在 web 应用上与服务器进行双向通信的需求 而产生出来的协议,

相比于轮询 HTTP 请求的方式,WebSocket 节省了服务器资源,有效的提高了效率

WebSocket 常用方法:

  • Socket.send():通过 Socket 向服务器发送信息
  • Socket.close():关闭 Socket 连接

WebSocket 常用属性:

  • Socket.readyState获取当前链接状态 0:正在连接中,1:连接正常可以通信,2:连接关闭中,3:连接已关闭/连接失败
  • Socket.url获取当前连接地址
  • Socket.binaryType获取传输的数据类型

WebSocket 生命周期:

  • Socket.onopen:连接建立时触发
  • Socket.onmessage : 客户端接收服务端数据时触发
  • Socket.onerror : 通信发生错误时触发
  • Socket.onclose : 连接关闭时触发

9,浏览器渲染页面的步骤

  • 1,解析html,生成DOM树;解析CSS,生成CSSOM树
  • 2,将DOM树和CSSOM树结合,生成渲染树(Render Tree)
  • 3,Layout(回流):根据生成的渲染树,计算它们在设备视口(viewport)内的确切位置和大小,这个阶段是回流
  • 4,Painting(重绘):根据渲染树以及回流得到的几个信息,得到节点的绝对像素
  • 5,Display:将像素发送给GPU,展示在页面上

10,DOM的重绘(Repaint)和重排(回流)(Reflow)

1,重绘

重绘: 元素样式的改变(但宽高、大小、位置等不变)

  • 比如我只是把当前元素的背景颜色变了
  • Outline、visibility、color、background-color等
2,重排

重排:元素的大小或者位置发生变化(当页面布局和几何信息发生变化的时候),触发了重新布局,导致渲染树重新计算布局和渲染

  • 如添加或者删除可见的DOM元素
  • 元素的位置发生变化
  • 元素的尺寸发生变化
  • 内容发生变化(比如文本变化或者图片被另一个不同尺寸的图片所替代)
  • 页面一开始渲染的时候,这个无法避免,因为回流是根据视口大小来计算元素的位置和大小的,所以浏览器的窗口尺寸变化会引发回流
  • 回流就是结构得重新算这就是回流

注意:重排一定会触发重绘,重绘不一定触发重排

3,避免DOM的回流的方案
1,放弃传统操作DOM的时代,基于vue/react开始数据影响视图模式

Mvvm、mvc、virtual dom、dom diff

2,DOM操作的分离读写(现代的浏览器都有渲染队列的机制)
offsetTop、offsetLeft、offsetWidth、offsetHeight、clientTop、clientLeft、clientWidth、clientHeight、scrollTop、scrollLeft、scrollWidth、scrollHeight、getComputedStyle、currentStyle....这些都会刷新渲染队列
<div id="box"></div>
box.style.width = "100px";
box.style.height = "100px";
box.style.background = "red";   // => 重绘制
box.style.margin = "20px auto";
// => 以上代码会引发几次回流(重排)?
// => 1次
// => 因为现代版浏览器都有“渲染队列”机制:发现某一行要修改元素的样式,不立即渲染,而是看看下一行,如果下一行也会改变样式,则把修改样式的操作放到“渲染队列中”.....一直到不再是修改样式的操作后,整体渲染一次,引起一次回流

读写分离:

box.style.width = "100px";  // => 写
console.log(box.offsetWidth)   // => 读
box.style.height = "100px";  // => 写
console.log(box.offsetHeight)   // => 读
box.style.background = "red";  // => 写
box.style.margin = "20px auto";  // => 写
// => 以上读的时候(console.log(box.offsetWidth)),会引发一次回流,所以以上代码会引发3次回流。所以要读写分离

box.style.width = "100px";  // => 写
box.style.height = "100px";  // => 写
box.style.background = "red";  // => 写
box.style.margin = "20px auto";  // => 写
console.log(box.offsetWidth)   // => 读
console.log(box.offsetHeight)   // => 读
// => 把读和写分开来做
3,样式集中改变
.box {
  width: 100px;
  height: 100px;
  background-color: aqua;
  margin: 20px auto;
}
<div id="boxId"></div>

// 方式一:
div.className = 'box'

// => 方式二:
div.style.cssText = 'width: 20px; height: 20px'
4,缓存布局信息(它的原理是读写分离)
div.style.left = div.offsetLeft + 1 + 'px'
div.style.top = div.offsetTop + 1 + 'px'

// => 改为
var curLeft = div.offsetLeft
var curTop = div.offsetTop
div.style.left = curLeft + 1 + 'px'
div.style.top = curTop + 1 + 'px'
5,元素批量修改

1, 文档碎片:createDocumentFragment

// => 假设我想给box动态加10个 span 
<div id="box"></div>
for (let i = 0; i < 10; i++) {
  let span = document.createElement("span");
  span.innerHTML = i;
  box.appendChild(span);
}
// => 以上方法引发10次回流

// => 方式1: 使用文档碎片
let frg = document.createDocumentFragment();
// 文档碎片:存储文档的容器
for (let i = 0; i < 10; i++) {
  let span = document.createElement("span");
  span.innerHTML = i;
  frg.appendChild(span);
}
box.appendChild(frg);
frg = null
// => 引发一次回流

// => 方式2: 使用模版字符串拼接
let str = ``;
for (let i = 0; i < 10; i++) {
  str += `<span>${i}</span>`;
}
box.innerHTML = str;
// => 引发一次回流
6,动画效果应用到position属性为absolute或者fixed的元素上,因为它们脱离文档流,不会引发其他元素的回流
7,CSS3硬件加速(GPU加速)

比起考虑如何减少回流重绘,我们更期望的是,根本不要回流重绘:transform/opacity/filters...这些属性会触发硬件加速,不会引发回流和重绘

可能会引发的坑:过多使用会占用大量内存,性能消耗严重,有时候会导致字体模糊等

8,牺牲平滑度换取速度

每次1像素移动一个动画,但是如果此动画使用了100%的CPU,动画就会看上去是跳动的,因为浏览器正在与更新回流做斗争,每次移动3像素可能看起来平滑度低了,但它不会导致CPU在较慢的机器中抖动

9,避免table布局和使用css的javascript表达式

2,面试题之 CSS 篇

1,介绍一下 CSS 的盒子模型

w3c 规范中,盒子模型被定义为一个元素所占用的网页空间。

盒模型由4部分组成:margin(外边距)、border(边框)、padding(内边距)、content(内容)

盒子大小的计算模型有两种:标准盒模型、IE盒模型,通过改变 css 的box-sizing属性的值来改变

两种盒模型的区别在于设置 width 和 height 的时候,对应的范围不同。

  • 标准盒模型:box-sizing的值为content-box(也是默认值),这种行为模式下,盒子的宽和高只决定元素的content内容部分,而 padding 和 border 是在 content 外部另外绘制,也就是说 width = content

    div {
      width: 100px;
      padding: 15px;
      border: 2px solid #ccc;
      margin: 30px;
      box-sizing: content-box;
    }
    

  • IE盒模型:box-sizing的值为border-box,这种行为模式下,为盒子设定的宽和高决定了元素的大小,盒子的 padding 和border 都将在已设定好的宽高内绘制,也就是说 width = content + padding + border

2,CSS3新特性

  • 1,边框:

    • 圆角效果border-radius

      border-radius10px 20px 30px 40px; /** 4个值分别表示左上角,右上角,右下角,左下角 */
      
    • 边框阴影border-shadow

      border-shadow: X轴偏移量 Y轴偏移量 阴影模糊半径 扩散半径 阴影颜色;
      比如:
      	/** x 偏移量 | y 偏移量 | 阴影模糊半径 | 阴影扩散半径 | 阴影颜色 */
      	box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.2);
      	
      	/** 任意数量的阴影,以逗号分隔 */
      	box-shadow: 3px 3px red, -1em 0 0.4em olive;
      
  • 2,颜色:

    • rgba

      r g b三个参数取值范围都是:0~255或者0.0%~100%,

      a 为透明度,取值范围为:0~1

      background-color: rgba(255,255,255,0.3);
      
    • 渐变

  • 3,文字与字体:

    • text-overflow

      text-overflow用于提示用户存在隐藏的溢出内容,其形式显示一个省略号或者一个自定义字符串

      text-overflow:clip(表示剪切) | ellipsis(表示显示省略标记);
      

      但是text-overflow只是用来说明文字溢出时用什么方式显示,要实现溢出时产生省略号的效果,还须其他条件:

      定义强制文本在一行显示(white-space:nowrap) 溢出内容为隐藏(overflow:hidden)

      text-overflow:ellipsis;
      overflow:hidden;
      white-space:nowrap;
      

      word-wrap用来设置文本行为,当前行超过指定容器的边界时是否断开转行

      word-wrap:normal |break-word;
      
    • 文字阴影text-shadow

      text-shadow:x-offset y-offset blur color; /** 阴影水平偏移距离 阴影垂直偏移距离 阴影模糊程度 阴影颜色*/
      
  • 4,css变形

    • 旋转 rotate(): 相对原点进行旋转
    • 缩放 scale(): 根据中心原点对对象进行缩放
  • 5,盒模型 box-sizing

    box-sizing: content-box | border-box | inherit  /** inherit:使元素继承父元素的盒模型模式 */
    
  • 6,弹性布局 flexbox 阮一峰Flex布局教程

    Flex布局将在下面详细介绍👇

  • 7,动画 animation

3,Flex弹性布局

常见的考题:

1,flex: 1表示什么

flex: 1flex-growflex-shrinkflex-basis的缩写,默认值是0 1 auto

``flex:1flex: 1 1 auto`

  1. flex-grow定义项目放大比例,默认为0,即如果存在剩余空间,也不放大
  2. flex-shrink定义项目的缩小比例,默认为1,即如果空间不足,该项目将缩小
  3. flex-basis定义在分配多余空间之前,项目占据的主轴空间,浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小

2,看效果写代码或者说出实现思路

<div class="container">
  <div class="item"></div>
  <div class="item"></div>
	<div class="item"></div>
</div>
.container {
  width: 200px;
  height: 200px;
  background-color: rgb(239, 253, 212);
  display: flex;
  justify-content: space-between;
}
.item {
  width: 60px;
  height: 60px;
  background-color: rgb(144, 0, 255);
}
.container div:nth-of-type(2) {
  align-self: center;
}
.container div:nth-of-type(3) {
  align-self: flex-end;
}

3,看效果说出实现的思路

<div class="container">
  <div class="first">
    <div class="item"></div>
    <div class="item"></div>
  </div>
  <div class="second">
  	<div class="item"></div>
  </div>
  <div class="second">
    <div class="item"></div>
    <div class="item"></div>
  </div>
</div>
.container {
  width: 200px;
  height: 200px;
  background-color: rgb(239, 253, 212);
  display: flex;
  justify-content: space-between;
}
.item {
  width: 60px;
  height: 60px;
  background-color: rgb(144, 0, 255);
}
.first,
.three {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
.second {
  align-self: center;
}

4,看效果说出实现思路

<div class="container">
  <div class="first">
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
  </div>
  <div class="second">
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
  </div>
</div>
.container {
  width: 200px;
  height: 200px;
  background-color: rgb(239, 253, 212);
  display: flex;
  justify-content: space-between;
}
.item {
  width: 80px;
  height: 80px;
  margin-bottom: 3px;
  background-color: rgb(144, 0, 255);
}
.first,
.second,
.three {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

更多案例参考阮一峰大佬的Flex教程

下面简单介绍一下Flex布局:

任何一个容器都可以指定为 Flex 布局:display: flex; 行内元素也可以使用 Flex 布局:display: inline-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
  • justify-content
  • align-items
  • align-content

1,flex-direction:决定主轴的方向(即项目的排列方向)

flex-direction: row | row-reverse | column | column-reverse;
                row(默认值):主轴为水平方向,起点在左端。
                row-reverse:主轴为水平方向,起点在右端。
                column:主轴为垂直方向,起点在上沿。
                column-reverse:主轴为垂直方向,起点在下沿

2,flex-wrap:如果一条轴线排不下,如何换行

flex-wrap: nowrap | wrap | wrap-reverse;
            nowrap(默认):不换行
            wrap:换行,第一行在上方
            wrap-reverse:换行,第一行在下方

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

flex-flow: <flex-direction> || <flex-wrap>;

4,justify-content:定义项目在主轴上的对齐方式

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

5,align-items:定义项目在垂直的交叉轴上如何对齐

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

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

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

其他内容就不写了,可以看阮神的Flex教程](www.ruanyifeng.com/blog/2015/0…

4,CSS选择器和优先级

选择器

选择器权重
id选择器 #id100
类选择器 .classname10
属性选择器 div[class="foo"]10
伪类选择器 div::last-child10
标签选择器 div1
伪元素选择器 div:after1
兄弟选择器 div+span0
子选择器 ui>li0
后代选择器 div span0
通配符选择器0

优先级

!important > 内联样式 > ID选择器 > 类选择器/伪类选择器/属性选择器 > 标签选择器/伪元素选择器 > 关系选择器/通配符选择器

5,伪元素和伪类的区别

  • 伪元素创建了一个新元素,用::表示,比如::before或者::after(目前一部分浏览器为了达到一个更好的兼容性效果,双冒号可以写成单冒号,但是一些低版本浏览器还是不支持的)
  • 伪类是一个已经存在的元素但是不能被我们看到, 用:表示,比如::hover

常见的伪元素有哪些:

  • ::before、::after表示元素内容区域的前面、后面
  • ::first-letter 表示第一个字
  • ::first-line 表示第一行
  • ::section 表示选中部分
  • ::placeholder 表示占位文本

常见的伪类:

  • :link 未点击的时候
  • :visited 点击时
  • :hover 悬停时
  • :active 被激活时
  • :focus 聚焦时
  • :not(x) 不是x
  • :first-child 第一个
  • :last-child 最后一个
  • :nth-child(x) 第x个
  • :nth-last-child(x) 倒数第x个
  • :checked 选中
  • :disabled 禁用

6,移动端 1px 问题及解决办法

1,认识设备的物理像素(设备像素)、逻辑像素(css像素)、设备像素比dpr
  • 物理像素:设备在出厂的时候,不同设备自带的不同像素就是UI设计师使用的像素
  • 逻辑像素:也就是我们开发时css记录的像素
  • DPR(devicePixelRatio) 设备像素比,它是设备像素和CSS像素的比值,可以用 js 中的window.devicePixelRatio来获取:dpr = 物理像素 / CSS像素

在移动端开发中,UI设计稿中设置边框为 1 像素,前端在开发过程中设置 border = 1px,测试人员会发现在某些机型上 1px 会比较粗,这就是经典的移动端1px像素问题

2,产生 1px 问题的原因

自从 2010 年 iPhone4 推出了 Retina 屏开始,移动设备屏幕的像素密度越来越高,于是便有了 2 倍屏、3 倍屏的概念。简单来说,就是手机屏幕尺寸没有发生变化,但屏幕的分辨率却提高了一倍,即同样大小的屏幕上,像素多了一倍。所以移动端页面的 1px 会变得很粗,呈现出不止 1px 的效果,产生 1px 问题的主要原因就是dpr。

目前主流的屏幕dpr=2(iPhone6/7/8),或者dpr=3(iPhone X),拿2倍屏来说,dpr = 物理像素 / css像素,dpr为2,物理像素为1px,所以可以得出逻辑像素( css像素)为0.5px。一般设计稿是按750来设计的,它上面的1px是以750来参照的,而我们写css样式是以设备375为参照的,所以我们写0.5px即可。

3,解决办法
1,设置 viewportscale
<meta name="viewport" content="initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />
let viewport = document.querySelector("meta[name=viewport]");
//根据设备像素设置viewport
if (window.devicePixelRatio == 1) {
  viewport.setAttribute(
    "content",
    "width=device-width,initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
  );
}
if (window.devicePixelRatio == 2) {
  viewport.setAttribute(
    "content",
    "width=device-width,initial-scale=0.5, maximum-scale=0.5, minimum-scale=0.5, user-scalable=no"
  );
}
if (window.devicePixelRatio == 3) {
  viewport.setAttribute(
    "content",
    "width=device-width,initial-scale=0.3333333333333333, maximum-scale=0.3333333333333333, minimum-scale=0.3333333333333333, user-scalable=no"
  );
}
var docEl = document.documentElement;
var fontsize = 32 * (docEl.clientWidth / 750) + "px";
docEl.style.fontSize = fontsize;

2,利用伪元素
// 1border
div {
  position: relative;
  &::after {
    position: absolute;
    content: "";
    background-color: red;
    top: 0;
    left: 0;
    width: 100%;
    height: 1px;
    transform: scale(1, 0.5);
  }
}

// 4border
div {
  position: relative;
  &::after {
    position: absolute;
    content: "";
    top: 0;
    left: 0;
    border: 1px solid red;
    width: 200%;
    height: 200%;
    transform-origin: left top;
    transform: scale(0.5);
  }
}
3,直接写0.5px
div {
  border-top: 0.5px solid red;
}

7,css 常见单位

  • px :物理像素,是相对于显示器屏幕分辨率的
  • emremem是相对于父元素的,rem相对于根元素html
  • vwvh:和浏览器窗口大小有关的单位,他们的参照对象都是浏览器窗口,
    • vw浏览器窗口宽度的百分比:假设浏览器宽度1000px,则`1vw = 浏览器窗口宽度的1% = 10px
    • vh,浏览器窗口高度的百分比:假设浏览器高度1000px,则1vh = 浏览器窗口高度的1% = 10px
  • %:是相对父元素的,当浏览器的宽和高改变时,当前元素也会根据比例发生改变

8,水平垂直居中、两栏布局、三栏布局的实现

1,水平垂直居中
1,利用绝对定位,设置四个方向的值都为0,并将margin设置为auto

由于宽高固定,因此对应方向实现平分,可以实现水平和垂直方向上的居中

.parent {
  position: relative;
}
.child {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  margin: auto;
}
2,利用绝对定位,再通过translate调整

先将元素的左上角通过top:50%left:50%定位到页面的中心,然后再通过translate来调整元素的中心点到页面的中心

.child {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
3,利用绝对定位,再通过margin负值进行调整

先将元素的左上角通过top:50%left:50%定位到页面的中心,然后再通过margin负值来调整元素的中心点到页面的中心

.child {
  position: absolute;
  top: 50%;
  left: 50%;
  margin-top: -40px;  /** 自身高度的一半 */
  margin-left: -40px; /** 自身宽度的一半 */
}
4,使用flex布局

通过align-items:centerjustify-content:center设置容器的垂直和水平方向上为居中对齐,然后它的子元素也可以实现垂直和水平的居中

.parent {
  display: flex;
  justify-content: center;
  align-items: center;
}
2,两栏布局

两栏布局非常常见,通常是一个宽度固定和一个宽度自适应的布局排列展示,如下形式展示

1,方法1:float + margin 实现
<div class="box">
  <div class="left">left</div>
  <div class="right">right</div>
</div>
.left {
  width: 200px;
  float: left;
}
.right {
  width: auto;
  margin-left: 200px;
}
2,方法2:左float,右overflow:hidden触发BFC

利用左float,右overflow:hidden这样右边就会触发BFC,BFC的区域不会与浮动元素发生重叠,所以两侧就不会发生重叠

.left{
  width: 200px;
	float: left;
 }
 .right{
   overflow: hidden;
 }
3,方法3:左绝对定位,右margin负值

将父级元素设置为相对定位。左边元素设置为absolute定位,并且宽度设置为200px。将右边元素的margin-left的值设置为200px

.box {
  position: relative;
}
.left {
  width: 200px;
  position: absolute;
}
.right {
  margin-left: 200px;
}
4,方法4:Flex布局

将左边元素设置为固定宽度200px,将右边的元素设置为flex:1

.box {
  display: flex;
}
.left {
  width: 200px;
}
.right {
  flex: 1;
}
3,三栏布局

三栏布局:两边固定,中间自适应

1,流体布局(float布局):

利用左右浮动,中间设置左右两个方向的margin值,注意⚠️:中间一栏必须放到最后

<div class="box">
  <div class="left">left</div>
  <div class="right">right</div>
  <div class="mid">middle</div>  /** 中间一栏必须放到最后 */
</div>
.left {
  width: 200px;
  float: left;
}
.right {
  width: 300px;
  float: right;
}
.mid {
  height: 200px;
  margin-left: 200px;
  margin-right: 300px;
}
2,BFC 布局:

两栏浮动,中间不做任何属性,这时中间栏默认是撑满全屏的,我们利用BFC的规则- BFC不会和浮动元素重叠,把中间元素改成BFC,使用overflow: hidden;或者display: flex;

<div class="box">
  <div class="left">left</div>
  <div class="right">right</div>
  <div class="mid">middle</div> /** 这种情况,中间一栏也必须放到最后 */
</div>
.left {
  width: 200px;
  float: left;
}
.right {
  width: 300px;
  float: right;
}
.mid {
  height: 200px;
  /* overflow: hidden; */
  display: flex; /** overflow: hidden; 或者 display: flex;  */
}
3,Flex布局:

父元素使用flex属性,中间使用flex: 1占据剩余空间

<div class="box">
  <div class="left">left</div>
  <div class="mid">middle</div>
  <div class="right">right</div>
</div>
.box {
  display: flex;
}
.left {
  width: 200px;
}
.right {
  width: 300px;
}
.mid {
  height: 200px;
  flex: 1;
}
4,position定位:

左右绝对定位,中间设置对应方向大小的margin值

.box {
  position: relative;
}
.left {
  width: 200px;
  position: absolute;
  top: 0;
  left: 0;
}
.right {
  width: 300px;
  position: absolute;
  top: 0;
  right: 0;
}
.mid {
  height: 200px;
  margin-left: 200px;
  margin-right: 300px;
}
5,圣杯布局:

利用浮动、负边距、相对定位实现。三列均设置左浮动,左右定宽,中间宽度100%,中间一列放在最前面,然后通过负边距进行调整,这时中间栏还是占据100%宽度,所以我们操作父元素给出和左右两栏相等的内边距,但是我们发现整体盒子被压缩了,所以我们再利用相对定位定到两边即可

<div class="box">
  <div class="mid">middle</div>
  <div class="left">left</div>
  <div class="right">right</div>
</div>
.box {
  padding-left: 200px;  /** 中间的元素宽度占满100%,所以文字被挡住了,我们操作父元素给出和左右两栏相等的内边距*/
  padding-right: 300px;
}
.left {
  width: 200px;
  float: left;
  margin-left: -100%; /** 先让三栏位于一行,左栏设置margin-left: -100%,此时左栏位于第一行首部*/
  position: relative;
  left: -200px;
}
.right {
  width: 300px;
  float: left;
  margin-left: -300px;
  position: relative;
  right: -300px;
}
.mid {
  width: 100%;
  float: left;
}
6,双飞翼布局:

双飞翼布局可以说是圣杯布局的改进版,他们达到的效果相同,都是侧边两栏宽度固定,中间栏宽度自适应。主要的区别在于解决中间部分被挡住的问题时,圣杯是在父元素上设置了左右内边距,再给左右设置相对定位,通过左移和右移即可。而双飞翼是在中间栏再加个div来放置内容,再给这个新的div设置margin值来避开遮挡即可

<div class="box">
  <div class="mid">
  	<div class="midContent">middle</div>
  </div>
  <div class="left">left</div>
  <div class="right">right</div>
</div>
.left {
  width: 200px;
  height: 200px;
  background-color: rgb(172, 254, 224);
  float: left;
  margin-left: -100%; /** 先让三栏位于一行,左栏设置margin-left: -100%,此时左栏位于第一行首部*/
}
.mid {
  float: left;
  width: 100%;
}
.midContent {
  height: 200px;
  background-color: yellow;
  margin-left: 200px;
  margin-right: 300px;
}
.right {
  width: 300px;
  height: 200px;
  background-color: rgb(228, 135, 249);
  float: left;
  margin-left: -300px;
}

9,link 和 @import的区别

两者都是外部引用css的方式,区别如下:

  • link是xhtml标签,除了引入css外,还可以用来定义RSS;@import属于css范畴,只能加载css
  • link引用css的时候,在页面载入时同时加载。 @import需要页面完全加载完成后加载
  • link是xhtml标签,无兼容问题,@import是css2提出来的,低版本的浏览器不支持
  • link支持js去控制DOM去改变样式,@import不支持

10,display 属性值及其作用

属性值作用
none元素不可见,并且会从文档流中移除
block块类型,默认宽度为父元素宽度,可设置宽高,换行显示
inline行内元素类型, 默认宽度为内容宽度,不可设置宽高,同行显示
inline-block默认宽度为内容宽度,可以设置宽高,同行显示
table此元素会作为块级表格来显示
inherit规定应该从父元素继承display属性的值
list-item像块类型元素一样显示,并添加样式列表标记

display的block、inline和inline-block的区别

(1)block:会独占一行,多个元素会另起一行,可以设置width、height、margin和padding属性 (2)inline:元素不会独占一行,设置width、height属性无效,但可以设置水平方向的margin和padding属性,不能设置垂直方向的padding和margin (3)inline-block:将对象设置为inline对象,但对象的内容作为block对象呈现,之后的内联对象会被排列在同一行内

11,position 常见的属性值

  • static :静态定位,top、bottom、left、right属性无效,等同于没有定位

  • relative :相对定位,top、bottom、left、right相对于该对象在标准文档流中的位置进行偏移

  • absolute :绝对定位,相对于static定位以外的第一个父元素进行定位

  • fixed :固定定位,相对于浏览器窗口进行定位

  • sticky :粘性定位,相对于用户滚动位置进行定位

12,隐藏元素的方法有哪些

  • Display: none; 渲染树不会包含该渲染对象,因此该元素不会在页面中占据位置,也不会影响绑定的监听事件
  • Visibility: hidden; 元素在页面中仍占据位置,但是不会响应绑定的监听事件
  • Opacity: 0; 将元素的透明度设置为0,元素在页面中仍占据位置,会响应绑定的监听事件
  • Position: absolute; 通过绝对定位将元素移除可视区域内
  • Z-index: 负值;来使其他元素遮盖住该元素
  • Transform: scale(0, 0)将元素缩放为0来实现元素的隐藏,元素在页面中仍占据位置,会响应绑定的监听事件

display: none; 和 visibility: hidden 的区别

(1)渲染树中

  • Display: none; 会让元素从渲染树中消失,不占位置
  • Visibility: hidden; 不会让元素从渲染树中消失,占据位置

(2)是否是继承属性

  • Display: none;是非继承属性,子元素会随着父元素消失而消失,通过修改子元素的属性无法使其显示
  • Visibility: hidden是继承性属性,子元素会随着父元素消失而消失,通过修改子元素的属性可以使其显示

13,CSS中可继承与不可继承属性

1,可继承
  • font-family、font-weight、font-size
  • line-height、color
  • visibility
2,不可继承
  • width、height
  • margin、padding、border
  • background
  • position、left、right、top、bottom
  • display

14,css 实现三角形

div {
    width: 0;
    height: 0;
    border-top: 50px solid pink;
    border-left: 50px solid transparent;
    border-right: 50px solid transparent;
  }
/**使用边框实现*/ 

15,BFC

1,什么是BFC?其规则是什么?

BFC的全称是Block formatting context 对应中文是:块级格式化上下文,它是一个独立的渲染区域,我们可以把BFC理解为一个封闭的容器,内部的元素无论怎么布局都不会影响外部,容器内的样式布局自然也不会受外界的影响。

它内部的规则有:

  • 1,BFC就是一个块级元素,块级元素会在垂直方向一个接一个排列
  • 2,BFC就是页面中的一个隔离的独立容器,容器里的标签不会影响到外部标签
  • 3,BFC区域不会与浮动的容器发生重叠
  • 4,属于同一个BFC的两个相邻元素的外边距会发生重叠,垂直方向的距离由两个元素中margin的较大值决定
  • 5,计算BFC的高度时,浮动元素也会参与计算
2,如何触发BFC

我们可以通过添加一些 css属性来触发,常见的有:

  • overflower除了visible以外的值
  • position的值设置为absolute或者fixed
  • display的值设置为inline-block或者flex
3,BFC到底可以解决什么问题呢
  • 1,它可以阻止元素被浮动元素覆盖,比如两栏布局

    <div class="left">left</div>
    <div class="right">right</div>
    .left {
      width: 100px;
      height: 100px;
      border: 1px solid aqua;
      float: left;
    }
    .right {
      background-color: rgb(255, 200, 209);
    }
    

由图可以看出,由于左边的div浮动后脱离文档流不占空间了,就会导致右边的div到了最左边,同时左侧浮动的div还会覆盖在上面,这时候我们就可以通过把右侧的div设置为一个BFC,比如可以给它添加display: flex来触发,就可以解决右侧被左侧覆盖的问题

.right {
  width: auto;
  background-color: rgb(255, 200, 209);
  display: flex;
}

  • 2,解决父元素没有高度,子元素设置为浮动元素时,产生的父元素高度塌陷的问题,比如一个容器内的两个div都是浮动元素,此时给父元素设置背景色是没有任何效果的,因为此时父元素的高度为0

    <div class="p">
      <div>1</div>
      <div>2</div>
    </div>
    
    .p div {
      width: 100px;
      height: 100px;
      border: 1px solid aqua;
      float: left;
    }
    .p {
      background-color: rgb(157, 255, 0);
    }
    

这时候我们就可以添加一个可以触发父元素BFC功能的属性,因为BFC有个规则是计算BFC的高度时,浮动元素也参与计算,所以触发BFC后,父元素的高度就会被撑开,也就是会产生清除浮动的效果

.p {
  background-color: rgb(157, 255, 0);
  overflow: hidden;
}

  • 3,可以解决margin边距重叠的问题,比如一个容器里有两个div,这两个div分别设置了自己的margin,一个是10px,一个是20px,正常两个盒子的垂直距离是30px,不然,我们会发现两个盒子之间的垂直距离是20px,这就是margin塌陷问题
<div>
  <div class="t">1</div>
  <div class="b">2</div>
</div>
.t,
.b {
  width: 100px;
  height: 100px;
  background-color: rgb(245, 108, 73);
  margin: 10px;
}
.b {
  background-color: paleturquoise;
  margin: 20px;
}

这就是margin塌陷问题,此时margin边距的结果为两个div间的较大值,如果我们想让margin外边距变为正常的30,可以触发一个div的BFC,它的内部就会遵循BFC规则,这样就可以为元素包裹一个盒子形成一个完全独立的空间,做到里面的元素不受外部元素的影响

<div>
	<div class="t">1</div>
	<div style="overflow: hidden">
		<div class="b">2</div>
	</div>
</div>