泊学4K视频css
回想起每次更新泊学网站,最让我头疼的,就是改写CSS。在不一样的阶段,对CSS不断深刻的理解,对网站内容的调整,对UI的重用需求,都影响着CSS的编写方式,所以,稍不留神,你的代码理解就会充斥着各类风格和各类做用的CSS,让你何时想起这些,都以为心情不那么愉快。布局
所以,就和你们分享一些心得,如何理解CSS,以及如何更有效的编写CSS。网站
首先,咱们从一个最简单的例子开始,回想一下你的第一个CSS例子,必定和下面这样是相似的,所谓CSS,表达的就是页面DOM的样式:spa
<p class="text-center"> Hello world! </p>
而后,在text-center
里,咱们指定文字居中对齐的样式:code
.text-center { text-align: center; }
很简单对不对?随着样式越写越多,咱们很快就会开始关注到一些编写CSS的建议。例如:应该把HTML和CSS的职责分开,HTML中不该该包含任何和具体样式(例如居中对齐)有关的信息,这些具体的样式都应该放到CSS中处理。视频
因而,咱们就开始尝试着用样式要表达的语意来替换掉它表达的具体样式:继承
<p class="greeting"> Hello world! </p> <style> .greeting { text-align: center; } </style>
这样看起来就好多了。不管.greeting
指定的具体样式是什么,都不影响它在HTML中表示欢迎信息样式的含义。这样,从理论上说,咱们就能够用一套HTML模板,实现各类不一样风格的UI了。接口
因而,咱们就开始基于这种语义的方式,来编写各类界面了。例如,咱们添加一个表示视频做者的信息卡,它的HTML模板是这样的:ip
<div class="container"> <div class="creator-info"> <img src="http://7xncmx.com1.z0.glb.clouddn.com/dora11.png" alt=""> <div> <h2>Mars</h2> <p> The creator of boxue.io. Bla bla bla... </p> </div> </div> </div>
一样,在这个模板里,creator-info
是一个按语义命名的样式,接下来,是这个样式的实现:rem
.creator-info { background-color: white; border: 1px solid rgba(0,0,0,0.1); border-radius: 4px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); overflow: hidden; > img { display: block; width: 100%; height: auto; } > div { padding: 1rem; > h2 { font-size: 1.25rem; color: rgba(0,0,0,0.8); } > p { font-size: 1rem; color: rgba(0,0,0,0.75); line-height: 1.5; } } }
它看上去的结果是这样的:
这里,咱们的重点不是这些样式的具体内容,而是这个CSS的结构,若是咱们把全部具体的样式都去掉,你就会发现,这个样式严重依赖于HTML中DOM的层次结构:
.creator-info > img > div > h2 > p
所以,尽管在HTML中,咱们依靠基于语义的样式剥离了CSS,但这种方式却很容易在CSS中暴露过多和HTML相关的细节。所以,这样的作法,实际上并无彻底实现剥离CSS和HTML职责的目的,咱们须要更好的作法。
把样式从DOM结构中剥离出来
为了不样式依赖DOM结构的问题,咱们的思路是:让样式的命名方式兼具格式和语义的功能。而后,在DOM里,对不一样位置的元素,使用对应的样式。这里,咱们借鉴了BEM命名方法,对咱们要使用的样式名称,统一使用这样的命名格式:主体-依赖主体的内容__内容的属性:
<div class="container"> <div class="creator-info"> <img class="creator-info__image" src="http://7xncmx.com1.z0.glb.clouddn.com/dora11.png" alt=""> <div class="creator-info__content"> <h2 class="creator-info__name">Mars</h2> <p class="creator-info__description"> The creator of boxue.io. Bla bla bla... </p> </div> </div> </div>
此次,咱们给DOM中,每个须要样式的元素绑定了有特定命名规则的样式。这样,在样式表里,全部的样式就能够是扁平结构的了:
.creator-info { background-color: white; border: 1px solid rgba(0,0,0,0.1); border-radius: 4px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); overflow: hidden; } .creator-info__image { display: block; width: 100%; height: auto; } .creator-info__content { padding: 1rem; } .creator-info__name { font-size: 1.25rem; color: rgba(0,0,0,0.8); } .creator-info__description { font-size: 1rem; color: rgba(0,0,0,0.75); line-height: 1.5; }
还记得当时本身把泊学网站样式修改为这样以后,着实兴奋了一阵子,由于这样的方式彷佛完全解决了HTML模板和CSS之间相互依赖的问题。
可是没过多久,我就发现了新的问题。当我编写首页上每一个视频系列的UI组件时,结构上,它和以前的做者信息卡几乎是同样的。因而我几乎不假思索的写出了这样的HTML模板:
<div class="container"> <div class="series-info"> <img class="series-info__image" src="https://dn-boxueio.qbox.me/YourFirstMLProject@2x-911fdc56906f05fc0757e5577084c840.jpg" alt=""> <div class="series-info__content"> <h2 class="series-info__name">Machine Learning from Scratch</h2> <p class="series-info__description"> Let's create a real-world machine learning demo from scratch. </p> </div> </div> </div>
它一样包含了一个封面图,一个标题和一个简介。只不过,咱们把样式名称中的主体从creator
换成了series
。可是,当我要给这些新的样式设置值的时候,就有点儿纠结了。该如何设置这些series-***
的样式呢?你可能想到了两种选择。
第一种,最直接的方法,就是把series-***
按照creator-***
复制一遍。这确定能够工做,可是估计没多少人会认同这种作法,由于它违反了Don't Repeat Yourself的原则;
第二种,若是你使用了SCSS,就能够实现从某个样式继承这样的用法:
.series-info { @extend .creator-info; } .series-info__image { @extend .creator-info__image; } .series-info__content { @extend .creator-info__content; } .series-info__name { @extend .creator-info__name; } .series-info__description { @extend .creator-info__description; }
但这样作也有它本身的问题,@extend
应该只在彼此有关联的样式之间使用,而不只仅是为了不重复编写相同的样式。而且,若是稍后咱们还要视频信息卡呢?真的须要这些使用了相一样式的selector么?显然,目前的这种解决方案仍旧不够理想。
实际上,形成样式难以重用的缘由,是由于selector表达的语义过于细致了。语义越细致,重用就越困难。所以,咱们只要把这种绑定相似界面布局UI的selector,起个名字替代掉相似creator
或series
这样的名字就行了:
.media-card { background-color: white; border: 1px solid rgba(0,0,0,0.1); border-radius: 4px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); overflow: hidden; } .media-card__image { display: block; width: 100%; height: auto; } .media-card__content { padding: 1rem; } .media-card__name { font-size: 1.25rem; color: rgba(0,0,0,0.8); } .media-card__description { font-size: 1rem; color: rgba(0,0,0,0.75); line-height: 1.5; }
这样,不管是做者信息仍是视频系列信息,就均可以用同一套样式来表示了:
<div class="container"> <div class="media-card"> <img class="media-card__image" src="https://dn-boxueio.qbox.me/YourFirstMLProject@2x-911fdc56906f05fc0757e5577084c840.jpg" alt=""> <div class="media-card__content"> <h2 class="media-card__name">Machine Learning from Scratch</h2> <p class="media-card__description"> Let's create a real-world machine learning demo from scratch. </p> </div> </div> </div>
甚至,只要UI布局和media-card
描述的体系相同,这套样式就能够直接重用。
可是情到此结束了么?显然没有,如今,你可能又会想了:假设咱们须要修改做者信息卡的样式,但仍保存视频系列信息卡的样式该怎么办呢?
若是像以前同样,它们的样式是独立的,只修改对应的样式就行了。如今,它们共享样式了,我不只要建立新的样式,还要连同对应的HTML一块儿修改,这样作真的好么?
为了回答这个问题,咱们得回到这一节开始提出的目的:分离HTML和CSS的职责。面对这个话题,咱们直觉上就会认为,只有完全剥离了才算完成达成目标。但实际的状况则是,它们二者根本没法作到彻底分离。咱们只能根据本身项目的实际状况,选择一种适合本身的方式。
对于哪些具有详细语义(.creator-info
和.series-info
)的样式而言,此时,HTML是独立的,它彻底不关心这些DOM会长成什么样子。它只暴露了一个接口,容许咱们定制其中的样式。所以,这种选择下的CSS不是独立的,它依赖于样式绑定的HTML,须要以HTML为参考,定义样式的内容。
对于那些具有中立语义(.media-card
)的样式而言,此时,CSS是独立的,它彻底不关心本身会被用在什么元素上。此时,HTML就不是独立的了,它须要知道样式表提供了哪些内容,并基于这些内容,来编排DOM。
实际上,这两种方法,没有绝对的谁优谁劣的问题。只是你要想清楚,哪一种方式更适合本身的项目。
看到这里,若是你和我以前有过相似的困惑,如今,你应该跃跃欲试地要调整下本身的CSS了。先别着急,在下一节里,咱们将继续讨论,如何经过合理的命名,最大化实现样式的可重用目标。