V8 引擎的优化机制

V8 是 Google 开发的 JavaScript 引擎(用于 Chrome、Node.js 等),它的核心优化机制可以总结为:即时编译(JIT) + 隐式类型优化 + 内联缓存 + 垃圾回收机制,通过这些方式来大幅提升 JS 的执行性能。 一、V8 的执行流程 V8 不直接解释执行 JavaScript,而是: 解析(Parser):将 JS 源码解析为 AST(抽象语法树) 生成字节码(Bytecode):由 Ignition 引擎生成并执行初始字节码 收集类型信息(Profiler):运行时收集变量类型、函数调用等信息 优化编译(JIT):将热点代码交给 TurboFan 引擎编译为高效的机器码 二、核心优化机制 1. 隐藏类(Hidden Class)与内联缓存(Inline Cache) 为了优化对象属性访问,V8 引入了隐藏类机制,类似 C++ 中的类结构: 初次创建对象时,生成一个隐藏类(HiddenClass) 添加属性时会生成新的隐藏类链表结构 相同结构的对象共享隐藏类,从而使访问更快 不要动态给对象添加属性,尽量保持对象结构稳定。 内联缓存:缓存某个属性的访问位置,使得后续同样结构的对象访问不必重新查找。 function Person(name) { this.name = name; } const p1 = new Person("Tom"); const p2 = new Person("Jerry"); // 内联缓存会优化 this.name 的访问路径 2. 类型反馈与优化编译(Type Feedback + JIT) V8 在执行字节码时会收集类型信息(比如函数参数、返回值的类型),并标记频繁调用的代码为“热点代码”: 热点代码会被交给 TurboFan 做优化编译 编译时使用收集到的类型信息来生成专用的机器码(类型特化) 例如: function add(a, b) { return a + b; } add(1, 2); // 优化为整数加法 add("a", "b"); // 类型变化 -> 去优化 不要在同一个函数中混用不同类型,可能导致优化失败或退化。 ...

December 17, 2024

浏览器的进程和线程

