CSS 写作建议和性能优化小结

作者:守候
文章转载自:https://segmentfault.com/a/1190000011390896

1.前言

还有几天就到国庆中秋了,快要放假了,先祝大家节日快乐!之前写过 JS 的写作建议和技巧,那么今天就来聊聊 CSS 吧!

说到 CSS,每一个网页都离不开 CSS,但是对于 CSS,很多开发者的想法就是,CSS 只要能用来布局,把效果图排出来就可以了,其它的细节或者优化,不需要怎么考虑。但是我觉得 CSS 可不只是把页面的布局完成就是完事的,还需要考虑很多细节有优化,更不会像大家想得那么简单。在学习当中,如果发现什么技巧或者优化的点,我也会学以致用!

那么今天,就分享下我总结的 CSS 写作建议和性能优化的一些问题!希望能帮让大家对神奇的 CSS 有一个新认识。当然,如果大家觉得还有什么其它的建议,欢迎指点!

2.CSS 渲染规则

首选,关于CSS 渲染的规则,大家可能都知道,是从右到左的渲染!如下栗子:

.nav h3 a{font-size: 14px;}

渲染过程大概是:首先找到所有的a,沿着a的父元素查找h3,然后再沿着h3,查找.nav。中途找到了符合匹配规则的节点就加入结果集。如果找到根元素html都没有匹配,则不再遍历这条路径,从下一个a开始重复这个查找匹配(只要页面上有多个最右节点为a)。

参考:CSS选择器从右向左的匹配规则

3.嵌套层级不要超过 3 级

一般情况下,元素的嵌套层级不能超过 3 级,过度的嵌套会导致代码变得臃肿、沉余、复杂,导致 CSS 文件体积变大,造成性能浪费,影响渲染的速度,而且过于依赖 HTML 文档结构。这样的 CSS 样式,维护起来,极度麻烦,如果以后要修改样式,可能要使用!important覆盖。

4.样式重置

这个我目前保持中立意见,因为看着网上的文章,有些人支持使用样式重置,有些人不支持使用,谁也说服不了谁。我自己的情况,我有使用样式重置,但是是比较简单的一个总结,代码如下!

body,dl,dd,h1,h2,h3,h4,h5,h6,p,form,ol,ul {
  margin: 0;
  padding: 0;
}
h1, h2, h3, h4, h5, h6 {
  font-weight: normal;
}

ol, ul {
  list-style: none;
}
h1{
  font-size: 24px;
}

h2{
  font-size: 20px;
}

h3{
  font-size: 18px;
}

h4 {
  font-size: 16px;
}

h5{
  font-size: 14px;
}

h6{
  font-size: 12px;
}

5.样式级别

首先,CSS 样式级别整理如下:

!important > 行内样式 > ID 样式 > Class 样式 > 标签名样式。

然后有一点要提一下就是,组合选择器使用权值会叠加的。比如 ID 的权值是100,Class 是10,标签名是 1(其它不清楚了)!那么div.test-class权值就是 11,div#test就是 101.

比如有一个 div:

<div id="test" class="test-class" style="color:green;"></div>

那么样式权值方面就是:

  • div {color: red !improtant;}(大于下面的一切)
  • <div id="test" class="test-class" style="color:black;"></div>(大于 111)
  • div#test.test-class(111)
  • #id.test-class(110)
  • div#test(101)
  • #test(100)
  • div.test-class(11)
  • .test-class(10)
  • div(1)
  • *(小于 1)

6.inline-block 的边距

不解释,看图:

上面几个p元素marginpadding都为0,但是还有边距。这个的解决方案有两种:

  1. 删除代码之前的空行空格

display:inline-block的元素之前的空行都删除掉,如下写法:

  1. 父元素font-size设置为0,这个直接看图:

7.图片要设置 width 和 height

如果页面有使用img标签,那么img很建议设置widthheight。目的是为了在网速差或者其它原因加载不出图片的时候,保证布局不会乱。如下栗子,一个很普通的布局。

但是万一出现什么情况,图片加载不出来的话,建议的处理方式是第一种,显示一张默认图片,即使不显示默认图片,也让图片有一个占位的作用,保证布局不会乱!

如果图片加载不出,img又没有设置widthheight的话,就会像下面这样,布局乱了!

