在今天的文章中,我将要聊聊我在一年半的实践中,总结出来的css经验。
首先让我提醒你,css是极其简单的一门语言,简单到可以用三个词概括:选择器,属性以及属性的值。这也是一些人不喜欢css的原因:他们觉得写css像孩子玩乐高玩具一样简单。
是这样的。。如果你给一个9岁的孩子介绍css的基本原理,他就会搭建一个网站。不过这个网站不会很复杂,也就是一些包含头部,链接,内容图片的页面而已。
事实上,css是一门简单的语言,并不意味着每个人的水平一样。有些人写起css来就跟个大猩猩在玩棍子,有些人可以掌握css,而有些人可以使用魔法般的使用css。
不管怎样,我还是要给你分享一些我这几个月来理解的东西,这并不是一些代码片段或者是css小技巧,而更像是一些通用的规则或者是最佳实践之类的东西,如下:
- 不要让你的代码脱离你的掌控,尽量简洁
- 掌握基础,学习CSS技巧
- 保持代码的可复用性
- 面向对象的css
- Css3 了解他能做的以及你可以使用的部分
- 渐进增强与优雅降级
- Css预处理工具
- 与时俱进
- 取长补短
- 熟能生巧
你想说什么呢?你准备好了?那我们继续往下吧。
1.不要让你的代码脱离你的掌控,尽量简洁
别让你的代码脱离你的掌控
这是编程的一种通用建议,不仅仅适合css. 当你开始写代码的时候,先思考,思考以下几个问题:
- 我怎样实现?
- 有其他方法实现么?
- 怎样优化(简洁,可维护,等等)?
急于编码会浪费时间,你有可能花了一个小时也没实现,不得不从头再来,这不应该发生。
如果你花了好几个小时写一个css幻灯片,最终没办法用了个js幻灯片插件或者别的,这是很蛋疼的,并不是说你没成功,而是无谓的浪费了很多时间。如果项目有deadline的话,你就要悲剧了。
保持他的简单性
Css很简单,但如果你想,同样可以变得很复杂。在很多场景里,最简单的即是最好的。当你要实现什么效果的时候,问问自己:还有更简单的方法实现么? 答案经常是肯定的。
举个例子,简单水平导航栏,你可以有多种方法实现:
- 列表元素浮动;
- 改变列表元素display属性为inline;
- 改变列表元素display属性为inline-block。
最简单的-设置display:inline,不需要清除浮动,不需要清除inline-block造成的空白,只需要一些padding即可,结束。
2. 掌握基础,学习CSS技巧
不仅是掌握css,掌握任何东西都要从基础做起。一个对最基本的东西都理解不透彻的人是不可能成为大师的。
CSS基础
什么是css基础呢?你可能会听到不同的声音,这也是一种无法用言语表达的东西。但我认为,css的基础是以下两部分:
- 盒模型:每个元素在css中都是一个盒子模型(块级或者内联),包含宽高及各种padding margin border.这是最重要的,详细可以阅读这里。
- 权重:了解哪个属性权重最高,在调试css中非常重要。更多相关信息可以阅读Assigning property values, Cascading, and Inheritance一文。
CSS技巧
当你了解了以上原理,才算踏上了康庄大道。那么现在你可能会处理一些特殊情况,下面展示了一些:
忘了在父元素设置position
.child { position: absolute; top: 0; left: 0; } /* 这是忘了的*/ /* .parent { position: relative; // Or anything else than static } */
这时候你会想:坑爹啊,怎么东西跑到页面左上角了???你忘了给父元素设置 position:absolute或relative了。。
添加下下层技巧
.parent { z-index: 1; opacity: 0.5; transform: rotate(5deg); } .child { z-index: -1; }
每个搞前端的都被层叠上下文折磨过。这个例子告诉我们,你不能对一个已经触发层叠上下文的元素(可能是z-index,transform或者是透明度)的子元素来应用z-index属性。 这没有变通方案,一旦你遇到过,绝对会记忆犹新。。
忘了清除浮动的技巧
你的布局乱套了,容器乱飞。你泪流满面:这是肿摸了。。请检查下浮动,可能忘了清除浮动了。
记住,一个容器如果仅仅包含浮动元素,他会塌陷,除非你清除浮动或者设置height或者overflow属性。
这种例子比比皆是,如果继续写那就没完没了了,这不是我这篇文章的目的。
我只是想指出 每天,人们都会不断的发现,css有很多的特性跟特殊情况。 你可能这一次踩个坑,下次就知道怎么对付了。
3. 保持代码的可复用性
Dry代表 不要重复自己。这并不是css特有的,这适合任何语言。
它的核心思想是,能重用的代码就不要写第n遍。在别的语言意味着封装成function,在css里,常常代表你需要利用一个可复用的类来代替重复应用的一个属性。这将在后面的面向对象css中进一步讲解。其实对于重构来说这是很简单的,我来解释一下:
当你在你的样式表里发现一段代码多次使用的时候,你需要重构一下,最终变成只出现一次(可复用)。例子:
.navigation li { color: #333; } .navigation li a { color: #333; } /* Refactoring */ .navigation li, .navigation li a { color: #333; }
明白么?你肯定会纳闷,这俩有啥区别啊?有两点需要考虑: 性能跟可维护性。
关于性能: 更少的行数意味着浏览器解析css会更快。按照下面这样写,浏览器会同时给两个选择器应用颜色,而不会解析两次。
关于可维护性,如果你需要修改类似的颜色,这样只需要修改一行,这里可能仅仅是两行,如果50行,100行呢。
扩展阅读
- DRY CSS, don’t repeat your CSS
- DRY CSS: a don’t-repeat-yourself methodology for creating efficient, unified and scalable style sheets
4. 面向对象的css
这是什么东东?
Oocss意思是面向对象的css,经常在其他面向对象的语言中出现这个名词。意思是利用一个“对象”,通常为一个类的实例(包含一些属性和方法)。你可能会问:这跟css有啥关系啊。
首先我要说明,oocss更像一个概念,css是不能真的“面向对象编程”的,因为没有命名空间,函数,方法,类,条件语句等。因此你要是谈oocss可能会被人嘲讽。
事实上我也是这么认为的,但我们可以利用这样的思想来促进css的书写,让网站性能提升,提高可维护性。
我们应该怎么做?
很简单,使用类名,各种类名。可以把你的网站想象成一个带有很多“方法”跟“组件”的地方,尝试找出这些重复的部分,把他们作为“对象”(类名),从而重用。
为了让你的对象划分的更精确,有两点需要注意:
- 分离结构与表现
- 分离容器与内容
单独的结构和样式
分离结构与表现是很重要的,这样你就可以单独操作负责显示的部分,让这部分在网站中多次出现,并且作用于不同的元素上。看看下面的代码,它可以作用到一个盒子,一个图片,或者一个按钮上:
#my-button, .my-box .my-box img { border: 1px solid #444; border-radius: 5px; box-shadow: 0 0 5px rgba(0,0,0,0.1); }
另外我们可以用一个叫做.skin的类名代替,然后应用到所要使用的元素上
.skin { border: 1px solid #444; border-radius: 5px; box-shadow: 0 0 5px rgba(0,0,0,0.1); }
这样使用,会让css样式表更加容易让人理解,更容易维护,解析更快。
单独的容器(结构)和内容
我认为这是oocss最重要的一点:每种组件拥有独立的代码,而不是在你某次写页面时配合页面的特定部分来定义。在你的站点中,类似的组件应该重用,就像下面代码一样:
#main h2 { color: #343434; font-size: 25px; line-height: 20px; border-bottom: 1px solid rgba(0,0,0,0.2); box-shadow: 0 1px rgba(255,255,255,0.4); }
这时候不管是我从页面底部再次使用h2,或者我用同样的思想使用h3,都可以类似上面所写的,创建一个类,并给类设置样式,而不是给元素单独设置样式。
关于从不使用ID的一说?
当Nicole Sullivan提出oocss的概念时,最热烈的讨论是“绝对不使用id选择器么?” Nicholas C. Zakas 与 Nicole Sullivan在他们的csslint(css质量检查工具)中特别反对对id选择器的使用。
为了理解nicole的观点,我们必须认识到id选择器因为高权重会在使用中出现一些问题。如下代码(代码来自于这里):
<!-- HTML --> <div id="header"> <p> <a href="#">Foo</a> <a href="#">Bar</a> </p> <div class="tweet"> <a href="#">Follow me on twitter</a> </div> </div> <div class="tweet"> <a href="#">Follow me on twitter</a> </div>
/* CSS */ #header a { color: #f90; } .tweet a { color: #000; }
如果让第一个twitter的链接变黑,你有两种选择:给一个id,或者利用!important选择器来机枪打蚊子。如果header是一个类名,就不会有这种问题了。
这也是Nicole Sullivan为什么讲“no ID”的原因。
我引用 harry roberts对此话题的一个讨论来作为这节结束
[…] I have decided that a blanket ban is sensible. Save yourself many potential headaches and never use IDs in your CSS files.
当然原则上id是可以使用的,而且很易生效
我对OOCSS的理解
事实上我并不熟悉oocss。因为我并不在一个拥有很多前端的的大型网站工作。Oocss对大型网站架构很有用,但不适合单页面作战。
然而虽然我并未应用oocss,但我关注前端工作中的组件重用,样式表的可维护性以及性能。这也是oocss所注重的,所以在某些方面,我的工作跟oocss并没有太大区别。
扩展阅读
- An introduction to OOCSS
- Object Oriented CSS
- OOCSS.org
- Don’t use IDs in CSS selectors?
- OOCSS——概念篇
- OOCSS——核心篇
5. Css3:了解他能做的以及你可以使用的部分
现在我们打住概念性的讨论,来点干货:css3,虽然这玩意至今没有个确切的定义。
Unlike CSS 2, which is a large single specification defining various features, CSS 3 is divided into several separate documents called “modules”. Each module adds new capabilities or extends features defined in CSS 2, over preserving backward compatibility. […] Due to the modularization, different modules have different stability and statuses.
From Cascading Style Sheets on Wikipedia
现在我们来讨论下那些已经被现代浏览器实现的一些特性。
当前,从圆角到渐变,从透明到阴影,伪类,随处可见css3。
学习你能做些什么?
我觉得,通过利用css3,你可以减少http请求(图片请求),减少标签数量,减少js的代码量。让我们展开来说:
- 圆角,一行代码代替了用四张小图片拼四个圆角;
- 透明度与alpha通道的支持: 一行代码代替了一张半透明png;
- 更先进的选择器:不需要js来写了;
- Flexbox:几行代码代替了一整个布局框架;
- 渐变:几行代码代替了背景平铺的图片;
- 多背景:不需要多个容器了;
- 伪类:装饰性的元素不需要额外的标签去定义了。
我可以继续讲下去,但是我相信你已经明白了我的意思:知晓你到底可以用css3来做什么。你需要做一个目录么?你可以用纯css来实现,配合CSS counters,你需要做一个漂亮的自定义边框么?你可以利用border-image属性来实现。
ss能做无数的事情,css3也一样。你需要了解css力所能及跟力所不能及的。但深入这些,没有什么捷径,只能通过不断的阅读文档,自我探索。比如,你可以用calc()属性来计算,但如果要搞六列的等高布局,你肯定会杯具。
学习你能用什么?
css最大的问题是浏览器兼容性。在css3里这种情况变得更加糟糕。当你不断试验css3属性时,这将是你萦绕不去的梦魇。
比如最耳熟能详的css3属性:border-radius,杯具的是ie8以下,跟opera mini浏览器仍然不认识这玩意。事实上chrome跟FF对圆角的渲染也不一致。
这对一名前端来说意味着啥呢?优雅降级。如果你做圆角,除了border-radius,你仍然需要利用多图片来拼圆角,努力让各大浏览器保持一致。
当我要使用css时这是我通常的思考步骤:
- 我要用这css干嘛?
- 我明白我要干嘛了,这是css2规范里的么?
- 必须的,结束。
- 不行,跳到第三步
- 这玩意兼容性怎么样啊
- 很好的兼容啊,结束
- 兼容性很一般,跳到第四步
- 这是锦上添花还是需求啊?
- 这是锦上添花,那么低端浏览器我就只能优雅降级了。
- 这是需求啊!跳到第五步
- 我怎么在不兼容的浏览器里对付这个需求呢?
现在以渐变为例:
- 这里要用渐变?
- 用吧。。css2里有渐变?
- 渐变是css3的好吧。
- 兼容性呢?
- 还好吧,一般化,ie8以下跟operamini不支持css3渐变(这里明显有误了)
- 这是锦上添花还是需求啊?
- 这只是一种更炫的手段,不是重点。不支持的我就用个单色代替吧。
- 需求要求这里就是用渐变啊!我得找兼容了。
- 我要如何让它不支持的浏览器上工作
- 用背景图片吧。
如果你用css的时候思考这些步骤,就有思路来处理浏览器兼容性跟优雅降级之类的了。
注意!一定要注意你产品的用户!如果你要做移动端app或者移动设备,你可以使劲用css3属性,不用担心。但如果你做个银行系统。。抱歉了,大部分用户都是ie8以下的
Providing fallbacks
根据不同情况,对低端浏览器做兼容可能会很蛋疼,也可能会很烦人。
No fallback or simple fallback
如果有些增强用户体验的特性不被支持,不会带来什么后果的话,你就不用强制兼容了,这太爽了。
也有一些情况兼容起来也比较简单。
总之你需要写两份属性来实现这个效果,作用于老版本浏览器的跟现代浏览器版的。
.my-element { border: 1px solid #666; border: 1px solid rgba(0,0,0,0.3); background: #708090; background: hsl(210, 13%, 50%); }
以上的例子中,如果浏览器不识别rgba跟hsl颜色,他会读第一行跟第三行作为降级。那么现代浏览器就会覆盖这些属性,以新属性来渲染。
Modernizr
现在当我们聊到css3的时候,绝对会提及一个库Modernizr。 他可以对浏览器做html5跟css3的特性检测。听起来可能觉得很庞大,但这个库性能非常的好。
无论如何,有时你必须确切地知道如果浏览器支持一个特定的功能。因为,对我们说,提供另一种优雅降级版本,需要知道他的CSS属性。
/* Normal version */ .dropdown { opacity: 0; pointer-events: none; } .trigger:hover .dropdown { opacity: 1; pointer-events: auto; } /* Fallback with Modernizr */ .no-opacity .dropdown, .no-pointerevents .dropdown { opacity: 1; pointer-events: auto; display: none; } .no-opacity .trigger:hover .dropdown, .no-pointerevents .trigger:hover .dropdown { display: block; }
如果你要提供一个降级方案的话,需要依赖modernizr提供的两个类(.no-opacity 跟.no-pointerevents)但不能同时触发两个。在使用新技术的时候,一定要记得优雅降级,这对用户体验很重要,如果不行,一定要告知用户。
扩展阅读
- CSS current work with table of specifications
- WebPlatform.org
- Modernizr for feature detection
- CanIUse for the browser support
6. 渐进增强与优雅降级
这两个概念大家肯定耳熟能详了,尤其是优雅降级。其实两者还是有点区别的。
渐进增强
渐进增强,你需要制定一个基本的需求和功能,然后根据浏览器支持度,增强用户体验。你在使用的时候,需要用一些html5属性来提醒某些部分缺失(比如在某某浏览器下可以获得最佳体验)。这是一种根据浏览器引擎增强用户体验的方式。
优雅降级
当你谈到优雅降级的时候,通常是给低端浏览器提供一个不支持特性的替代方案。他的形式通常是从高级到低级讨论的。比如说你需要在canvas标签里面注明,这样当浏览器不支持canvas的时候用户就会知道了。
<canvas> This page uses HTML5 Canvas. Please use a recent browser to see this content. To get another browser, go to <a href="http://browsehappy.com/">BrowseHappy</a> </canvas>
他们有何不同?
事实上没啥区别。有些特性呈现在现代浏览器上,而对此在低端浏览器上则上替代方案。这是一个过程:你可以让网页在现代浏览器中的效果很炫,也得顾忌ie,或者置之不理,这完全取决于你。事实上我想说:不同浏览器的用户体验绝对是不同的,即使你需要提供一些基本功能,也请记得利用新特性增强一下你的浏览器或者应用,这是非常好的。
扩展阅读
7. Css预处理工具
Css预处理器大概是本年度热门话题了。。这玩意真的好用么?用来干嘛?我需要用么?用什么样的?这是css圈子里的热门话题了。
在这个环节我将以客观的态度来对待这个问题。首先要明确一点:如果你不想用预处理器,请不要用,然后就不会纠结了。不用预处理器并不代表你不是个好前端,仅仅是你可能无法完成一些事情而已。但对待预处理器这件事上,你仍然需要有自己独立的思考。
接下来,什么是预处理器?事实上预处理器就是把一些语句段编译成别的引擎(比如浏览器)需要的语言。各种语言都有预编译,比如html可以使用markdown或者jade。Less,sass跟stylus都是css的预处理器。Coffeescript是js的预处理器,当然还有php的预处理器:cakephp。
要点是什么?
预处理器赋予了css一些基于面向对象语言的特性,比如
- 变量(variables)
- 可传参的函数(functions (with parameters))
- 命名空间(namespaces)
- 嵌套(nesting)
- 条件语句(conditional statements)
- 操作(operations)
- 其他(and many more)
听起来很有吸引力,对吧?也许你想要一个例子来找出发生了什么。让我们看下面的CSS导航栏。
.navigation { width: 800px; width: calc(100%-150px); } .navigation li { color: #444; } .navigation li a { text-decoration: none; }
看一个Scss处理的版本
$main-color: #444; .navigation { width: (100%-150px); li { color: $main-color; a { text-decoration: none; } } }
预处理器的基本功能就是把这些表达式翻译成css,结果肯定是相同的,而处理逻辑不同。预处理器会自动处理并输出结果,而不需要calc函数的支持。
最终,你得到了一个可读性更强的(包含嵌套与变量),可维护性更强的(包含变量与函数)的样式表。上面的仅仅是举个例子,在真实的项目里你会体会到这一点。
如何选择?
现在市面上已经有一些不同的css预处理器了,他们各有千秋,同时在细微之处也有区别。选择的余地完全在你手里。这里提供几个主要的选择:
- Sass (written in Ruby)
- LESS (written in JavaScript)
- Stylus (written in JavaScript)
- Crush (written in PHP)
最好的方式是了解他们是否能最完美的满足你跟你项目的需求。这是由很多因素决定的,如果全部列出来就超出本文的范围了,但你可以找到一些相关的css预处理器的资料。
我对CSS预处理的理解?
我不敢说精通css预处理器,但我非常喜欢。他完善了一些css缺少的非常有用的特性:变量,嵌套以及条件语句。
我之前小玩了一下less,受益匪浅。利用less我完善了以前制作的 CSS Loading Animations,less应用在了循环,自动加前缀以及关键帧上。
我也尝试了sass跟compass。令我震惊的是这玩意安装很简单,在ruby上跑得也很顺畅。所以我觉得Sass + Compass碉堡了。你可以看看我的文章:为啥我抛弃了less选择了sass。
不过我还是需要完全手写普通的css,这也占据了我工作的绝大部分。但最终我觉得大家都会用css预处理器。Css缺乏一些很有用的特性,而预处理器正好填补了这方面的空白。
扩展阅读
- Sass vs. LESS vs. Stylus
- Musing on preprocessing
- Deep Dive Into CSS Preprocessors
- Guidelines using OOCSS and CSS preprocessors
8. 与时俱进
语言在不断的进化,css是显著典型。Css草案没完没了,浏览器厂商也在不断的实现这些。
因此,你需要与时俱进,始终对新技术保持跟进,虽然一时半会还用不上,但可以了解chrome开发版本是不是支持了?chrome跟safari,ff,opera未来的版本会不会支持呢?你需要在css解决方案及css问题上,不断的开拓自己的眼界。
扩展阅读
- Cascading Style Sheets home page
- CanIUse.com for browser share and compatibility
- Mozilla Developer Network for excellent documentation
- HTML5 Rocks for latest, cutting-edge tutorials and articles
9. 取长补短
读源码是学编程最好的方式之一。css是客户端的,你可以用WebKit Inspector, Dragonfly, Firebug F12等工具看css。同时,互联网是很开放的,大家都乐于开源。
另外一种方法是跟着教程一步步地走,然后从头自己写一遍。遇到问题后瞄一眼答案,然后继续。
如果你觉得自己已经熟悉css了,想深入css,你需要写一些demo来测试那些试验性的css属性,或者解决一个问题的不同思路。学无止境。
前阵子Chris Coyier, Tim Sabat 和 Alex Vazquez三位建立了CodePen,他是一个在线分享前端代码的平台,可以自由的添加你需要的库,比如jQuery, jQuery UI, MooTools, YUI, Prototype, Zepto, Dojo, Ext JS, PrefixFree等等。同时也可以使用一些预处理器比如HAML, Markdown, Slim, LESS, SCSS, Sass, CoffeeScript。
学习其他人例子的网站:
10. 熟能生巧
实践出真知。所以最好的建议:不断的练习。熟能生巧。并不是让你不停的从头建站。你可以从dribbble上找些图用纯css实现一下。最终你可能不一定会用到,但你学到了,这就足够了。
我之前也说了,掌握基础,了解技巧。Css有很多坑,填坑是csser日常工作的一部分。而坑都是写代码的时候踩出来的,只有踩过了,解决过了,才能提高。
同时我建议你多多分享自己的代码,让大家提提意见,取百家之长方为上。你可以扔到JSFiddle里然后分享到群里,问问大家有没有可以吐槽的。
扩展阅读
本文提到很多链接与资源,全部列入在此,以供大家索引阅读:
- Cascading Style Sheets home page
- CSS current work with table of specifications
- Assigning property values, Cascading, and Inheritance
- Cascading Style Sheets on Wikipedia
- CSS 2.1: Box Model
- WebPlatform.org
- Modernizr
- CanIUse.com
- Z-Index And The CSS Stack: Which Element Displays First? by Steven Bradley
- DRY CSS, don’t repeat your CSS by Steven Bradley
- DRY CSS: a don’t-repeat-yourself methodology for creating efficient, unified and scalable style sheets by Jeremy Clarke
- Progressive enhancement and graceful degradation on DevOpera
- Understanding progressive enhancement by Aaron Gustafson
- Sass
- LESS
- Stylus
- Crush
- Sass vs. LESS vs. Stylus by Johnathan Croom
- Musing on preprocessing by Chris Coyier
- Deep Dive Into CSS Preprocessors by Johnathan Verrecchia
- Guidelines using OOCSS and CSS preprocessors by Chris Webb
- Mozilla Developer Network
- HTML5 Rocks
- CodePen
- CSS Deck
- Dabblet
- TheCodePlayer
非常感谢你阅读此文,希望这篇文章可以真正在你学习使用css的时候帮到你。当然有意见跟建议你也可以提出来~
译者手语:整个翻译依照原文线路进行,并在翻译过程略加了个人对技术的理解。如果翻译有不对之处,还烦请同行朋友指点。谢谢!
如需转载烦请注明出处:
英文原文:http://tympanus.net/codrops/2012/11/20/learning-principles-for-improving-your-css
中文译文:http://www.w3cplus.com/css/learning-principles-for-improving-your-css.html