区分进程和线程 线程和进程区分不清,是很多新手都会犯的错误,没有关系。这很正常。先看看下面这个形象的比喻: - 进程是一个工厂,工厂有它的独立资源 - 工厂之间相互独立 - 线程是工厂中的工人,多个工人协作完成任务 - 工厂内有一个或多个工人 - 工人之间共享空间 再完善完善概念: - 工厂的资源 -> 系统分配的内存(独立的一块内存) - 工厂之间的相互独立 -> 进程之间相互独立 - 多个工人协作完成任务 -> 多个线程在进程中协作完成任务 - 工厂内有一个或多个工人 -> 一个进程由一个或多个线程组成 - 工人之间共享空间 -> 同一进程下的各个线程之间共享程序的内存空间(包括代码段、数据集、堆等) 然后再巩固下: 如果是windows电脑中,可以打开任务管理器,可以看到有一个后台进程列表。对,那里就是查看进程的地方,而且可以看到每个进程的内存资源信息以及cpu占有率。 所以,应该更容易理解了:进程是cpu资源分配的最小单位(系统会给它分配内存) 最后,再用较为官方的术语描述一遍: 进程是cpu资源分配的最小单位(是能拥有资源和独立运行的最小单位) 线程是cpu调度的最小单位(线程是建立在进程的基础上的一次程序运行单位,一个进程中可以有多个线程) tips 不同进程之间也可以通信,不过代价较大 现在,一般通用的叫法:单线程与多线程,都是指在一个进程内的单和多。(所以核心还是得属于一个进程才行) 浏览器是多进程的 理解了进程与线程了区别后,接下来对浏览器进行一定程度上的认识:(先看下简化理解) 浏览器是多进程的 浏览器之所以能够运行,是因为系统给它的进程分配了资源(cpu、内存) 简单点理解,每打开一个Tab页,就相当于创建了一个独立的浏览器进程。 关于以上几点的验证,请再第一张图: 图中打开了Chrome浏览器的多个标签页,然后可以在Chrome的任务管理器中看到有多个进程(分别是每一个Tab页面有一个独立的进程,以及一个主进程)。 感兴趣的可以自行尝试下,如果再多打开一个Tab页,进程正常会+1以上 **注意:**在这里浏览器应该也有自己的优化机制,有时候打开多个tab页后,可以在Chrome任务管理器中看到,有些进程被合并了 (所以每一个Tab标签对应一个进程并不一定是绝对的) 浏览器都包含哪些进程? 知道了浏览器是多进程后,再来看看它到底包含哪些进程:(为了简化理解,仅列举主要进程) Browser进程:浏览器的主进程(负责协调、主控),只有一个。作用有 负责浏览器界面显示,与用户交互。如前进,后退等 负责各个页面的管理,创建和销毁其他进程 将Renderer进程得到的内存中的Bitmap,绘制到用户界面上 网络资源的管理,下载等 第三方插件进程:每种类型的插件对应一个进程,仅当使用该插件时才创建 GPU进程:最多一个,用于3D绘制等 浏览器渲染进程(浏览器内核)(Renderer进程,内部是多线程的):默认每个Tab页面一个进程,互不影响。主要作用为 页面渲染,脚本执行,事件处理等 强化记忆:在浏览器中打开一个网页相当于新起了一个进程(进程内有自己的多线程) 当然,浏览器有时会将多个进程合并(譬如打开多个空白标签页后,会发现多个空白标签页被合并成了一个进程),如图 另外,可以通过Chrome的更多工具 -> 任务管理器自行验证 浏览器多进程的优势 相比于单进程浏览器,多进程有如下优点: 避免单个page crash影响整个浏览器 避免第三方插件crash影响整个浏览器 多进程充分利用多核优势 方便使用沙盒模型隔离插件等进程,提高浏览器稳定性 简单点理解:如果浏览器是单进程,那么某个Tab页崩溃了,就影响了整个浏览器,体验有多差;同理如果是单进程,插件崩溃了也会影响整个浏览器;而且多进程还有其它的诸多优势。。。 当然,内存等资源消耗也会更大,有点空间换时间的意思。 重点是浏览器内核(渲染进程) 重点来了,我们可以看到,上面提到了这么多的进程,那么,对于普通的前端操作来说,最终要的是什么呢?答案是渲染进程 ...

December 17, 2024

浏览器渲染过程

渲染流程 首先要了解的概念: 渲染引擎:它是浏览器最核心的部分是 “Rendering Engine”,不过我们一般习惯将之称为 “浏览器内核” 渲染引擎主要包括的线程: 各个线程主要职责: GUI渲染线程:GUI 渲染线程负责渲染浏览器界面,解析 HTML,CSS,构建 DOM 树和 RenderObject 树,布局和绘制等。当界面需要重绘(Repaint)或由于某种操作引发回流(Reflow)时,该线程就会执行。 JavaScript引擎线程: JavaScript 引擎线程主要负责解析 JavaScript 脚本并运行相关代码。 JavaScript 引擎在一个Tab页(Renderer 进程)中无论什么时候都只有一个 JavaScript 线程在运行 JavaScript 程序。需要提起一点就是,GUI线程与JavaScript引擎线程是互斥的,这也是就是为什么JavaScript操作时间过长,会造成页面渲染不连贯,导致页面出现阻塞的原理。 事件触发线程:当一个事件被触发时该线程会把事件添加到待处理队列的队尾,等待 JavaScript 引擎的处理。 通常JavaScript引擎是单线程的,所以这些事件都会排队等待JS执行。 定时器触发器: 我们日常使用的setInterval 和 setTimeout 就在该线程中,原因可能就是:由于JS引擎是单线程的,如果处于阻塞线程状态就会影响记时的准确,所以需要通过单独的线程来记时并触发响应的事件这样子更为合理。 Http请求线程: 在 XMLHttpRequest 在连接后是通过浏览器新开一个线程请求,这个线程就Http请求线程,它 将检测到状态变更时,如果设置有回调函数,异步线程就产生状态变更事件放到 JavaScript 引擎的处理队列中等待处理。 有了上述的概念,对接下我们讲渲染流水线会有所帮助 简略版的渲染机制 很久之前就把浏览器工作原理读完了,看了很多博客,文章,当时简简单单的梳理一些内容,如下👇 简略版渲染机制一般分为以下几个步骤 处理 HTML 并构建 DOM 树。 处理 CSS 构建 CSSOM 树。 将 DOM 与 CSSOM 合并成一个渲染树。 根据渲染树来布局,计算每个节点的位置。 调用 GPU 绘制,合成图层,显示在屏幕上。 接下来大概就是这么说: 在构建 CSSOM 树时,会阻塞渲染,直至 CSSOM 树构建完成。并且构建 CSSOM 树是一个十分消耗性能的过程,所以应该尽量保证层级扁平,减少过度层叠,越是具体的 CSS 选择器,执行速度越慢。 ...