关于设置widthheight,我顺便说几点:

  1. PC 站,建议在img标签的属性设置widthheight。这样避免加载不出 CSS 而错位;
  2. 手机站,建议用 CSS 设置imgwidthheight,因为手机站要做适配,在属性设置widthheight不灵活,比如使用rem布局,在属性那里设置不了widthheight
  3. 如果图片不固定,但是有一个max-widthmax-height,那么建议在img的父元素设置widthheightimg根据父元素的widthheight设置max-widthmax-height

8.任意元素垂直居中

这里只放图,不解释:

8-1. table-cell

8-2. flex

8-3. position,transform

8-4. position,margin

这个方式不推荐使用,因为这个写法,.div2的宽高必须要设置,否则就是 100%,比如设置了top:0;bottom:0;效果和设置height:100%;是一样的。如果想要避免,就必须要设置height

9.图片预加载

这里说的预加载,不是懒加载。首先根据我个人理解科普下,懒加载和预加载的区别。

  • 懒加载:页面加载的时候,先加载一部分内容(一般是先加载首屏内容),其它内容等到需要加载的时候再进行加载。
  • 预加载:页面加载的时候,先加载一部分内容(一般是先加载首屏内容),其它内容等到先加载的一部分内容(一般是首屏内容)加载完了,再进行加载。

两种方式,都是为了减少用户进入网站的时候,更快的看到首屏的内容。

下面栗子,将这#preloader这个元素加入到到 HTML 中,就可以实现通过 CSS 的background属性将图片预加载到屏幕外的背景上。只要这些图片的路径保持不变,当它们在 Web 页面的其他地方被调用时,浏览器就会在渲染过程中使用预加载(缓存)的图片。简单、高效,不需要任何 JavaScript。

#preloader {
    /*需要预加载的图片*/
    background: url(image1.jpg) no-repeat,url(image2.jpg) no-repeat,url(image3.jpg) no-repeat;
    width: 0px;
    height: 0px;
    display: inline;
}

但是这样会有一个问题,因为#preloader预加载的图片,会和页面上的其他内容一起加载,增加了页面的整体加载时间。所以需要用 JS 控制。

function preloader(urlArr,obj) {
    var bgText='';
    for(var i=0,len=urlArr.length;i<len;i++){
        bgText+='url('+urlArr[i]+') no-repeat,';
    }
    obj.style.background=bgText.substr(0,bgText.length-1);
}
window.onload = function() {
   preloader(['image1.jpg','image2.jpg','image3.jpg'],document.getElementById('preloader'));
}

原理也很简单,就是先让首屏的图片加载完,然后再加载其它的图片。通过给#preloader设置背景图片,加载所需要的图片,然后页面上需要加载这些图片的时候,就直接从缓存里面拿图片,不需要通过 HTTP 请求获取图片,这样加载就很快。

10.慎用 * 通配符

在做网页的时候,经常会使用下面两种方式重置样式,以此来消除标签的默认布局和不同浏览器对于同一个标签的渲染。

*{margin:0;padding:0;}

上面这种方式,代码少,但是性能差,因为渲染的时候,要匹配页面上所有的元素。很多基础样式没有marginpadding的元素,比如divli等都被匹配,完全没必要。下面看另一种方式:

body,dl,dd,h1,h2,h3,h4,h5,h6,p,form,ol,ul{margin:0;padding:0;}

这种方式,代码稍微多,但是性能比上面的方式好。在渲染的时候,只匹配body,dl,dd,h1,h2,h3,h4,h5,h6,p,form,ol,ul这里面的元素,这些元素带有marginpadding,需要重置。

再看例子:

.test * {color: red;}

匹配文档中所有的元素,然后分别向上逐级匹配classtest的元素,直到文档的根节点:

.test a {color: red;}

匹配文档中所有a的元素,然后分别向上逐级匹配classtest的元素,直到文档的根节点。

两种方式,哪种更好不言而喻,所以在开发的时候,建议避免使用通配选择器。

11.合并、压缩 CSS

这个没什么好解释的,就是压缩和合并 CSS。

首先压缩 CSS,除了使用工具,比如 Gulp、Webpack 等把代码压缩,把空格和换行都去掉。还有一个建议就是属性简写。

比如:

margin-top:0;
margin-right:10px;
margin-bottom:10px;
margin-left:10px;
background-image: url('test.jpg');
background-position: top center;
background-repeat: no-repeat;
border-width:1px;
border-style:solid;
border-color:#000;
color:#0099FF;

