写在前面
一个故事:
你知道normalize吗?与reset的区别是什么?
面试官问,我编(当时确实不知道,但两个单词的字面意思其实很明确了)
一.reset
reset:重置,清零
最粗暴的方式:
* {padding:0; margin:0;}
把所有标签全都扒光。body
、h1-h6
、div
、article
等一大推本来各不相同的标签,现在长的一模一样了,仅剩名字作为最后的尊严
当然,也有温和一点的(更长的):
body, dl, dd, h1, h2, h3, h4, h5, h6, p, form{margin:0;}
ol,ul{margin:0; padding:0;}
温和reset的原则是:只去掉需要去掉的。比如div
本来就啥也没穿,还被扒了一遍,这不人道
含reset的样式结构可能是这样:
reset.css // 去掉所有默认样式
common.css // 项目维护的公共样式
page.css // 业务需要的样式(无法复用)
按顺序引入,用下面的覆盖掉上面的。所以一个样式属性可能经过层层重写后才以最终的模样展现给用户,存在冗余reset的问题:如果某块样式注定是需要支持订制的,那就一定会被后来的css覆盖,没必要先用reset扒光吧?
二.normalize
normalize:归一化,使正常化、标准化
Normalize.css makes browsers render all elements more consistently and in line with modern standards. It precisely targets only the styles that need normalizing.
normalize做了几件事情:
保留浏览器默认样式中有用的部分
同时保证跨浏览器一致性(修复各浏览器中存在的不合W3C规范的问题)
在合适的地方设置默认值
normalize是补丁性质的,不像reset是破坏性的,例如normalize.css源码:
/**
* Add the correct display in IE 9-.
* 1. Add the correct display in IE.
*/
figcaption,
figure,
main { /* 1 */
display: block;
}
/**
* 1. Add the correct box sizing in Firefox.
* 2. Show the overflow in Edge and IE.
*/
hr {
box-sizing: content-box; /* 1 */
height: 0; /* 1 */
overflow: visible; /* 2 */
}
此处通过前端方案修复了浏览器存在的样式问题,同时考虑低版本浏览器兼容,这里倾向于“标准化”。此外,也有“正常化”的一面:
/**
* 1. Change the default font family in all browsers (opinionated).
* 2. Correct the line height in all browsers.
* 3. Prevent adjustments of font size after orientation changes in IE and iOS.
*/
html {
font-family: sans-serif; /* 1 */
line-height: 1.15; /* 2 */
-ms-text-size-adjust: 100%; /* 3 */
-webkit-text-size-adjust: 100%; /* 3 */
}
前辈已经解读过源码了,请查看关于CSS Reset 那些事(二)之 Normalize.css 源码解读
三.normalize与reset的区别
一个段子:
CSS Reset 是革命党,CSS Reset 里最激进那一派提倡不管你小子有用没用,通通给我脱了那身衣服,凭什么你 body 出生就穿一圈 margin,凭什么你姓 h 的比别人吃得胖,凭什么你 ul 戴一胳膊珠子。于是 *{margin:0;} 等等运动,把人家全拍扁了。看似是众生平等了,实则是浪费了资源又占不到便宜,有求于人家的时候还得贱贱地给加回去,实在需要人家的默认样式了怎么办?人家锅都扔炉子里烧了,自己看着办吧。
Normalize.css 是改良派。他们提倡,各个元素都有其存在的道理,简单粗暴地一视同仁是不好的。body 那一圈确实挤压了页面的生存空间,那就改掉。士农工商,谁有谁的作用,给他们制定个规范,确保他们在任何浏览器里都干好自己的活儿。
引自知乎会撸代码的段子手的回答
reset的特点
目标:强制所有浏览器表现一致
去掉大多数来自浏览器的默认样式,保证common, page
等样式下层是整齐划一的初始表现
所以一般意义的reset是破坏性的,统统扒光
主要存在2个问题:
冗余reset,影响性能
无论是写错的reset(本不需要),还是在上层一定会被覆盖的reset(没必要),都增大了样式文件,影响了渲染性能
容易杀错,也容易放过。精确的高性能reset?很难实现,甚至不存在(除FF, Chrome, Safari外,还有一大堆xx浏览器,谁知道它默认样式是啥呀)
分组缺少语义,难以维护
reset中对标签的分类不考虑语义,只关注默认表现
引发的后果就是调试工具查看某元素,关注某个属性,一层层追下去,最后看到一长串不相关的标签被绑在一起,应用了一两条规则
至于性能,在成为问题之前都不是问题。据传言* {padding:0; margin:0;}
对渲染对影响也只是2ms,如果真是这样,那就不用多想了,直接统统扒光最好。因为比起更复杂(更长,更人道)的reset带来的负面影响(增大了样式文件),渲染时的2ms比芝麻还要小
维护的问题,其实还是指向精确的高性能reset,如果reset恰到好处,样式问题应该与reset无关,如果调试中发现需要往下层追,就说明reset不够好
“不reset行吗?”
“当然不行呀,不reset的话,那么多浏览器,保不齐有什么奇怪的默认样式呢,前端应该有1px的执着,精确还原设计稿”
其实仔细想想,为什么我们需要reset?就因为大家都在用?
确实很多reset样式在业务中永远不会用到(老古董legend
、fieldset
以及新的语义化标签aside
、section
对于纯移动页面是几乎不需要的),真正有用的常用的可能只是body {margin: 0; }
,其它都要么在用的时候需要全面重写,要么永远用不到
所以几年前掀起了一场no reset运动,后来迎来了normalize……但答案究竟是什么?
normalize的特点
从源码可以发现normalize就像补丁一样,让浏览器默认样式更“正常”一些:
/* 1.样式补丁,修补浏览器差异,使其表现贴近标准 */
/**
* Prevent the duplicate application of `bolder` by the next rule in Safari 6.
*/
b,
strong {
font-weight: inherit;
}
/**
* Add the correct font weight in Chrome, Edge, and Safari.
*/
b,
strong {
font-weight: bolder;
}
/* 2.微量的reset */
/**
* Add the correct background and color in IE 9-.
*/
mark {
background-color: #ff0;
color: #000;
}
/**
* Prevent `sub` and `sup` elements from affecting the line height in
* all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
同样,通过源码也能发现它并不是reset的替代品:
reset像压路机,开过去之后路面非常平整
normalize像沥青,填补路面上的裂缝,小坑
但是,我们需要这层沥青吗?就因为Bootstrap用了我们就得用?
对于纯移动页面来说,normalize里98%的样式都用不着,很巧,有用的几行可能还是:
/**
* Remove the margin in all browsers (opinionated).
*/
body {
margin: 0;
}
当然,Bootstrap需要同时支持PC和移动端,适配大屏小屏,一个框架引入这些兼容代码自然没错,更健壮了
但我们的应用可能真的不需要normalize,即便需要,可能也只需要取其中真正能用到的30%,其余部分应该是根据业务特点,去掉某些丑丑的默认样式(比如table
),再置入基础样式,避免在每个页面中都去设置这些东西,那么最后产生的这个css就叫——base.css
四.css三层结构
base: 基本样式
站点级的,最基础,最通用的样式,不同风格不同内容的站点可以共用base样式
base是原子的,不可再分,比如兼容性良好的flex, clearfix等等
reset与base并列,作为基本样式组件,当然,也可以把简单的reset放在base层里
common: 通用样式
模块级的,自定义的样式模块,可以供各个页面复用
在base层基础上提供更复杂的样式模块,比如日历,popup等等
page: 页面样式
页面级的,不需要复用的样式
针对具体页面,添加特有的样式,比如具体色值,字体,hack等等
合理的分层能够有效提高样式的复用性,可以通过在高层简单地重写低层某条样式规则来改变最终样式;此外还能提高样式的可维护性,各层分工明确,新增样式对号入座,html中以class组合的方式来实现最终样式
base层和common层应该由很少的人来负责管理维护,不会经常变动,但可以扩展,开发者直接针对UI设计稿完成page层样式,实现视觉效果,编写page层样式时同样可以按照三层结构来组织,例如:
/* base */
body {
background-color: #eee;
}
h1 {
border-bottom: 1px solid #ccc;
}
/* common */
.panel {
border: 1px solid #ddd;
}
.line {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* page */
h1 span {
border: 1px solid red;
border-raduis: 3px;
}
.panel .line {
line-height: 1.5em;
}
五.总结
reset?normalize?需要吗?不需要吗?
为业务量身定制的才是最好的,精简、高效