个人主页:不爱吃糖的程序媛
♂️ 作者简介:前端领域新星创作者、CSDN内容合伙人,专注于前端各领域技术,成长的路上共同学习共同进步,一起加油呀!
✨系列专栏:前端面试宝典、JavaScript进阶、vue实战
资料领取:前端进阶资料以及文中源码可以在公众号【不爱吃糖的程序媛】领取
const box = document.getElementById('box');
function isIcon(target) {
return target.className.includes('icon');
}
box.onClick = function(e) {
e.stopPropagation();
const target = e.target;
if (isIcon(target)) {
target.style.border = '1px solid red';
}
}
const doc = document;
doc.onclick = function(e) {
const children = box.children;
for (let i; i < children.length; i++) {
if (isIcon(children[i])) {
children[i].style.border = 'none';
}
}
}
/*类似下面的代码:*/
.space {
font-size: 0;
}
.space a {
font-size: 12px;
}
/*类似下面的代码:*/
.space {
letter-spacing: -3px;
}
.space a {
letter-spacing: 0;
}
该方法可以搞定基本上所有浏览器。
这个方法,基本上可以解决大部分浏览器下inline-block元素之间的间距(IE7等浏览器有时候会有1像素的间距)。
display:none: 会让元素完全从渲染树中消失,渲染的时候不占据任何空间, 不能点击。
visibility: hidden:不会让元素从渲染树消失,渲染元素继续占据空间,只是内容不可见,不能点击 。opacity: 0: 不会让元素从渲染树消失,渲染元素继续占据空间,只是内容不可见,可以点击。
display: none和opacity: 0:是非继承属性,子孙节点消失由于元素从渲染树消失造成,通过修改子孙节点属性无法显示。
visibility: hidden:是继承属性,子孙节点消失由于继承了hidden,通过设置visibility: visible;可以让子孙节点显式。
displaynone : 修改元素会造成文档回流,读屏器不会读取display: none元素内容,性能消耗较大 。visibility:hidden: 修改元素只会造成本元素的重绘,性能消耗较少读屏器读取visibility: hidden元素内容 。opacity: 0 :修改元素会造成重绘,性能消耗较少。
这个是元素的默认定位方式,元素出现在正常的文档流中,会占用页面空间。
相对定位方式,相对于其父级元素(无论父级元素此时为何种定位方式)进行定位,准确地说是相对于其父级元素所剩余的未被占用的空间进行定位(在父元素由多个相对定位的子元素时可以看出),且会占用该元素在文档中初始的页面空间,即在使用top,bottom,left,right进行移动位置之后依旧不会改变其所占用空间的位置。可以使用z-index进行在z轴方向上的移动。
绝对定位方式,脱离文档流,不会占用页面空间。以最近的不是static定位的父级元素作为参考进行定位,如果其所有的父级元素都是static定位,那么此元素最终则是以当前窗口作为参考进行定位。
可以使用top,bottom,left,right进行位置移动,亦可使用z-index在z轴上面进行移动。当元素为此定位时,如果该元素为内联元素,则会变为块级元素,即可以直接设置其宽和高的值;如果该元素为块级元素,则其宽度会由初始的100%变为auto。
注意:当元素设置为绝对定位时,在没有指定top,bottom,left,right的值时,他们的值并不是0,这几个值是有默认值的,默认值就是该元素设置为绝对定位前所处的正常文档流中的位置。
绝对定位方式,直接以浏览器窗口作为参考进行定位。其它特性同absolute定位。
当父元素使用了transform的时候,会以父元素定位。
粘性定位,可以简单理解为relative和fixed布局的混合。
当粘性约束矩形在可视范围内为relative,反之,则为fixed粘性定位元素如果和它的父元素一样高,则垂直滚动的时候,粘性定位效果是不会出现的它的定位效果完全受限于父级元素们。
如果父元素的overflow属性设置了scroll,auto,overlay值,那么,粘性定位将会失效同一容器中多个粘贴定位元素独立偏移,因此可能重叠;位置上下靠在一起的不同容器中的粘贴定位元素则会鸠占鹊巢,挤开原来的元素,形成依次占位的效果。
页面加载自上而下 当然是先加载样式。
写在body标签后由于浏览器以逐行方式对HTML文档进行解析,当解析到写在尾部的样式表(外联或写在style标签)会导致浏览器停止之前的渲染,等待加载且解析样式表完成之后重新渲染,在windows的IE下可能会出现FOUC现象(即样式失效导致的页面闪烁问题)。
当按百分比设定一个元素的宽度时,它是相对于父容器的宽度计算的,但是,对于一些表示竖向距离的属性,例如 padding-top , padding-bottom , margin-top , margin-bottom 等,当按百分比设定它们时,依据的也是父容器的宽度,而不是高度。
相信大多数初学者都会认为CSS匹配是左向右的,其实恰恰相反。
CSS匹配发生在Render Tree构建时(Chrome Dev Tools将其归属于Layout过程)。此时浏览器构建出了DOM,而且拿到了CSS样式,此时要做的就是把样式跟DOM上的节点对应上,浏览器为了提高性能需要做的就是快速匹配。
首先要明确一点,浏览器此时是给一个"可见"节点找对应的规则,这和jQuery选择器不同,后者是使用一个规则去找对应的节点,这样从左到右或许更快。但是对于前者,由于CSS的庞大,一个CSS文件中或许有上千条规则,而且对于当前节点来说,大多数规则是匹配不上的,稍微想一下就知道,如果从右开始匹配(也是从更精确的位置开始),能更快排除不合适的大部分节点,而如果从左开始,只有深入了才会发现匹配失败,如果大部分规则层级都比较深,就比较浪费资源了。
除了上面这点,我们前面还提到DOM构建是"循序渐进的",而且DOM不阻塞Render Tree构建(只有CSSOM阻塞),这样也是为了能让页面更早有元素呈现。
考虑如下情况,如果我们此时构建的只是部分DOM,而CSSOM构建完成,浏览器就会构建Render Tree。
这个时候对每一个节点,如果找到一条规则从右向左匹配,我们只需要逐层观察该节点父节点是否匹配,而此时其父节点肯定已经在DOM上。
但是反过来,我们可能会匹配到一个DOM上尚未存在的节点,此时的匹配过程就浪费了资源。
Grid 布局即网格布局,是一个二维的布局方式,由纵横相交的两组网格线形成的框架性布局结构,能够同时处理行与列。
擅长将一个页面划分为几个主要区域,以及定义这些区域的大小、位置、层次等关系。
这与之前讲到的flex一维布局不相同,
设置display:grid/inline-grid的元素就是网格布局容器,这样就能出发浏览器渲染引擎的网格布局算法。
"container">
"item item-1">
"sub-item">
"item item-2">
"item item-3">
上述代码实例中,.container元素就是网格布局容器,.item元素就是网格的项目,由于网格元素只能是容器的顶层子元素,所以p元素并不是网格元素。
这里提一下,网格线概念,有助于下面对grid-column系列属性的理解
上图是一个 2 x 3 的网格,共有3根水平网格线和4根垂直网格线。
同样,Grid 布局属性可以分为两大类:
容器属性,
项目属性
关于容器属性有如下:
文章开头讲到,在元素上设置display:grid 或 display:inline-grid 来创建一个网格容器
display:grid 则该容器是一个块级元素
display: inline-grid 则容器元素为行内元素
grid-template-columns 属性设置列宽,grid-template-rows 属性设置行高。
.wrapper {
display: grid;
/* 声明了三列,宽度分别为 200px 200px 200px */
grid-template-columns: 200px 200px 200px;
grid-gap: 5px;
/* 声明了两行,行高分别为 50px 50px */
grid-template-rows: 50px 50px;
}
以上表示固定列宽为 200px 200px 200px,行高为 50px 50px
上述代码可以看到重复写单元格宽高,通过使用repeat()函数,可以简写重复的值。
第一个参数是重复的次数
第二个参数是重复的值
所以上述代码可以简写成
.wrapper {
display: grid;
grid-template-columns: repeat(3,200px);
grid-gap: 5px;
grid-template-rows:repeat(2,50px);
}
除了上述的repeact关键字,还有:
grid-template-columns: repeat(auto-fill, 200px) 表示列宽是 200
px,但列的数量是不固定的,只要浏览器能够容纳得下,就可以放置元素
grid-template-columns: 200px 1fr 2fr 表示第一个列宽设置为
200px,后面剩余的宽度分为两部分,宽度分别为剩余宽度的 1/3 和 2/3
minmax(100px, 1fr)表示列宽不小于100px,不大于1fr
grid-template-columns: 100px auto 100px 表示第一第三列为 100px,中间由浏览器决定长度
grid-row-gap 属性、grid-column-gap 属性分别设置行间距和列间距。grid-gap 属性是两者的简写形式
grid-row-gap: 10px 表示行间距是 10px
grid-column-gap: 20px 表示列间距是 20px
grid-gap: 10px 20px 等同上述两个属性
用于定义区域,一个区域由一个或者多个单元格组成
.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-auto-flow决定,默认为行,代表"先行后列",即先填满第一行,再开始放入第二行。
justify-items 属性设置单元格内容的水平位置(左中右),align-items 属性设置单元格的垂直位置(上中下)两者属性的值完成相同。
.container {
justify-items: start | end | center | stretch;
align-items: start | end | center | stretch;
}
属性对应如下:
place-items属性是align-items属性和justify-items属性的合并简写形式
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;
}
两个属性的写法完全相同,都可以取下面这些值:
有时候,一些项目的指定位置,在现有网格的外部,就会产生显示网格和隐式网格
比如网格只有3列,但是某一个项目指定在第5行。这时,浏览器会自动生成多余的网格,以便放置项目。超出的部分就是隐式网格
而grid-auto-rows与grid-auto-columns就是专门用于指定隐式网格的宽高
关于项目属性,有如下:
指定网格项目所在的四个边框,分别定位在哪根网格线,从而指定项目的位置。
举个例子:
"container">
"item item-1">1
"item item-2">2
"item item-3">3
通过设置grid-column属性,指定1号项目的左边框是第二根垂直网格线,右边框是第四根垂直网格线
grid-area 属性指定项目放在哪一个区域
.item-1 {
grid-area: e;
}
意思为将1号项目位于e区域
与上述讲到的grid-template-areas搭配使用
justify-self属性设置单元格内容的水平位置(左中右),跟justify-items属性的用法完全一致,但只作用于单个项目。
align-self属性设置单元格内容的垂直位置(上中下),跟align-items属性的用法完全一致,也是只作用于单个项目
.item {
justify-self: start | end | center | stretch;
align-self: start | end | center | stretch;
}
这两个属性都可以取下面四个值。
文章开头就讲到,Grid是一个强大的布局,如一些常见的 CSS 布局,如居中,两列布局,三列布局等等是很容易实现的,在以前的文章中,也有使用Grid布局完成对应的功能。
总体兼容性还不错,但在 IE 10 以下不支持;目前,Grid布局在手机端支持还不算太友好。
每一个网页都离不开css,但是很多人又认为,css主要是用来完成页面布局的,像一些细节或者优化,就不需要怎么考虑,实际上这种想法是不正确的。
作为页面渲染和内容展现的重要环节,css影响着用户对整个网站的第一体验;
因此,在整个产品研发过程中,css性能优化同样需要贯穿全程。
实现方式有很多种,主要有如下:
在打开一个页面,页面首要内容出现在屏幕的时间影响着用户的体验,而通过内联css关键代码能够使浏览器在下载完html后就能立刻渲染。
而如果外部引用css代码,在解析html结构过程中遇到外部css文件,才会开始下载css代码,再渲染
所以,CSS内联使用使渲染时间提前。
注意:但是较大的css代码并不合适内联(初始拥塞窗口、没有缓存),而其余代码则采取外部引用方式。
在CSS文件请求、下载、解析完成之前,CSS会阻塞渲染,浏览器将不会渲染任何已处理的内容。
前面加载内联代码后,后面的外部引用css则没必要阻塞浏览器渲染。这时候就可以采取异步加载的方案,主要有如下:
// 创建link标签
const myCSS = document.createElement( "link" );
myCSS.rel = "stylesheet";
myCSS.href = "mystyles.css";
// 插入到header的最后位置
document.head.insertBefore( myCSS, document.head.childNodes[ document.head.childNodes.length - 1 ].nextSibling );
"stylesheet" href="mystyles.css" media="noexist" οnlοad="this.media='all'">
"alternate stylesheet" href="mystyles.css" οnlοad="this.rel='stylesheet'">
利用webpack、gulp/grunt、rollup等模块化工具,将css代码进行压缩,使文件变小,大大降低了浏览器的加载时间
css匹配的规则是从右往左开始匹配,例如#markdown .content h3匹配规则如下:
如果嵌套的层级更多,页面中的元素更多,那么匹配所要花费的时间代价自然更高。
所以我们在编写选择器的时候,可以遵循以下规则:
在页面发生重绘的时候,昂贵属性如box-shadow/border-radius/filter/透明度/:nth-child等,会降低浏览器的渲染性能
css样式文件有两种引入方式,一种是link元素,另一种是@import
@import会影响浏览器的并行下载,使得页面在加载时增加额外的延迟,增添了额外的往返耗时
而且多个@import可能会导致下载顺序紊乱。
比如一个css文件index.css包含了以下内容:@import url(“reset.css”)
那么浏览器就必须先把index.css下载、解析和执行后,才下载、解析和执行第二个文件reset.css
css实现性能的方式可以从选择器嵌套、属性特性、减少http这三面考虑,同时还要注意css代码的加载顺序。