可以换成下面的:

margin:0 10px 10px 10px;
background: url('test.jpg') no-repeat top center;
border:1px solid #000;
color:#09F;       

至于合并的时候,我按照自己的开发习惯给几个建议:

  1. 合并公用的样式。比如项目的头部、底部、侧边栏这些,一般都是公用的,这些可以写在一个公用样式表上,比如main.css
  2. 上面所说的main.css是每一个页面都需要引入,而样式重置表reset.css也是每一个页面都需要用到的,那么建议main.cssreset.css合并成一个文件,给页面引入,减少请求;
  3. 每个页面对应的样式为独立的文件。比如首页对应的是index.css,产品列表页对应的样式是product-list.css。那么index.css就只在首页引入,其它页面不引入,因为引入纯属浪费请求资源,其他页面对应的样式也是这个处理方式。index.cssproduct-list.css等其它页面的样式就保留单独的文件,不作合并处理。

12.CSS 在 head 引入

浏览器在所有的 stylesheets 加载完成之后,才会开始渲染整个页面。在此之前,浏览器不会渲染页面里的任何内容,页面会一直呈现空白。这也是为什么要把 stylesheet 放在头部的原因。如果放在 HTML 页面底部,页面渲染就不仅仅是在等待 stylesheet 的加载,还要等待 HTML 内容加载完成,这样一来,用户看到页面的时间会更晚。

13.避免使用 @import

CSS 样式文件有两种引入方式,一种是link元素,另一种是@import。在这里,我建议就是避免使用@import。因为@import会影响浏览器的并行下载,使得页面在加载时增加额外的延迟,增添了额外的往返耗时。而且多个@import可能会导致下载顺序紊乱。

比如一个 CSS 文件index.css包含了以下内容:@import url("reset.css")。那么浏览器就必须先把index.css下载、解析和执行后,才下载、解析和执行第二个文件reset.css。简单的解决方法是使用<link>替代@import

14.从 PSD 文件思考怎么写代码

接到效果图,先不用着急切图,先看下 PSD 文件。思考下怎么排版,那些模块可以做成公用的模块,模块应该怎么命名,写样式等。当我们拿到设计师给的 PSD 时,首先不要急于写 CSS 代码,首先对整个页面进行分析,先思考下面几点:

  1. 分析页面有哪些模块是公用的。常见公用模块有头部、底部、菜单栏、悬浮按钮等;
  2. 分析模块有什么样式,把公用的样式提取出来,公用样式包括公用的状态样式。比如按钮、输入框、下拉框等公用的选中状态,禁用状态的样式等。

15.小图标的处理方案

一个网站肯定会有很多个小图标,对于这些小图标,目前的解决方案有两个,CSS Sprite(雪碧图),字体图标,把图片转成 base64。下面对比一下这两种方式:

  • CSS Sprite:把所有 icon 图片合成一张 png 图片,使用的是在对节点设置宽高,加上bacgroud-position。以背景图方式显展示需要的 icon,如果一个网站有 20 图标,那么就要请求 20 次。使用 CSS Sprite,只需要请求一次,大大的减少了 HTTP 请求。缺点就是管理不灵活,如果需要新增一个图标,都需要改合并图片的源文件,图标定位也要规范,不然容易干扰图片之间的定位;
  • 字体图标:简单粗暴的理解就是把所有的图标当成一个字体处理,这样不用去请求图片。一般是使用 class 来定义图标,要替换图标时,只需更换样式名,管理方便,语意明确,灵活放大缩小,并且不会造成失真,但是只支持单色的图片。
  • base64:另一种方案就是把小的 icon 图片转成 base64 编码,这样可以不用去请求图片,把 base64 编码直接整合到 JS 或者 CSS 里面,可以防止因为一些相对路径,或者图片被不小删除了等问题导致图片 404 错误。但是找个方式会生成一大串的 base64 编码。一般来说,8K 以下的图片才转换成 base64 编码。如果把一张 50K 的图片转成 base64 编码,那么会生成超过 65000 个字符的 base64 编码,字符的大小就已经是将近 70K 了!建议就是:8K 以下的图片才转换成 base64 编码。

