噩梦:间距从 8 的倍数全部换成 5 的倍数
在进行 UI 统一的过程中,为了达到统一的视觉效果,设计师会约定元素的间距为某一个常量的倍数,例如内外边距都要求为 8 的倍数,转换为代码即为:
/* style.css */
.box {
margin: 8px;
padding: 8px 16px;
}
.box2 {
margin-left: 16px;
}
.box3 {
padding-right: 32px;
}
......
对于每一个元素声明样式间距,显得细碎繁琐,且存在“灾难隐患”,如果设计提出“8 的倍数太大(小)了, 我们把间距的基准调整为 5(10)吧 ~”,对于野蛮生长的代码来说,这一句话意味着着极大的低效重复工作。
1. 什么是 CSS 预处理器
CSS
使用大量简单语句的集合来标示元素样式。作为样式表语言,没有编程语言的变量结构、控制语句等特性,编写低效,不可避免的产生许多重复、冗余的基础代码。
为了解决上述的问题,例如 Sass
、Less
、Stylus
等 CSS 预处理器应运而生,可以将支持定义嵌套、变量定义、控制语句、逻辑判断等类编程语言结构的 DSL 编译成 CSS,提高开发效率和可维护性。
2. Sass 如何解决 8 变 5 的问题
$base-margin: 8; // 变量定义
@for $i from 1 through 6 { // for 循环 从 1 到 6
$margin: $base-margin * $i; // 变量定义
.m#{$i}x {
margin: #{$margin}px;
}
.m_t#{$i}x {
margin-top: #{$margin}px;
}
.m_r#{$i}x {
margin-right: #{$margin}px;
}
.m_b#{$i}x {
margin-bottom: #{$margin}px;
}
.m_l#{$i}x {
margin-left: #{$margin}px;
}
}
编译后
.m1x {
margin: 8px;
}
.m_t1x {
margin-top: 8px;
}
.m_r1x {
margin-right: 8px;
}
.m_b1x {
margin-bottom: 8px;
}
.m_l1x {
margin-left: 8px;
}
.m2x {
margin: 16px;
}
.m_t2x {
margin-top: 16px;
}
.m_r2x {
margin-right: 16px;
}
.m_b2x {
margin-bottom: 16px;
}
.m_l2x {
margin-left: 16px;
}
.m3x {
margin: 24px;
}
......
这里使用了 Sass
的变量定义,来声明了基准间距 base-margin
,使用 for
循环从 1 到 6,遍历生成 1~6 倍基准间距的 margin
样式。当发生基准值变化的时候,我们只需要修改这里的 base-margin
变量定义,即可完成对整体样式间距的调整。
这是对 Sass
for
循环 控制语句的一个简单应用,Sass
还提供了更多统一样式结构、简化开发的用法。基础速成推荐 阮一峰老师的 SASS用法指南。
下面来看一下 Sass 进阶用法。
3.Sass 进阶
3.1 变量
$baseTextColor: #666666;
.title {
color: $baseTextColor;
}
3.1.1 Sass 的六种数据类型
- 数字(1.2,13,10px)
- 文本(“qjyd”,‘foo’,abc)
- 颜色值(#fff,rgbc(0,0,0,0.3))
- boolean(true,false)
- null
- 值列表,通过空格或者逗号分割(Arial,sans-serif,0 10px 5px 10px)
- 值映射,kv(key :value)
3.1.2 变量作用域
Sass 中变量存在块级作用域(对比 Less 的变量作用域),但不存在提升,变量必须在使用前进行定义;
$color: #fff;
.container {
color: $color;
$color: #000;
.box1 {
color: $color;
}
.box2 {
$color: #ccc;
color: $color;
}
}
.right {
color: $color;
}
compile
.wrap .main {
width: 20px;
}
.wrap .sidebar {
width: 30px;
}
.content {
width: 10px;
}
3.2 四则运算
Sass 支持 加减乘除以及取余运算
// 数值
.box {
$width: 10px;
$width2: 20px;
width: $width + $width2;
}
// 文本
.box:before {
content: "Foo " + Bar;
}
compile
.box:before {
content: "Foo Bar";
}
复杂运算可以使用 #{}
进行包裹,#{}
可以将变量转换为字符串,然后在选择器和属性值上可以进行拼接操作
$base-margin: 8;
@for $i from 1 through 3 {
.m#{$i}x {
margin: #{$base-margin * $i}px;
}
}
compile
.m1x {
margin: 8px;
}
.m2x {
margin: 16px;
}
.m3x {
margin: 24px;
}
Sass 中的除法需要特别注意,
/
运算符在 css 中也是合法符号,例如:font 在略写属性时,font-size 和 line-height 会使用 / 分割,font: 18px/1.5;
,对于 CSS 中属性允许包含/
的位置,Scss 编译不进行计算;针对这种情况,可以使用
#{}
包裹,使用 变量、函数、括号等进行强制运算
3.3 继承
3.3.1 @extend
@extend
可以解决 CSS 代码复用的问题。举个例子,我们日常习惯使用 .clearfix
类来清除浮动,需要给每一处 HTML 结构增加类,产生 CSS 和 HTML 的耦合
.clearfix {
clear: both;
}
.contaienr {
@extend .clearfix;
}
.slide {
@extend .clearfix;
border: 1px solid #ddd;
}
compile
.clearfix, .contaienr, .slide {
clear: both;
}
.slide {
border: 1px solid #ddd;
}
思考,如果继承的双方是复杂选择器会发生什么呢?
.table .cell { color: #fff; } .table .box .content { @extend .cell; }
3.3.2 @mixin
@mixin
类似宏,定义一段片段,可以是变量,可以是属性kv,也可以是完整的选择器和内容样式
// 基础用法
@mixin error {
color: red;
border-color: red;
}
.text.error {
@include error;
}
// 指定参数 && 缺省
@mixin skin($value: #ccc) {
color: $value;
}
.default {
@include skin();
}
.green {
@include skin(green);
}
compile
.text.error {
color: red;
border-color: red;
}
.default {
color: #ccc;
}
.green {
color: green;
}
3.4 控制语句
3.4.1 @for 循环
只能使用数值循环,固定循环间隔
$base-margin: 8;
@for $i from 1 through 3 {
.m#{$i}x {
margin: #{$base-margin * $i}px;
}
}
compile
.m1x {
margin: 8px;
}
.m2x {
margin: 16px;
}
.m3x {
margin: 24px;
}
3.4.2 @while 循环
相比 @for
循环,@while
可以自定义间隔
$i: 6;
@while $i > 0 {
.item-#{$i} { width: 2em * $i; }
$i: $i - 2; // 自定义 flag
}
compile
.item-6 {
width: 12em;
}
.item-4 {
width: 8em;
}
.item-2 {
width: 4em;
}
3.4.3 @each 循环
比 @while
更灵活的循环
// 单一变量遍历
@each $item in a,b,c,d {
.#{$item} {
background-image: url(/image/#{$item}.jpg);
}
}
// 变量组 遍历
@each $animal, $color, $cursor in (puma, black, default),
(sea-slug, blue, pointer),
(egret, white, move) {
.#{$animal}-icon {
background-image: url('/images/#{$animal}.png');
border: 2px solid $color;
cursor: $cursor;
}
}
3.4.4 自定义函数
// px 2 rem 转换
@function px2rem($px, $base-font-size: 75px) {
@if (unitless($px)) {
@return px2rem($px + 0px);
} @else if (unit($px) == rem) {
@return $px;
}
@return ($px / $base-font-size) * 1rem;
}
.banner-common{
width: 100%;
height: px2rem(420px);
}
compile
.banner-common {
width: 100%;
height: 5.6rem;
}
日常我们使用 sass,最多的是嵌套结构,变量定义,其他的特性很少触及;类似的还有框架里的进阶用法、手动 render、或者是日常习惯了但存在优雅实现的语法特性,都要我们在常规开发中,不断思考、持续摸索,打破常规、寻找快乐~ ????