css 预处理器
1. css 使用的缺点
1)css语法不够强大,因为无法嵌套导致有很多重复的选择器;
2)没有变量和合理的样式复用机制,导致逻辑上相关的属性值只能以字面量的形式重复输出,难以维护。
2. css预处理器的定义
为css增加编程特性的拓展语言,可以使用变量、简单逻辑判断、函数等基本编程技巧;
用一种专门的编程语言,进行 Web 页面样式设计,再通过编译器转化为正常的 CSS 文件,以供项目使用。
说明:css预处理器编译输出还是标准的css样式。
3. 预处理器带来的好处
1)css代码更加整洁,更易维护,代码量更少;
2)修改更快,基础颜色使用变量,一处动处处动;
3)常用代码使用代码块,节省大量代码;
4)css嵌套减少了大量的重复选择器,避免一些低级;
5)变量、混入大大提升了样式的复用性;
6)额外的工具类似颜色函数 (lighten,darken,transparentize等等),mixins,loops,这些方法使css更像一个真正的编程语言,让开发者能够有能力生成更加复杂的css样式。
sass 和 less 预处理器
Sass、Less、Stylus都是动态的样式语言,是css预处理器,css上的一种抽象层。他们是一种特殊的语法/语言而编译成css。
Sass是一种动态样式语言,Sass语法属于缩排语法,比css比多出好些功能(如变量、嵌套、运算,混入(Mixin)、继承、颜色处理,函数等),更容易阅读。
Sass官网地址:www.sass.hk/ Sass与Scss是什么关系? Sass的缩排语法,对于写惯css前端的web开发者来说很不直观,也不能将css代码加入到Sass里面,因此sass语法进行了改良,Sass 3就变成了Scss(sassy css)。与原来的语法兼容,只是用{}取代了原来的缩进。
Less是一种动态样式语言. 对CSS赋予了动态语言的特性,如变量、继承、运算、函数。Less 既可以在客户端上运行 (支持IE 6+, Webkit, Firefox),也可在服务端运行。 LESS的官网: less.bootcss.com/
Sass与Less区别
- 1、实现方式 1)Less是基于JavaScript,是在客户端处理的。
2)Sass是基于Ruby的,是在服务器端处理的。
- 2、变量 1)sass 是以开头定义的变量,如:开头定义的变量,如:开头定义的变量,如:mainColor: #963;
2)less 是以@开头定义的变量,如 @mainColor: #963;
Sass与Less,选择Sass
为什么选择使用Sass而不是Less?
1、Sass在市面上有一些成熟的框架,比如说Compass,而且有很多框架也在使用Sass,比如说Foundation。
2、就国外讨论的热度来说,Sass绝对优于LESS。
3、就学习教程来说,Sass的教程要优于LESS。在国内LESS集中的教程是LESS中文官网,而Sass的中文教程,慢慢在国内也较为普遍。
4、Sass也是成熟的CSS预处理器之一,而且有一个稳定,强大的团队在维护。
5、同时还有Scss对sass语法进行了改良,Sass 3就变成了Scss(sassy css)。与原来的语法兼容,只是用{}取代了原来的缩进。
6、bootstrap(Web框架)最新推出的版本4,使用的就是Sass。
sass 预处理器使用
1. 变量
sass使用$符号来标识变量(老版本的sass使用!来标识变量。
$highlight-color: #F90;
与CSS属性不同,变量可以在css规则块定义之外存在。当变量定义在css规则块内,那么该变量只能在此规则块内使用。
$nav-color: #F90;
nav {
$width: 100px;
width: $width;
color: $nav-color;
}
//编译后
nav {
width: 100px;
color: #F90;
}
在声明变量时,变量值也可以引用其他变量。
$height : 10px;
$width: $height + 10px;
nav {
width: $width;
}
2. 嵌套(Nesting)
子组合选择器和同层组合选择器:>、+和~
这三个组合选择器必须和其他选择器配合使用,以指定浏览器仅选择某种特定上下文中的元素。 这些组合选择器可以毫不费力地应用到sass的规则嵌套中。可以把它们放在外层选择器后边,或里层选择器前边:
article {
~ article { border-top: 1px dashed #ccc }
> section { background: #eee }
dl > {
dt { color: #333 }
dd { color: #555 }
}
nav + & { margin-top: 0 }
}
sass会如你所愿地将这些嵌套规则一一解开组合在一起:
article ~ article { border-top: 1px dashed #ccc }
article > footer { background: #eee }
article dl > dt { color: #333 }
article dl > dd { color: #555 }
nav + article { margin-top: 0 }
属性嵌套
属性嵌套指的是有些属性拥有同一个开始单词,如border-width,border-color都是以border开头。
nav {
border: {
style: solid;
width: 1px;
color: #ccc;
}
}
// 编译成功后的css为:
nav {border:1px soild #ccc;}
选择器嵌套
选择器嵌套指的是在一个选择器中嵌套另一个选择器来实现继承,从而增强了文件的结构性和可读性。在选择器嵌套中,可以使用&表示父元素选择器。
#content {
article {
h1 { color: #333 }
p { margin-bottom: 1.4em }
}
aside { background-color: #EEE }
}
// 编译成功后的css为:
#content article h1 { color: #333 }
#content article p { margin-bottom: 1.4em }
#content aside { background-color: #EEE }
Mixins (混入)
sass样式中声明Mixins时需要使用“@mixin”,然后后面紧跟Mixins的名,他也可以定义参数,同时可以给这个参数设置一个默认值,但参数名是使用“$”符号开始,而且和参数值之间需要使用冒号(:)分开。可以重用的代码块。 Sass 混入语法:
/* Sass mixin error with (optional) argument $borderWidth which defaults to 2px if not specified */
@mixin error($borderWidth: 2px) {
border: $borderWidth solid #F00;
color: #F00;
}
.generic-error {
padding: 20px;
margin: 4px;
@include error(); /* Applies styles from mixin error */
}
.login-error {
left: 12px;
position: absolute;
top: 20px;
@include error(5px);
/* Applies styles from mixin error with argument $borderWidth equal to 5px*/
}
混合关键词传参 //编译前
@mixin button-variant($color, $background, $border) {
color: $color;
border: 1px solid $border;
background-color: $background;
}
.block{
@include button-variant( $background:#fff,$color:red, $border:red)
}
超出省略号 (与项目结合)
// ****** 超出省略号
@mixin ellipsis($line) {
display: -webkit-box;
-webkit-box-orient:vertical;
overflow: hidden;
-webkit-line-clamp: $line;
}
.tit-name {
@include ellipsis(1);
color: #333;
}
继承
sass的继承:@extend
//sass style
h1{
border: 4px solid #ff9aa9;
}
.speaker{
@extend h1;
border-width: 2px;
}
//css style
//-------------------------------
h1,.speaker{
border: 4px solid #ff9aa9;
}
.speaker{
border-width: 2px;
}
函数
最好的例子应该是 REM 布局中的 px2rem 函数了。(移动端开发)
@function px2rem ($px) {
$rem : 37.5px;
@return ($px / $rem) + rem;
}
.hello {
width: px2rem (100px);
height: px2rem (100px);
&.b {
width: px2rem ( 50px);
height: px2rem (50px);
}
}
导入SASS文件;
css有一个特别不常用的特性,即@import规则,它允许在一个css文件中导入其他css文件。然而,后果是只有执行到@import时,浏览器才会去下载其他css文件,这导致页面加载起来特别慢。
sass也有一个@import规则,但不同的是,sass的@import规则在生成css文件时就把相关文件导入进来。这意味着所有相关的样式被归纳到了同一个css文件中,而无需发起额外的下载请求。
使用sass的@import规则并不需要指明被导入文件的全名。你可以省略.sass或.scss文件后缀
使用SASS部分文件
当通过@import把sass样式分散到多个文件时,你通常只想生成少数几个css文件。那些专门为@import命令而编写的sass文件,并不需要生成对应的独立css文件,这样的sass文件称为局部文件。
sass局部文件的文件名以下划线开头。这样,sass就不会在编译时单独编译这个文件输出css
默认变量值;
!default用于变量,含义是:如果这个变量被声明赋值了,那就用它声明的值,否则就用这个默认值。
/* $fancybox-width: 400px !default;
.fancybox {
width: $fancybox-width;
} */
在上例中,如果用户在导入你的sass局部文件之前声明了一个 $fancybox-width
变量,那么你的局部文件中对 $fancybox-width
赋值400px的操作就无效。如果用户没有做这样的声明,则 $fancybox-width
将默认为400px
less 预处理器使用
1. 变量
Less 的变量名使用 @ 符号开始: 例如:
@mainColor: #0982c1;
@siteWidth: 1024px;
@borderStyle: dotted;
body {
color: @mainColor;
border: 1px @borderStyle @mainColor;
max-width: @siteWidth;
}
// 编译成功后的css为:
body {
color: #0982c1;
border: 1px dotted #0982c1;
max-width: 1024px;
}
在声明变量时,变量值也可以引用其他变量。
@width: 10px;
@height: @width + 10px;
#header {
width: @width;
height: @height;
}
编译为:
#header {
width: 10px;
height: 20px;
}
2. 嵌套
嵌套(Nesting) Less 提供了使用嵌套(nesting)代替层叠或与层叠结合使用的能力。假设我们有以下 CSS 代码:
#header {
color: black;
}
#header .navigation {
font-size: 12px;
}
#header .logo {
width: 300px;
}
用 Less 语言我们可以这样书写代码:
#header {
color: black;
.navigation {
font-size: 12px;
}
.logo {
width: 300px;
}
}
用 Less 书写的代码更加简洁,并且模仿了 HTML 的组织结构。
混合(Mixins)
混合(Mixin)是一种将一组属性从一个规则集包含(或混入)到另一个规则集的方法。假设我们定义了一个类(class)如下:
.bordered {
border-top: dotted 1px black;
border-bottom: solid 2px black;
}
如果希望在其它规则集中使用这些属性,只需像下面这样输入所需属性的类(class)名称即可
#menu a {
color: #111;
.bordered();
}
.post a {
color: red;
.bordered();
}
/* LESS mixin error with (optional) argument @borderWidth which defaults to 2px if not specified */
.error(@borderWidth: 2px) {
border: @borderWidth solid #F00;
color: #F00;
}
.generic-error {
padding: 20px;
margin: 4px;
.error(); /* Applies styles from mixin error */
}
.login-error {
left: 12px;
position: absolute;
top: 20px;
.error(5px);
/* Applies styles from mixin error with argument @borderWidth equal to 5px */
}
// 编译成功后的css为:
.generic-error {
padding: 20px;
margin: 4px;
border: 2px solid #f00;
color: #f00;
}
.login-error {
left: 12px;
position: absolute;
top: 20px;
border: 5px solid #f00;
color: #f00 ;
}
继承
less的继承:类似于mixins
//less style
.block {
margin: 10px 5px;
padding: 2px;
}
p {
.block;/*继承.block选择器下所有样式*/
border: 1px solid #eee;
}
ul,ol {
.block; /*继承.block选择器下所有样式*/
color: #333;
text-transform: uppercase;
}
函数
Less 内置了多种函数用于转换颜色、处理字符串、算术运算等。这些函数在Less 函数手册中有详细介绍。
函数的用法非常简单。下面这个例子将介绍如何利用 percentage 函数将 0.5 转换为 50%,将颜色饱和度增加 5%,以及颜色亮度降低 25% 并且色相值增加 8 等用法:
@base: #f04615;
@width: 0.5;
.class {
width: percentage(@width); // returns `50%`
color: saturate(@base, 5%);
background-color: spin(lighten(@base, 25%), 8);
}
@function px2rem ($px) {
$rem : 37.5px;
@return ($px / $rem) + rem;
}
.hello {
width: px2rem (100px);
height: px2rem (100px);
&.b {
width: px2rem ( 50px);
height: px2rem (50px);
}
}
Vue3 新特性 css 变量
为什么 Vue3 选择了 CSS 变量
Vue 3 新增了一条实验性的功能——「单文件组件状态驱动的 CSS 变量」 image
之前的css 变量
CSS 变量又称为 CSS 自定义属性,它包含的值可以在整个文档中重复使用。由自定义属性标记设定值(比如: --main-color: black;),由 var() 函数来获取值(比如: color: var(--main-color);)
为什么选择两根连词线(--)表示? 因为变量 ? 被 Sass 用掉了,@ 被 Less 用掉了。为了不产生冲突,官方的 CSS 变量就改用两根连词线了
给个例子
<div class="parent">
I am Parent
<div class="child">
I am Child
</div>
</div>
.parent {
/* 变量的作用域就是它所在的选择器的有效范围,所以.parent 读取不到 child 中的变量 */
color: var(--body-child);
/* 定义变量 */
--parent-color: blue;
}
.child {
/* 通过 var 读取变量 */
color: var(--parent-color);
--child-color: green;
}
我们现在 .parent 中定义变量 --parent-color: blue;,在 .child 中使用 color: var(--parent-color);
需要注意的是,变量的作用域就是它所在的选择器的有效范围,比如 .child 中定义的 --child-color: green;, 在 .parent 读取不到的,只针对 .child 元素下的元素有效
如果希望能够在 HTML 文档中都能访问到,则可以定义在类 :root 中
除了基础的使用,还有以下几点需要注意
- CSS 变量的命名是对大小写敏感的,也就是 --myColor 和 --mycolor 是不一样的
- var() 参数可以使用第二个参数设置默认值,当该变量无效的时候,就会使用这个默认值
- CSS 变量提供了 JavaScript 与 CSS 通信的一种途径,在 JS 中我们可以操作 CSS,跟操作普通的 CSS 属性是一样
// 获取一个 Dom 节点上的 CSS 变量
element.style.getPropertyValue("--my-var");
// 获取任意 Dom 节点上的 CSS 变量
getComputedStyle(element).getPropertyValue("--my-var");
// 修改一个 Dom 节点上的 CSS 变量
element.style.setProperty("--my-var", jsVar + 4);
Vue2 中使用css 变量
说实话很少用到我们应该直接用less sass
上面说了,CSS 变量并不是什么某个框架的产物,而是原生 CSS 的标准规范。那么在 Vue 2 中直接使用 CSS 变量肯定可以的,并没什么约束。
关键是我们怎么让 Vue 组件中的状态同步到 CSS 变量中,其实也很简单,通过 Style 绑定 即可。
<template>
<!-- 如果要该组件都可以使用,则必须放置在根元素下 -->
<div class="hello" :style="styleVar">
<div class="child-1">I am Child 1</div>
<div class="child-2">I am Child 2</div>
<div @click="onClick">Change Red TO Blue</div>
</div>
</template>
<script>
export default {
name: "HelloWorld",
props: {
msg: String,
},
data() {
return {
styleVar: {
"--colorBlue": "blue",
"--colorRed": "red",
"--fontSize": "30px",
"--fontSizeTest": "30px",
},
};
},
methods: {
onClick() {
this.styleVar["--fontSizeTest"] = "40px";
},
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.child-1 {
color: var(--colorBlue);
font-size: var(--fontSize);
}
.child-2 {
color: var(--colorRed);
font-size: var(--fontSizeTest);
}
</style>
我们只需要在组件的根元素中设置 :style="styleVar"(如果要该组件都可以使用,则必须放置在根元素下),就可以在 Vue 2.x 中实现组件中的状态和 CSS 值的绑定,而且这种绑定关系是响应式的,比如我定义一个方法,改变 font-size 的值,是可以实时更新的 image
:style VS CSS 变量
这里有个问题,现有的 Vue 可以通过 :style 的方式定义去动态绑定 CSS,比如我可以直接在上面的 .child-1中做如下绑定,效果跟上面是一致的。
<div class="child-1" :style="{ color: 'blue', fontSize: '30px' }">
I am Child 1
</div>
那我为什么还要使用 CSS 变量?这样大费周章是否真有意义?
我总结有如下两个原因:
原因一: 复杂的网站都会有大量的 CSS 代码,通常也会有许多重复的值。当组件中的一个状态被几十个地方用到时,那么你可能需要绑定很多个 :style。一来代码会显得可读性不强,二来性能上应该是比原生的要差,毕竟要将更改经过 Vue 的指令绑定到每一个元素上(这一点暂未验证) 通过 CSS 变量,就可以直接通过在组件的根元素设置变量,在组件内部 中直接使用即可
原因二:伪元素的使用 如果直接使用 :style 我们无法设置伪元素的样式,而 CSS 变量就可以
p::first-line {
color: var(--theme-secondary-color);
}
在 Vue 3 中使用 CSS 变量
新增 vars 绑定
<template>
<div class="text">hello</div>
</template>
<script>
export default {
data() {
return {
color: "red",
border: '1px solid black',
};
},
};
</script>
<style vars="{ color, border }">
.text {
color: var(--color);
border: var(--border);
}
</style>
在 Vue 3 中的 SFC 中,style 标签支持 vars 绑定,该参数接受对象键值对方式注入 CSS 变量,如上所示 <style vars="{ color }">
。
这些变量会直接绑定到组件的根元素上,上面的例子中,最后的渲染结果如下:
<div style="--color:red" class="text">hello</div>
和scoped 一起使用
当 vars 和 <style scoped>
一起使用时,所应用的 CSS 变量将以组件的 Scoped id 作为前缀,访问的时候也会自动加上 Scoped id
比如,我们书写如下:
<style scoped vars="{ color }">
h1 {
color: var(--color);
}
</style>
则编译过后,变成
h1 {
color: var(--6b53742-color);
}
假如我们这种情况下想访问的是全局的 CSS 变量呢?也就是我们不希望加上 Scoped Id,那么要书写类似如下:
<style scoped vars="{ color }">
h1 {
color: var(--color);
font-size: var(--global:fontSize);
}
</style>
这样会编译成如下结果:
h1 {
color: var(--6b53742-color);
font-size: var(--fontSize);
}
Less/Sass 中的变量 VS CSS 变量
我理解最重要的一点,就是 CSS 变量可以跟 JavaScript 更好的通信,相当于 CSS 和 JavaScript 的桥梁。在 Vue 中这一点还是体现得挺明显的
另外来看一个切换主题的例子,如果我们用 Sass 变量,如下:
$color-primary: blue;
$color-text: black;
$color-bg: white;
/* invert */
$color-primary-invert: red;
$color-text-invert: white;
$color-bg-invert: black;
.component {
color: $color-text;
background-color: $color-bg;
a {
color: $color-primary;
}
}
.component--dark {
color: $color-text-invert;
background-color: $color-bg-invert;
a {
color: $color-primary-invert;
}
}
我们有两个主题,一个是普通的主题,一个暗黑模式的(dark)。注意,在暗黑模式中,我们需要新的颜色变量去更新旧的颜色变量。假如这种设置非常多的时候,我们会很苦恼。 看 CSS 变量设置的话
:root, [data-theme="default"] {
--color-primary: blue;
/* color contrasts */
--color-bg: white;
--color-contrast-lower: hsl(0, 0%, 95%);
--color-contrast-low: hsl(240, 1%, 83%);
--color-contrast-medium: hsl(240, 1%, 48%);
--color-contrast-high: hsl(240, 4%, 20%);
--color-contrast-higher: black;
}
[data-theme] {
background-color: var(--color-bg);
color: var(--color-contrast-high);
}
[data-theme="dark"] {
--color-primary: red;
/* color contrasts */
--color-bg: black;
--color-contrast-lower: hsl(240, 6%, 15%);
--color-contrast-low: hsl(252, 4%, 25%);
--color-contrast-medium: hsl(240, 1%, 57%);
--color-contrast-high: hsl(0, 0%, 89%);
--color-contrast-higher: white;
}
这种情况下,我们不需要额外定义一个颜色变量,因为我们只需要设置CSS 变量为正确的值即可
之所以会有以上用法上的不同,我理解是 SASS 变量是编译时,也就是说预处理器在向浏览器输出前已经解析完毕,而浏览器对 CSS 变量解析是运行时的
另外预处理器和 CSS 变量并不冲突,它们结合可以更好的提升我们的开体验
缺点——浏览器兼容性问题
CSS 变量目前的支持度并非特别好,IE 目前全部都是不支持的,但终上所述,依旧看好它的未来