模块化
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 */)
]
}
]
}
]
复制代码