前一阵子在项目组中讲了一个关于CSS的Session,在讲以前我曾收到了许多意见,大部分是但愿能讲讲CSS实用性的技术,好比盒模型,CSS3之类的。干货人人都喜欢,由于看得见摸得着,拿来就有用,但我最后仍是决定讲一些”湿货“。由于在Code Diff的时候我发现了许多样式的问题不是因为不会写CSS致使的,而是因为在错误的地方使用了写在错误地方的样式。css
其实CSS很简单,没有计算没有流程,只是一直描述,不管什么复杂的效果,你只要Google一下就知道怎么写了,甚至能够直接copy。但CSS又很复杂,一个元素的表现会受到它旁边的兄弟元素,也会受到内部的子元素影响,还会受到父元素影响,在这种多重影响下,一个元素的显示逻辑会变得错综复杂。有没有面对塌陷的块级元素而一筹莫展?不管怎么改它的属性就是得不到本身想要的,但看看彷佛如出一辙的示例程序却安然无恙,是否是恨得咬牙切齿?我想这就是本文所要解决的主要问题,让你学会如何优雅的写CSS。html
其实咱们只要稍微接触过CSS,必定都学过盒模型,我假设你已经对margin、padding和border已经很熟悉。好了,咱们常常会遇到一种状况,想让父元素和子元素之间有一些空间,好比布局的时候,container和content之间的留白。通常来讲有两种方式,一种是给父元素加padding内边距,另外一种是给子元素加margin外边距。如今想一想,你是否慎重考虑过用哪种方式?你是否明白二者的区别?若是你从未考虑过这些,如今考虑也不迟,这真的很重要,若是你真的想优雅的运用CSS,而不是被它耍的团团转,若是你真的想把CSS写出规模,那你就要认真的思考这里面的逻辑。git
先说说父元素的container加上padding的方式,子元素的背景将不会延伸到空白区域,另外一种给子元素加margin的方式则反之。但我想先抛下这个表象,看看此时加上padding的父元素的逻辑。它意味着,我建立了一个容器,而且该容器的内部有一些区域是被看不见的东西填充的,不管放入什么都不该该占据这个区域。在你的脑海中想象一个厚厚的玻璃瓶,它就好像是在说“虽然我是透明的,可是在这厚厚的玻璃以内才是你应该呆的地方,不管是什么只要你想放在瓶子里”。如今来看看子元素,是的,其背景也应该而且确实在内部,而不应占据那段空白的区域。若是是为子元素加上margin,这意味着我在容器中建立了某个东西,而这个东西有一个本身的地盘,容器内的其余东西都不能进入这里。github
因此他们的本质区别在于其所表达的意义,也就是语义,一个是容器上的语义,另外一个是容器内元素的语义,主语也不一样,谓语意义也不一样。那么这能说明什么呢,不得不提一下高级语言中的高级,这表明某个语言将机器语言封装的更好,接口更接近天然语言,其强大不言而喻。其实编程语言的发展轨迹就是不断把机器语言往天然语言翻译,让人们能够更容易的跟机器沟通,终极目标天然是人工智能,和机器用天然语言自由沟通。因此虽然代码或者说CSS的语法并无什么变化,但咱们应该在思惟上清楚的区分代码片断的意图和语义来写CSS。编程
语言学家乔姆斯基曾构造过一句符合语法的话:浏览器
“Colorless green ideas sleep furiously”框架
意思是无色的绿色想法愤怒的睡觉。想法睡觉是违反常识的,无色的绿色是矛盾的,愤怒的睡觉是不合常理的。仅仅符合语法是不够的,仅仅不报错也是不够的,尤为是CSS这种描述性的语言不多会报错,因此我想说的是,其描述性质让咱们有更多选择来实现咱们所指望的效果,但咱们却应该慎重,要让语义分明,而不是在有限的语法规则下任意妄为,那样写不出好的CSS代码。除了其自己的语法规则,咱们必须自我约束,引入语义规则,不只仅是为了提升可读性这样的理由,而是拉近人与机器的距离,让咱们在思惟上更加和代码契合,这样才能写出优秀的程序。less
言归正传,究竟如何语义化CSS呢。以前有讲过OOCSS,其实面向对象的思想就是一种语义化,将虚拟的元素看做实际的对象,用常识来构造代码,就像是用户体验中的用户习惯同样,这是一种遍布全人类的用户习惯,让代码更友好,即所谓的优雅。编程语言
好比最多见的布局,咱们通常都会有header、body和footer,这样无需任何说明和规则,谁都会理解,header在前,footer在后,中间是body。有趣的是table中的thead、tbody和tfoot,因为加载优化,咱们即便把tfoot放在tbody前面,让其先加载,但显示的时候tfoot仍然会在tbody下面,因而可知语义化的重要,不然你必定会觉得不是W3C的人弄错了标准,就是浏览器厂商搞出了Bug。虽然这是HTML标签不是CSS,但我以为这个例子很恰当的说明了一点,显示逻辑是独立的,不该该和其余逻辑混为一谈,它应该只关心如何显示。ide
再好比,一个导航条通常分为左右两边,里面各有若干连接。你会如何命名?navbar-left和navbar-right是Bootstrap所使用的class,但当宽度减小,Responsive响应式的Bootstrap会让这些连接都收进下拉菜单中,左和右又从何谈起呢?一样是Bootstrap中的颜色命名就作的十分红熟,不是green、blue、red这些词汇,而是success、primary、warning这些词,它们的区别是表现化与语义化的区别,我喜欢把这个叫作显示逻辑
。也就是说在class层面咱们应该只关注元素(或者说对象)是用来作什么的(意图)以及它应该表示什么(语义)。这里三种颜色表明成功、重要和警告,至于咱们是用绿、蓝和红来表示仍是经过其余什么颜色甚至形状,应该在style层面写CSS属性表示。如此咱们使用class时无需迷茫于表示成功应该用绿色仍是红色,意图明确无误。回到导航栏的例子,咱们应该使用main和sub之类的词语标识导航栏中重要的和次要的连接,即便在某些实现下,主要和次要没有区别也不用担忧,那是该实现的显示逻辑,咱们不该该横加干涉。
说到class和style(样式属性),这又是一段混乱不清的关系。其实每当咱们要实现一个样式,自觉或不自觉的都会考虑,是将元素和class一一对应,而后为元素上的class写style,仍是用class和几条style对应以后在元素上搭配组合。前者的好处是每一个class中的style不会影响其余class,但可用性十分的低,极端点说这已经不算是在编程了,而是在画页面;后者的好处能够灵活使用不一样的样式搭配给元素使用,组合出元素须要的效果,但很难维护,牵一发动全身,样式很难测试,没法保证在你动了一条style以后,没有影响其余的地方。甚至最要命的是大部分CSS代码都是无心识的游走在这两种状况之间,因此咱们要作的不是选择一种极端,而是找到一个平衡点,并使用一些方法使得咱们的CSS既能灵活复用在各类元素上,又能易于维护,不致修了这破坏那的状况。
首先,对于一个或一套元素的样式,咱们应该有本身的建立原则,而不是想到哪写到哪。好比,我通常使用这样的步骤来建立元素:
首先仅关注结构布局,以站点总体为基准,将元素抽象为一个或多个结构。
好比制做一个按钮,你也许会发现它的尺寸和导航上的连接一致,而内外边距以及display和overflow之类的属性又和页面容器同样,这时你就能够把按钮的结构拆成两个结构,一个是尺寸,一个是边界逻辑,这种状况时常发生,因此有的CSS理论认为应该把width和height这对尺寸属性和padding以及margin这对边距属性完全的分开也是这个道理。其实并非说它们4个放一块儿就决定不行,只是通常它们都有各自复用的价值,因此经常被拆开使用,归根揭底这是由显示逻辑决定的。
通常因为设计统一性,咱们能够借助设计指导,轻松的制做出标准皮肤。但要注意的是,皮肤指的不只仅甚至不必定是颜色之类的。继续用Bootstrap举例,有5种基础颜色,但这并非皮肤,5种颜色的语义不一样,它们只是默认用了5种颜色,勉强能够看做默认皮肤,而真正的皮肤是theme,让按钮变得有立体感。还有一个误区就是认为哪几种属性是皮肤,哪几种不是。就像前面所说的,咱们要在语义上进行划分。一个属性在某些意图下多是结构,在另外的意图中多是皮肤。
举个极端的例子,在一个Workshop中我用CSS和HTML制做了左边这样的Logo,Logo自己应该彻底算是皮肤,由于通常来讲就是一张图片,因此制做它的全部CSS属性都应该算做皮肤。下面的CSS代码中,不管是定位仍是文字的处理,以及尺寸等,都是为了构造Logo,因此这些属性都是皮肤。
css#logo i, #logo b { position: relative; } #logo i { left: -30px; transform: rotate(-30deg); font-size: 60px; letter-spacing: -11px; opacity: 0.3; } #logo b { top: -43px; left: 40px; font-size: 68px; word-break: break-all; width: 3px; line-height: 10px; text-indent: 6px; }
除告终构和皮肤,其实还有一类很容易被人忽视的样式,即便是设计人员也常常忘了它,那就是状态。最多见的是hover,鼠标触碰元素与否的状态,以及active,当前选中的标签,当前所在的分页等等。一般人们会把它划分到皮肤中,但你要明白咱们划分的依据是意图,很显然,状态不是皮肤,仅仅是一般为表达某些状态时会使用一些颜色,毕竟颜色是最好的表示方法。它还与各类逻辑有着千丝万缕的联系,常常会使用JavaScript来加以控制,因此将状态单独分出来是极有必要的,JavaScript只须要更改一个class就能够实现状态的切换,而不是在执行的时候才想起来应该把哪里隐藏把哪里显示,或者是变个颜色出个动画之类的。
接着,不管咱们是已经把各类写好的CSS属性分好了组,仍是正准备以这种方式开始写CSS,我先引入一个语言学的术语 语块(Lexical chunk)
,创造这一术语的 Michael Lewis 认为语言并不是由传统语法和词汇组成,而是由多个词汇的预制语块组成。咱们如今分好的组其实就是一个个CSS的语块,CSS自己就是这种预制功能,咱们要作的就是把style语块化,而后在HTML中写上表明它的class名称,当HTML元素上的多个class组合在一块儿时就组成完整的语义。
好比表示步骤的元素,这是一个形状相似标签,一个挨一个的排列的元素。我将它的尺寸等属性抽出来命名为label,而后把布局的属性组命名为float-left,若是个人设计风格是扁平化的,我能够把相关的皮肤属性命名为flat,你知道虽然扁平化通常用不着特别的属性,但我也能够写一些强制去掉圆角和渐变背景的属性。做为步骤,会分为当前的步骤,以前的步骤,以及还没到的步骤,当前的步骤能够命名为current,或者is—active,后面的步骤不能点因此能够命名为is-disable,这些都是状态。而如今咱们来看看当前步骤元素是什么样的
<div class="flat label float-left is-active"></div>
总结成一句话就是“The flat label which float left is active”。这就是语义化的CSS。把组织好的语块像说话同样做用于元素上,对元素发出指令,让其变成想要的样式。并且你应该会发现,一组该元素所独有的属性,或者是尺寸之类的通常是主语,布局是动宾短语,而皮肤可能是一些形容词,最后状态能够用表语。
总之,CSS做为一个描述性的语言,有不少人以为不能算一种语言,但我反而以为这是一种高级语言,由于更接近天然语言。固然其主要做用是在视觉渲染上,因此应该是一种受限的语言,能够看做是接近天然语言的子集。因此它的性质以为了其重语义轻语法的特色,写CSS不能仅靠语法规则,必定要用上语义规则,最好是能和项目中全部人达成共识,CSS框架其实就是一种通用共识。