December 17, 2024

JSX

时下虽然接入 JSX 语法的框架越来越多,但与之缘分最深的毫无疑问仍然是 React。 2013 年,当 React 带着 JSX 横空出世时,社区曾对 JSX 有过不少的争议,但如今,越来越多的人面对 JSX 都要说上一句“真香”!我们就来一起认识下这个“真香”的 JSX,聊一聊“JSX 代码是如何‘摇身一变’成为 DOM 的”。 开始之前请先思考几个问题: JSX 的本质是什么,它和 JS 之间到底是什么关系? 为什么要用 JSX?不用会有什么后果? JSX 背后的功能模块是什么,这个功能模块都做了哪些事情? 面对以上问题,如果无法形成清晰且系统的思路,那么很可能是把 JSX 想得过于简单了。大多数人只是简单地把它理解为模板语法的一种,但事实上,JSX 作为 React 框架的一大特色,它与 React 本身的运作机制之间存在着千丝万缕的联系,上述 3 个问题的答案,就恰恰隐藏在这层“联系”中。 JSX 的本质:JavaScript 的语法扩展 JSX 到底是什么?看看 React 官网给出的一段定义: JSX 是 JavaScript 的一种语法扩展,它和模板语言很接近,但是它充分具备 JavaScript 的能力。 “语法扩展”这一点在理解上几乎不会产生歧义,不过“它充分具备 JavaScript 的能力”这句,却总让人摸不着头脑,JSX 和 JS 怎么看也不像是“一路人”啊?这就引出了“JSX 语法是如何在 JavaScript 中生效的”这个问题。 JSX 语法是如何在 JavaScript 中生效的:认识 Babel Facebook 公司给 JSX 的定位是 JavaScript 的“扩展”,而非 JavaScript 的“某个版本”,这就直接决定了浏览器并不会像天然支持 JavaScript 一样地支持 JSX。那么,JSX 的语法是如何在 JavaScript 中生效的呢?React 官网其实早已给过我们线索: ...

December 17, 2024

中间人攻击

