泊學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了。先彆着急,在下一節裏,咱們將繼續討論,如何經過合理的命名,最大化實現樣式的可重用目標。