模塊化
css
選擇符嵌套是文件內部的代碼組織方式,它可讓一系列相關的規則呈現出層級關係。在之前若要達到這個目的,寫法以下,這種寫法須要手工維護縮進關係,當上級選擇符發生變化時全部相關的下級選擇符都要修改;此外把每條規則寫成一行也不易閱讀,爲單條聲明寫註釋也很尷尬(只能插在聲明之間了)html
.nav {margin: auto /* 水平居中 */; width: 1000px; color: #333;}
.nav li {float: left /* 水平排列 */; width: 100px;}
.nav li a {display: block; text-decoration: none;}
複製代碼
在 CSS 預處理語言中,嵌套語法能夠很容易地表達出規則之間的層級關係,爲單條聲明寫註釋也很清晰易讀前端
.nav {
margin: auto // 水平居中
width: 1000px
color: #333
li {
float: left // 水平排列
width: 100px
a {
display: block
text-decoration: none
}
}
}
複製代碼
// 原生 CSS 代碼
strong {
color: #ff4466;
font-weight: bold;
}
.notice {
color: #ff4466;
}
// 用 Stylus 來寫
$color-primary = #ff4466
strong
color: $color-primary
font-weight: bold
.notice
color: $color-primary
複製代碼
// 只能用註釋來表達 max-height 的值是怎麼來的,且註釋中 3 這樣的值也是幻數,還須要進一步解釋
// 將來當行高或行數發生變化的時候,max-height 的值和註釋中的算式也須要同步更新,維護起來很不方便
.wrapper {
overflow-y: hidden;
line-height: 1.5;
max-height: 4.5em; /* = 1.5 x 3 */
}
// 預處理語言來改良
// 在後期維護時,只要修改那兩個變量就能夠了
.wrapper
$max-lines = 3
$line-height = 1.5
overflow-y: hidden
line-height: $line-height
max-height: unit($line-height * $max-lines, 'em')
// 這種寫法還帶來另外一個好處:$line-height 這個變量能夠是 .wrapper 定義的局部變量也能夠從更上層的做用域獲取
// 這意味着 .wrapper 可向祖先繼承行高,而不須要爲這個 「只顯示三行」 的需求把本身的行高寫死
// 有了運算,就有能力表達屬性與屬性之間的關聯,它令代碼更加靈活、更加 DRY
$line-height = 1.5 // 全局統一行高
body
line-height: $line-height
.wrapper
$max-lines = 3
max-height: unit($line-height * $max-lines, 'em')
overflow-y: hidden
複製代碼
// 給一個按鈕添加鼠標懸停效果
.button {
background-color: #ff4466;
}
.button:hover {
background-color: #f57900;
}
// 很難分清 #ff4466 和 #f57900 這兩種顏色到底有什麼關聯
// 若代碼是用預處理語言來寫,那事情就直觀多了
.button
$color = #ff9833
background-color: $color
&:hover
background-color: darken($color, 20%)
複製代碼
Mixins 是 CSS 預處理器語言中最強大的特性,簡單點來講 Mixins 可將一部分樣式抽出,做爲單獨定義的模塊,被不少選擇器重複使用node
Sass 的混合
git
@mixin
,後面緊跟 Mixins 名,也能夠定義參數同時可給這個參數設置一個默認值,但參數名是使用 $
符號開始且和參數值之間須要使用冒號:
分開@include
,而後在其後緊跟要調用的 Mixins 名,不過在 Sass 中還支持老的調用方法,就是使用加號 +
調用 Mixins,在 +
後緊跟 Mixins 名// 聲明一個 Mixins 叫做 error
@mixin error($borderWidth: 2px) {
border: $borderWidth solid #f00;
color: #f00;
}
// 調用 error mixins
.generic-error {
@include error(); /*直接調用error mixins*/
}
.login-error {
@include error(5px); /*調用error mixins,並將參數$borderWidth的值重定義爲5px*/
}
複製代碼
Less 的混合
github
ClassA
中引入另外一個已經定義的 Class
,就像在以前的 Class 中增長一個屬性@
開頭,一樣參數和默認參數值之間須要使用冒號:
分隔開// 聲明一個 Mixin 叫做 error
.error(@borderWidth: 2px){
border: @borderWidth solid #f00;
color: #f00;
}
// 調用 error Mixins
.generic-error {
.error(); /*直接調用error mixins*/
}
.login-error {
.error(5px); /*調用error mixins,並將參數@borderWidth的值重定義爲5px*/
}
複製代碼
Stylus 的混合
編程
=
來鏈接// 聲明一個 Mixin 叫做 error
error(borderWidth=2px){
border: borderWidth solid #f00;
color: #f00;
}
// 調用error Mixins
.generic-error {
error(); /*直接調用error mixins*/
}
.login-error {
error(5px); /*調用error mixins,並將參數$borderWidth的值重定義爲5px*/
}
複製代碼
以上三個示例都將會轉譯成相同的 CSS 代碼瀏覽器
.generic-error {
border: 2px solid #f00;
color:#f00;
}
.login-error {
border: 5px solid #f00;
color: #f00;
}
複製代碼
額外的編譯配置:在寫樣式前須要作一些額外的編譯配置工做,sass-node 安裝以及編譯的配置就能卡住一批前端新手 sass
編譯成本:每次修改代碼都須要從新編譯,佔用時間和 CPU markdown
學習成本:不一樣的 CSS 預處理器語法不一樣,增長學習成本。在同一個團隊甚至項目裏,可能同時使用了好幾種樣式預處理器
// Sass
$color: #f00;
$images: "../img";
@mixin clearfix {
&:after {
content: " ";
display: block;
clear: both;
}
}
body {
color: $color;
background: url("#{images}/1.png");
@include clearfix;
}
// Less
@color: #f00;
@images: "../img";
.clearfix() {
&:after {
content: " ";
display: block;
clear: both;
}
}
body {
color: @color;
background: url("@{images}/1.png");
.clearfix;
}
複製代碼
調試:在使用 CSS 預處理器時,一般會配置 SourceMap 來輔助調試,但即便這樣,仍是會碰到一些調試困難的狀況
各類 CSS 預處理器在更新迭代的過程當中功能愈來愈繁雜花哨,但絕大部分人用到的核心功能仍是那幾樣:Variables、Mixing、Nested、Module,頂多再加上一些工具類函數。既想要預處理器的優勢,又不想要它帶來的成本和缺點,有沒有一箭雙鵰的辦法?CSS 這麼多年一直也在從社區汲取營養加速進化和迭代,能不能從 CSS 標準裏面找到答案呢?
/* declaration */
--VAR_NAME: <declaration-value>;
/* usage */
var(--VAR_NAME)
/* root element selector (global scope), e.g. <html> */
:root {
/* CSS variables declarations */
--main-color: #ff00ff;
--main-bg: rgb(200, 255, 255);
--logo-border-color: rebeccapurple;
--header-height: 68px;
--content-padding: 10px 20px;
--base-line-height: 1.428571429;
--transition-duration: .35s;
--external-link: "external link";
--margin-top: calc(2vh + 20px);
}
body {
/* use the variable */
color: var(--main-color);
}
複製代碼
爲何變量的定義以
--
開頭?緣由在這裏:Let’s Talk about CSS Variables
:root {
--block-font-size: 1rem;
}
.block__highlight {
/* WORKS */
font-size: calc(var(--block-font-size)*1.5);
}
複製代碼
能夠用於經過 RGB 等函數生成和計算顏色:Generate Colors
CSS 變量出現前,從 CSS 傳值給 JS 很是困難,甚至須要藉助一些 Hack 的手法。現使用 CSS 變量,可直接經過 JS 獲取變量值並進行修改
.breakpoints-data {
--phone: 480px;
--tablet: 800px;
}
const breakpointsData = document.querySelector('.breakpoints-data');
// GET
const phone = getComputedStyle(breakpointsData).getPropertyValue('--phone');
// SET
breakpointsData.style.setProperty('--phone', 'custom');
複製代碼
html {
--hue: 210; /* Blue */
--text-color-normal: hsl(var(--hue), 77%, 17%);
...
}
html[data-theme='dark'] {
--text-color-normal: hsl(var(--hue), 10%, 62%);
...
}
// 經過 JS 改變元素屬性,動態切換主題
document.documentElement.setAttribute('data-theme', 'dark')
document.documentElement.setAttribute('data-theme', 'light')
複製代碼
:root {
--pink-schema: {
color: #6A8759;
background-color: #F64778;
}
}
body{
@apply --pink-schema;
}
複製代碼
/* Dropdown menu on hover */
ul {
/* direct nesting (& MUST be the first part of selector)*/
& > li {
color: #000;
& > ul { display: none; }
&:hover {
color: #f00;
& > ul { display: block; }
}
}
}
複製代碼
:matches pseudo-class(已改名爲 :is())
/* 語法 */
:matches( selector[, selector]* )
.nav:matches(.side,.top) .links:matches(:hover, :focus) {
color: #BADA55;
}
/* 至關於如下代碼 */
.nav.side .links:hover,
.nav.top .links:hover,
.nav.side .links:focus,
.nav.top .links:focus {
color: #BADA55;
}
複製代碼
/* 語法 */
@custom-selector: <custom-selector> <selector-list>;
複製代碼
@custom-selector:--text-inputs input[type="text"], input[type="password"];
:--text-inputs.disabled,
:--text-inputs[disabled] {
opacity: 0.5
}
/* 至關於如下代碼 */
input[type="text"].disabled,
input[type="password"].disabled,
input[type="text"][disabled],
input[type="password"][disabled] {
opacity: 0.5
}
複製代碼
rules: [
{
test: /\.css$/,
use: [
'style-loader',
{ loader: 'css-loader', options: { importLoaders: 1 } },
{ loader: 'postcss-loader', options: {
ident: 'postcss',
plugins: () => [
postcssPresetEnv(/* pluginOptions */)
]
}
]
}
]
複製代碼