一句话总结:中间人攻击的关键在于获取公钥。 一、我和小美传纸条 我和隔壁班的小美互相喜欢,经常互相传纸条。但我懒得动,一般让老王帮我顺路带过去,我信任老王,所以就是简单把纸对折一下就交给老王了。 二、带锁的盒子 有一天我发现,老王居然偷看我的纸条! 我很生气,于是买了一个带锁的盒子,并配了两把钥匙🔑,我留一把,另一把让老王交给小美。我心想这下子老王没钥匙,看不了我们的纸条了。 三、一个需要两把钥匙的盒子 又过了几天,我发现老王还是会偷看,为什么呢?原来这老小子当初传递钥匙的时候,自己去复刻了一把! 于是我又想了一个办法,换了一个更高级的盒子,这个盒子必须用一对钥匙才能使用,使用公钥上锁,必须使用私钥才能打开。我委托老王把我的公钥交给小美,把小美的公钥拿给我。 以后我们都用对方的公钥来进行加密,对方用自己的私钥就能解密。而且就算老王把公钥拿去复刻一把也没关系,没有私钥他就打不开箱子,完美! 四、班主任 过了几天,我发现老王还是能偷看我们的纸条,为什么呢?????? 我想了好几天终于想明白了!原来老王当初传递钥匙的时候,他把我俩的公钥自己留下了,这老小子把自己的公钥给了我们俩。他现在有手里有四把钥匙,想看什么看什么! 这次我们终于意识到问题的关键,不管什么方案,让老王传钥匙就得坏事!于是我和小美商量好,这次不通过老王,而是通过我的班主任传递公钥,终于可以愉快的聊天了! 五、网络中的加密知识 对称加密 对称加密使用同一个密钥进行加密和解密。它的优点是速度快,它的问题是密钥传播过程中一旦泄露,就功亏一篑了。 非对称加密 非对称加密使用一对密钥:公钥和私钥。公钥用于加密,私钥用于解密。它的优点是密钥分发问题得到解决,公钥可以公开传播。缺点是速度较慢,通常用于加密小数据量或密钥交换。常见做法是通过非对称加密建立链接,交换对称加密密钥,然后使用对称加密的方式进行消息传递。 证书 数字证书是由认证机构(CA)签发的,包含公钥及其持有者身份信息的电子文档。它通过 CA 的数字签名验证其真实性,确保通信双方的身份和公钥的可信性。(证书就是上面例子中的班主任,是一个可信任的获取对方公钥的机构。) 六、中间人攻击 中间人攻击的关键在于攻击者成功获取并提供可信公钥,欺骗用户使其认为其公钥是合法服务器的公钥。这可以通过伪造证书或利用受损的 CA 来实现。(用上面例子来说,就是老王把自己的公钥伪装成小美的公钥给了我) 作为普通用户防御措施很简单,当访问一个网站时,如果浏览器弹出“证书不可信”告警的时候,不要点“我信任”。 常见考点 1. 中间人攻击的基本概念 问题: 什么是中间人攻击?请用通俗的语言解释。 中间人攻击有哪些典型的攻击方式? 被动攻击(如窃听)。 主动攻击(如数据篡改)。 中间人攻击的危害有哪些? 关键点: 中间人攻击是一种攻击者拦截并篡改通信内容的攻击。 危害包括:窃取敏感数据(如密码)、篡改通信内容、伪装身份等。 2. 中间人攻击的原理 问题: 中间人攻击是如何实现的?请简要描述其工作流程。 在 HTTP 中,为什么容易发生中间人攻击? HTTPS 是否完全能防止中间人攻击?为什么? DNS 劫持和 ARP 欺骗是如何帮助实现中间人攻击的? 关键点: 工作流程: 攻击者充当通信双方之间的“中间人”。 拦截通信数据,可能进行监听或篡改。 常见技术: ARP 欺骗:伪装网关。 DNS 劫持:将域名解析到攻击者控制的服务器。 Wi-Fi 劫持:在公共网络中拦截通信数据。 3. 防御中间人攻击的技术措施 问题: HTTPS 如何防御中间人攻击?它的安全机制是什么? 什么是证书信任链?如何防止伪造的证书? 什么是 HSTS(HTTP Strict Transport Security)?它如何防御中间人攻击? 什么是双向 SSL/TLS?它如何进一步提高安全性? 如何防止公共 Wi-Fi 中的中间人攻击? 关键点: ...

December 4, 2024

新变化