16.不要在 ID 选择器前面进行嵌套或写标签

  1. ID 在页面上本来就是唯一的,而且人家权值那么大,前方嵌套(.content #test)完全是浪费性能,以及多写一些没有意义的代码。这个虽然是一句话,但是还是有人犯这样的错。
  2. 除了嵌套,在 ID 的前面也不需要加标签或者其它选择器。比如div#test或者.test#test。这两种方式完全是多余的,理由就是 ID 在页面就是唯一的。前面加任何东西都是多余的!

17.把常用样式抽封装成公用样式

把长段相同样式提取出来作为公用样式使用,比如常用的清除浮动,单行超出显示省略号,多行超出省略号等。

如下栗子:

/*超出省略号*/
/*<p class='text-ellipsis'></p>*/
.text-ellipsis{
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
/*清除浮动*/
/*<div class='clearfix'></div>*/
.clearfix:after {
    display: block;
    content: '';
    clear: both;
    height:0;
}

18.CSS3 动画的优化

在我之前一篇文章(移动 Web 开发问题和优化小结),也有写过关于这个的优化建议,之前说的两个建议是:

  1. CSS3 动画或者过渡尽量使用transformopacity来实现动画,不要使用lefttop
  2. 动画和过渡能用CSS3解决的,就不要使用JS。如果是复杂的动画可以使用CSS3+JS(或者HTML5+CSS3+JS)配合开发,效果只有想不到,没有做不到。

下面补充一个:动画不宜过多,尤其是手机网站,否则会出现性能的问题.比如 CPU 一下子就被占用满了,掉帧等。而且,不建议给每一个元素都使用硬件加速。

参考链接:

19.Body 设置最小宽度

这个是在 PC 站会出现的问题,应该大家都知道。下面简单说一下!

比如下面的栗子,一个网站,页面内容宽度是 1200px。看着很正常,没什么特别:

如果这个时候,把页面窗口缩小。小于 1200px,页面出现滚动条,然后把滚动条拖到最右边:

这样是不是就发现,顶部的图片和背景有一部分是断层了!解决这个问题也很简单,就是给body加上min-width。值就是页面宽度的值:body{min-width:1200px;}

重复上一步操作,无论怎么改变浏览器窗口大小,都是正常的:

之所以会出现这样的问题,是因为,比如窗口缩小到 900px 的时候,小于内容宽度的 1200px。就是出现横向的滚动条,但是body的宽度是 900px。这个时候,如果有元素(比如图片的灰色区域和粉红色的图片)是相对bodywidth设置 100%,那么实际上这些元素的宽度也就是 900px。所以会出现断层那些的视觉!解决方式就是给body加上min-width。让body的宽度最小不会小于内容的宽度!

20.小结

关于我对 CSS 写作建议和性能优化的一个总结,就到这里了。CSS 绝对不是那种只要能用就行,或者只要能用 CSS 把布局弄好就行的一门语言。CSS 给我的感觉,就是上手很简单,但是如果想用好 CSS,还是得花时间去研究。CSS 或者 CSS3,能够优化的东西还有很多,用好 CSS 或者 CSS3 能够少写很多 JS 代码,做出来的东西也是很神奇,大家还是得继续学习当中的知识。

如果大家觉得我文章有哪个地方写得不好,写错了,欢迎指正。如果有什么其它的建议,欢迎指点,让大家互相交流,互相学习,一起进步!最后,祝大家节日快乐!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • 问答题47 /72 常见浏览器兼容性问题与解决方案? 参考答案 (1)浏览器兼容问题一:不同浏览器的标签默认的外补...
    _Yfling阅读 13,725评论 1 92
  • 选择qi:是表达式 标签选择器 类选择器 属性选择器 继承属性: color,font,text-align,li...
    wzhiq896阅读 1,730评论 0 2
  • 选择qi:是表达式 标签选择器 类选择器 属性选择器 继承属性: color,font,text-align,li...
    love2013阅读 2,301评论 0 11
  • 画画课后我和儿子坐在回家的公交车上。 妈妈:“今天下午重新装系统的那个手机,对于你来说只是学习用的工具,里面...
    何金霖阅读 195评论 0 0
  • 既然无法选择开始 又何必不停地抱怨 不如用那些抱怨的时间 去呼唤 谁敢说冬天的呼唤 不是春天 既然无法选择开始 又...
    浅得塾心灵文画阅读 162评论 2 7