CSS 发展史 上图是20 世纪 90 年万维网刚出现时,由于当时并没有可以装饰网页的方法,原始的 Web 页面呈现的效果,随着 CSS(层叠样式表,Cascading Style Sheets)的诞生与发展,Web页面的样式有了翻天覆地的变化。 CSS的发布过程 CSS1.0 19912月W3C发布了第一个有关样式的标准CSS1.0。这个版本中,已经包含了的相关font的相关属性、颜色与背景的相关属性、文字的相关属性、box的相关属性等。 CSS2.0 1985年5月,CSS2.0正式推出。这个版本推荐的是内容和表现效果分离的方式,并开始使用样式表结构。 CSS2.1 2004年2月,CSS2.1正式推出。它在CSS2.0的基础上略微做了改动,删除了许多不被浏览器支持的属性 CSS3 从2011年开始CSS被分为多个模块单独升级。这些模块统称为CSS3 包含有: CSS 选择器level3 CSS 媒体查询level3 CSS color level3 CSS4 设计中 CSS 标准的制定大概有下面几个步骤 下面主要介绍的是与我们日常工作有关联的一些新特性,其中一些已经在主流浏览器中得到了支持,还有一些特性还在草案阶段,可能还会有一些变化。 CSS 伪类选择器 is()和where() 在编写css时,有时会需要使用很长的选择器列表来定位具有相同样式的子元素,比如对所有H元素下的span设置为block,之前会这么写: 这样写选择器看起来很长,可读性差。 此时,可以使用is()来提高易读性,同时避免使用长选择器 浏览器支持: :is() Chrome 88/ Firefox 78/ Edge 88 /Safari 14 :where() Chrome 88/ Firefox 78/ Edge 88 /Safari 14 注意: is()和where()在使用方法上和其他的伪类选择器一样,可以任意组合排列。 is()和where()的功能大体上是一样的,他们的差异性体现在选择器的权重上 where()选择器没有权重,也就是权重是0 is()选择器的权重由它的选择器列表中的最搞权重决定 规则示例: ...

November 9, 2024

移动端适配

导读 移动端适配,是我们在开发中经常会遇到的,这里面可能会遇到非常多的问题: 1px问题 UI图完美适配方案 iPhoneX适配方案 横屏适配 高清屏图片模糊问题 … 上面这些问题可能我们在开发中已经知道如何解决,但是问题产生的原理,以及解决方案的原理可能会模糊不清。在解决这些问题的过程中,我们往往会遇到非常多的概念:像素、分辨率、PPI、DPI、DP、DIP、DPR、视口等等,你真的能分清这些概念的意义吗? 本文将从移动端适配的基础概念出发,探究移动端适配各种问题的解决方案和实现原理。 一、英寸 一般用英寸描述屏幕的物理大小,如电脑显示器的17、22,手机显示器的4.8、5.7等使用的单位都是英寸。 需要注意,上面的尺寸都是屏幕对角线的长度: 英寸(inch,缩写为in)在荷兰语中的本意是大拇指,一英寸就是指甲底部普通人拇指的宽度。 英寸和厘米的换算:1英寸 = 2.54 厘米 二、分辨率 2.1 像素 像素即一个小方块,它具有特定的位置和颜色。 图片、电子屏幕(手机、电脑)就是由无数个具有特定颜色和特定位置的小方块拼接而成。 像素可以作为图片或电子屏幕的最小组成单位。 下面我们使用sketch打开一张图片: 将这些图片放大即可看到这些像素点: 通常我们所说的分辨率有两种,屏幕分辨率和图像分辨率。 2.2 屏幕分辨率 屏幕分辨率指一个屏幕具体由多少个像素点组成。 下面是apple的官网上对手机分辨率的描述: iPhone XS Max 和 iPhone SE的分辨率分别为2688 x 1242和1136 x 640。这表示手机分别在垂直和水平上所具有的像素点数。 当然分辨率高不代表屏幕就清晰,屏幕的清晰程度还与尺寸有关。 2.3 图像分辨率 我们通常说的图片分辨率其实是指图片含有的像素数,比如一张图片的分辨率为800 x 400。这表示图片分别在垂直和水平上所具有的像素点数为800和400。 同一尺寸的图片,分辨率越高,图片越清晰。 2.4 PPI PPI(Pixel Per Inch):每英寸包括的像素数。 PPI可以用于描述屏幕的清晰度以及一张图片的质量。 使用PPI描述图片时,PPI越高,图片质量越高,使用PPI描述屏幕时,PPI越高,屏幕越清晰。 在上面描述手机分辨率的图片中,我们可以看到:iPhone XS Max 和 iPhone SE的PPI分别为458和326,这足以证明前者的屏幕更清晰。 由于手机尺寸为手机对角线的长度,我们通常使用如下的方法计算PPI: iPhone 6的PPI为 ...

November 9, 2024

原子化CSS

1. 什么是原子化CSS 1.1 基本概念 原子化CSS(Atomic CSS) 近年来热度逐渐增加,与原子化CSS相关的库在Github上也收获上万的Star。那么什么是原子化CSS呢,引用文章 Let’s Define Exactly What Atomic CSS is 中定义:“原子化CSS是一种CSS架构方式,其支持小型、单一用途的类,其名称基于视觉功能。” 更加通俗的来讲,原子化CSS是一种新的CSS编程思路,它倾向于创建小巧且单一用途的class,并且以视觉效果进行命名。举个简单的例子: <!-- 原子化类定义 --> <style> .text-white { color: white; } .bg-black { background-color: black; } .text-center { text-align: center; } </style> <!-- 原子化类使用 --> <div class="text-white bg-black text-center">hello Atomic CSS</div> 1.2 VS 行内样式 看到以上的示例,你可能很快就想到,直接使用行内样式不是更好吗,还省去了原子类的定义。这个问题可以从样式编写、一致性、功能、和缓存四个方面来回答。 在样式编写层面,CSS预处理和后处理器很大程度上依赖单独的样式表,原子化CSS可以充分利用Sass、Less等CSS预处理器功能进行样式的编写,同时可以借助PostCSS进一步增强CSS的功能。而对于行内样式,虽然在技术上支持使用预处理和后处理器对其进行处理,但很少有成熟的工具对此提供支持和维护。 在一致性层面,原子化CSS框架一般有预定义的设计系统,开发者仅能在设计系统中选择要设置的值。而对于行内样式或者传统CSS类定义来说,可设置的值是没有任何限制的。对于行内样式或者传统的CSS类设置来说,一个标签的字体大小可能是14px或0.875rem,当产品(or 客户)说需要调小一点时,开发者A可能调整为13px,开发者B可能调整为12px。但对于原子化CSS框架来说,调小一点意味着设置的类从text-sm变为text-xs。 以下为部分采用传统CSS类编写的网站样式统计数据(统计来源): 掘金官网:283种背景颜色 471种字体颜色 264种字体大小 GitLab:1199种背景颜色 1351种字体颜色 450种字体大小 CSDN:585种背景颜色 1190种字体颜色 504种字体大小 在功能方面,原子化CSS本质上还是CSS类,因此支持媒体查询功能,也支持对元素的悬停、聚焦等状态进行处理,而内联样式缺少这部分的能力。 在打包方面,内联样式包含在JS文件中,样式的修改会导致整个bundle的改变,原子化CSS样式定义和JS逻辑分离,修改元素的class属性可能并不影响(在没有新CSS类的情况下)最终打包输出样式文件。 2. 谁在使用原子化CSS 截至目前已经有部分网站借鉴或者使用原子化CSS的思想重构了自己的web网站,比较知名的网站有Facebook、Twitter、Github、swipperjs等。根据网上公开的信息,Facebook在使用原子化CSS思想重构之后,仅登录页面的413KB样式文件,减少为整个站点的74KB。 Facebook ...

November 9, 2024

BFC

BFC 是前端面试中经常会被问到的一个知识点,今天就来带大家深入了解下什么是 BFC 以及它的作用。 文档流 在介绍BFC之前,需要先给大家介绍一下文档流。 我们常说的文档流其实分为定位流、浮动流、普通流三种。 绝对定位(Absolute positioning) 如果元素的属性 position 为 absolute 或 fixed,它就是一个绝对定位元素。 在绝对定位布局中,元素会整体脱离普通流,因此绝对定位元素不会对其兄弟元素造成影响,而元素具体的位置由绝对定位的坐标决定。 它的定位相对于它的包含块,相关CSS属性:top、bottom、left、right; 对于 position: absolute,元素定位将相对于上级元素中最近的一个relative、fixed、absolute,如果没有则相对于body; 对于 position:fixed,正常来说是相对于浏览器窗口定位的,但是当元素祖先的 transform 属性非 none 时,会相对于该祖先进行定位。 浮动 (float) 在浮动布局中,元素首先按照普通流的位置出现,然后根据浮动的方向尽可能的向左边或右边偏移,其效果与印刷排版中的文本环绕相似。 普通流 (normal flow) 普通流其实就是指BFC中的FC。FC(Formatting Context),直译过来是格式化上下文,它是页面中的一块渲染区域,有一套渲染规则,决定了其子元素如何布局,以及和其他元素之间的关系和作用。 在普通流中,元素按照其在 HTML 中的先后位置至上而下布局,在这个过程中,行内元素水平排列,直到当行被占满然后换行。块级元素则会被渲染为完整的一个新行。 除非另外指定,否则所有元素默认都是普通流定位,也可以说,普通流中元素的位置由该元素在 HTML 文档中的位置决定。 BFC 概念 先看下MDN上关于BFC的定义: 块格式化上下文(Block Formatting Context,BFC) 是Web页面的可视CSS渲染的一部分,是块盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域。 具有 BFC 特性的元素可以看作是隔离了的独立容器,容器里面的元素不会在布局上影响到外面的元素,并且 BFC 具有普通容器所没有的一些特性。 通俗一点来讲,可以把 BFC 理解为一个封闭的大箱子,箱子内部的元素无论如何翻江倒海,都不会影响到外部。 除了 BFC,还有: IFC(行级格式化上下文)- inline 内联 GFC(网格布局格式化上下文)- display: grid FFC(自适应格式化上下文)- display: flex或display: inline-flex 注意:同一个元素不能同时存在于两个 BFC 中。 ...

November 9, 2024

z-index

大家可能觉得,z-index 是一个很简单的属性,你给它设置哪个值,元素就会位于 y 轴的哪个位置。但它实际上并没有我们想象的这么简单,这个属性背后是一系列决定元素所在层级的规则。 在进行今天的介绍前,我们先列出三个问题,如果你能一眼看出它们的解决方案,那么恭喜你掌握了z-index,也就不需要阅读本文了;如果不行,那么耐心看完本文,相信能找到答案。 三个自测问题 问题一:为什么z-index 数值更大,但 Content 没有在 Box 2 之上? <div id="box1"> Box 1 </div> <div id="content"> Content <br/> z-index: 2; </div> <div id="box2"> Box 2 <br/> z-index: 1; </div> div { padding: 25px; font-size: larger; } #box1 { background-color: chocolate; width: 200px; height: 100px; margin-bottom: -50px; } #content { background-color: gold; width: 300px; height: 200px; z-index: 2; } #box2 { background-color: cyan; width: 200px; height: 100px; margin-top: -50px; z-index: 1; } 问题二:明明 z-index 数值更小,为什么 Content 这次反而在Box 2 之上了? <div id="box1"> Box 1 </div> <div id="content"> Content <br/> transform: rotate(90deg); <br/> z-index: 1; </div> <div id="box2"> <br/> Box 2 <br/> z-index: 2; </div> div { padding: 25px; font-size: larger; } #box1 { background-color: chocolate; width: 200px; height: 100px; margin-bottom: -10px; } #content { background-color: gold; width: 250px; height: 200px; z-index: 1; transform: rotate(90deg); } #box2 { background-color: cyan; width: 200px; height: 100px; margin-top: -10px; z-index: 2; } ...

November 9, 2024