作为一个前端开发者我们每天都要写大量的CSS。但是原生的CSS有很多不便比如不能用变量不能嵌套代码重复多维护困难,等。
CSS预处理器就是为了解决这些问题而诞生的。它在原生CSS的基础上增加了变量嵌套混合函数等特性让CSS写起来更优雅更高效更易维护。
目前最流行的CSS预处理器有Sass和Less。我自己在项目中经常使用Sass和Less今天就来分享一下CSS预处理器的实战教程希望能帮到大家。
什么是CSS预处理器
CSS预处理器是一种脚本语言它扩展了CSS的语法增加了变量嵌套混合函数等特性。然后通过编译工具把预处理器的代码编译成原生的CSS供浏览器使用。
简单来说CSS预处理器就是让你用更高级的语法写CSS然后编译成浏览器能识别的原生CSS。
CSS预处理器的好处
- 变量:可以定义变量比如颜色字体尺寸等方便统一管理和修改。
- 嵌套:可以嵌套选择器让代码结构更清晰更易读。
- 混合:可以定义可复用的代码块减少重复代码。
- 函数:可以定义函数进行计算和操作让CSS更灵活。
- 继承:可以继承其他选择器的样式减少重复代码。
- 模块化:可以把CSS分成多个文件模块化管理更易维护。
常见的CSS预处理器
- Sass:最流行的CSS预处理器功能强大生态完善有两种语法Sass(缩进语法),和SCSS(CSS兼容语法)。
- Less:另一个流行的CSS预处理器语法简单学习成本低和CSS很,像。
- Stylus:更灵活的CSS预处理器语法非常简洁但是相对小众。
Sass入门
Sass的安装
Sass是用Ruby写的所以需要先安装Ruby。不过现在也有Node.js版本的Sass更方便前端开发者使用。
使用Node.js安装Sass:
# 全局安装sass
npm install -g sass
# 查看版本
sass --version也可以在项目中本地安装:
npm install sass --save-devSass的编译
Sass文件的扩展名是,.scss或,.sass。.scss是CSS兼容语法和CSS很,像;.sass是缩进语法更简洁但是和CSS差别较大。推荐使用,.scss语法学习成本更低。
编译Sass文件:
# 编译单个文件
sass input.scss output.css
# 监听文件变化,自动编译
sass --watch input.scss:output.css
# 监听目录
sass --watch scss:css
# 输出压缩后的CSS
sass --style compressed input.scss output.css也可以配合webpack,gulp等构建工具使用更方便。
Sass的基本语法
变量
Sass用,$,符号定义变量:
// 定义颜色变量
$primary-color: #333;
$secondary-color: #666;
$accent-color: #007bff;
// 定义字体变量
$font-family: "Helvetica Neue", Arial, sans-serif;
$font-size-base: 16px;
$font-size-lg: 18px;
$font-size-sm: 14px;
// 定义间距变量
$spacing-xs: 4px;
$spacing-sm: 8px;
$spacing-md: 16px;
$spacing-lg: 24px;
$spacing-xl: 32px;
// 使用变量
body {
font-family: $font-family;
font-size: $font-size-base;
color: $primary-color;
}
.button {
background-color: $accent-color;
padding: $spacing-sm $spacing-md;
font-size: $font-size-sm;
}变量的好处是统一管理修改的时候只需要改一处就能全部生效。
嵌套
Sass支持选择器嵌套让代码结构更清晰:
// 原生CSS
.nav {
list-style: none;
}
.nav li {
display: inline-block;
}
.nav li a {
color: #333;
text-decoration: none;
}
.nav li a:hover {
color: #007bff;
}
// Sass嵌套
.nav {
list-style: none;
li {
display: inline-block;
a {
color: #333;
text-decoration: none;
&:hover {
color: #007bff;
}
}
}
}注意,&,符号代表父选择器上面的,&:hover就相当于a:hover。
嵌套属性也可以:
// 原生CSS
.box {
margin-top: 10px;
margin-right: 20px;
margin-bottom: 10px;
margin-left: 20px;
}
// Sass嵌套属性
.box {
margin: {
top: 10px;
right: 20px;
bottom: 10px;
left: 20px;
}
}混合(Mixin)
混合是Sass中非常强大的功能可以定义可复用的代码块:
// 定义混合
@mixin border-radius($radius) {
-webkit-border-radius: $radius;
-moz-border-radius: $radius;
-ms-border-radius: $radius;
border-radius: $radius;
}
// 使用混合
.box {
@include border-radius(5px);
}
.button {
@include border-radius(3px);
}混合也可以有默认参数:
@mixin border-radius($radius: 5px) {
border-radius: $radius;
}
.box {
@include border-radius; // 使用默认值5px
}
.button {
@include border-radius(3px); // 使用3px
}混合也可以包含条件判断:
@mixin triangle($direction, $size, $color) {
width: 0;
height: 0;
@if $direction == up {
border-left: $size solid transparent;
border-right: $size solid transparent;
border-bottom: $size solid $color;
} @else if $direction == down {
border-left: $size solid transparent;
border-right: $size solid transparent;
border-top: $size solid $color;
} @else if $direction == left {
border-top: $size solid transparent;
border-bottom: $size solid transparent;
border-right: $size solid $color;
} @else if $direction == right {
border-top: $size solid transparent;
border-bottom: $size solid transparent;
border-left: $size solid $color;
}
}
.triangle-up {
@include triangle(up, 10px, #333);
}继承
Sass支持选择器继承用,@extend:
// 基础样式
.message {
padding: 10px;
border: 1px solid #ccc;
border-radius: 4px;
}
// 继承基础样式
.success {
@extend .message;
border-color: green;
color: green;
}
.error {
@extend .message;
border-color: red;
color: red;
}
.warning {
@extend .message;
border-color: yellow;
color: yellow;
}编译后,.success,.error,.warning都会继承,.message的样式减少重复代码。
函数
Sass内置了很多函数也可以自定义函数:
// 内置函数
$color: #007bff;
.lighten-color {
color: lighten($color, 20%); // 变亮20%
}
.darken-color {
color: darken($color, 20%); // 变暗20%
}
.opacity-color {
color: rgba($color, 0.5); // 设置透明度
}
// 自定义函数
@function calculate-width($columns, $gap) {
@return percentage($columns / 12) - $gap;
}
.col-6 {
width: calculate-width(6, 10px);
}导入
Sass支持把CSS分成多个文件用,@import导入:
// 主文件style.scss
@import "variables"; // 导入_variables.scss
@import "mixins"; // 导入_mixins.scss
@import "base"; // 导入_base.scss
@import "components"; // 导入_components.scss注意被导入的文件通常以下划线开头比如,_variables.scss这样Sass就不会单独编译这个文件。
条件判断和循环
Sass支持条件判断和循环:
// 条件判断
$theme: dark;
body {
@if $theme == dark {
background-color: #333;
color: #fff;
} @else {
background-color: #fff;
color: #333;
}
}
// for循环
@for $i from 1 through 12 {
.col-#{$i} {
width: percentage($i / 12);
}
}
// each循环
$colors: primary #007bff, success #28a745, danger #dc3545, warning #ffc107;
@each $name, $color in $colors {
.text-#{$name} {
color: $color;
}
.bg-#{$name} {
background-color: $color;
}
}
// while循环
$i: 1;
@while $i <= 5 {
.mt-#{$i} {
margin-top: $i * 4px;
}
$i: $i + 1;
}Less入门
Less的安装
Less是用JavaScript写的可以在浏览器端使用也可以在Node.js环境编译。
使用Node.js安装Less:
# 全局安装less
npm install -g less
# 查看版本
lessc --versionLess的编译
Less文件的扩展名是,.less。
编译Less文件:
# 编译单个文件
lessc input.less output.css
# 输出压缩后的CSS
lessc --clean-css input.less output.css也可以在浏览器端直接使用Less:
<link rel="stylesheet/less" type="text/css" href="styles.less" />
<script src="https://cdn.jsdelivr.net/npm/less@4"></script>不过不推荐在生产环境使用浏览器端编译应该提前编译成CSS。
Less的基本语法
Less的语法和Sass很像但是更接近原生CSS。
变量
Less用,@,符号定义变量:
// 定义颜色变量
@primary-color: #333;
@secondary-color: #666;
@accent-color: #007bff;
// 定义字体变量
@font-family: "Helvetica Neue", Arial, sans-serif;
@font-size-base: 16px;
// 使用变量
body {
font-family: @font-family;
font-size: @font-size-base;
color: @primary-color;
}
.button {
background-color: @accent-color;
}Less的变量还支持变量插值和变量变量:
// 变量插值
@property: color;
.box {
@{property}: #333;
}
// 变量变量
@fnord: "I am fnord.";
@var: "fnord";
.content {
content: @@var; // 输出 content: "I am fnord.";
}嵌套
Less也支持选择器嵌套:
.nav {
list-style: none;
li {
display: inline-block;
a {
color: #333;
text-decoration: none;
&:hover {
color: #007bff;
}
}
}
}和Sass一样,&,代表父选择器。
混合(Mixin)
Less的混合更简单直接用类名就可以作为混合:
// 定义混合
.border-radius(@radius: 5px) {
-webkit-border-radius: @radius;
-moz-border-radius: @radius;
border-radius: @radius;
}
// 使用混合
.box {
.border-radius(10px);
}
.button {
.border-radius(3px);
}Less也支持不带参数的混合直接把一个类的样式混入另一个,类:
.centered {
display: flex;
justify-content: center;
align-items: center;
}
.box {
.centered; // 混入.centered的样式
width: 100px;
height: 100px;
}Less也支持条件判断用when:
.mixin(@a) when (@a > 10) {
background-color: black;
}
.mixin(@a) when (@a <= 10) {
background-color: white;
}
.class1 {
.mixin(15); // background-color: black;
}
.class2 {
.mixin(5); // background-color: white;
}继承
Less用,&:extend(),实现继承:
.message {
padding: 10px;
border: 1px solid #ccc;
border-radius: 4px;
}
.success {
&:extend(.message);
border-color: green;
color: green;
}
.error {
&:extend(.message);
border-color: red;
color: red;
}函数
Less内置了很多函数:
@color: #007bff;
.lighten-color {
color: lighten(@color, 20%);
}
.darken-color {
color: darken(@color, 20%);
}
.opacity-color {
color: fade(@color, 50%);
}
.mix-color {
color: mix(@color, #fff, 50%);
}Less也支持自定义函数但是比较复杂需要用JavaScript或者Less的插件机制。
导入
Less用,@import导入文件:
@import "variables.less";
@import "mixins.less";
@import "base.less";Less的导入更灵活可以导入CSS文件也可以条件导入。
循环
Less本身不直接支持循环但是可以通过递归混合实现:
.generate-columns(@n, @i: 1) when (@i =< @n) {
.col-@{i} {
width: percentage(@i / @n);
}
.generate-columns(@n, (@i + 1));
}
.generate-columns(12);Sass和Less的对比
| 特性 | Sass | Less |
|---|---|---|
| 变量符号 | $ | @ |
| 混合定义 | @mixin | 直接定义 |
| 混合使用 | @include | 直接调用 |
| 继承 | @extend | &:extend() |
| 条件判断 | @if/@else | when |
| 循环 | @for/@each/@while | 递归混合 |
| 函数 | 支持自定义 | 内置函数丰富自定义复杂 |
| 语法 | SCSS接近CSS,Sass缩进 | 接近CSS |
| 生态 | 更成熟Compass等框架 | 也不错Bootstrap使用 |
| 学习成本 | 稍高 | 较低 |
总的来说Sass功能更强大生态更成熟适合大型项目;Less语法更简单学习成本更低适合小型项目和初学者。
实战:用Sass写一个响应式布局
下面我用一个简单的例子演示如何用Sass写一个响应式布局。
项目结构
project/
├── scss/
│ ├── _variables.scss # 变量
│ ├── _mixins.scss # 混合
│ ├── _base.scss # 基础样式
│ ├── _layout.scss # 布局样式
│ ├── _components.scss # 组件样式
│ └── style.scss # 主文件
└── css/
└── style.css # 编译后的CSS_variables.scss
// 颜色
$primary-color: #007bff;
$secondary-color: #6c757d;
$success-color: #28a745;
$danger-color: #dc3545;
$warning-color: #ffc107;
$info-color: #17a2b8;
$light-color: #f8f9fa;
$dark-color: #343a40;
// 文字颜色
$text-color: #333;
$text-color-light: #666;
$text-color-muted: #999;
// 背景颜色
$bg-color: #fff;
$bg-color-light: #f5f5f5;
// 字体
$font-family-sans: "Helvetica Neue", Arial, sans-serif;
$font-family-serif: Georgia, "Times New Roman", serif;
$font-family-mono: "Courier New", monospace;
$font-size-base: 16px;
$font-size-lg: 18px;
$font-size-sm: 14px;
$font-size-xs: 12px;
$line-height-base: 1.5;
// 间距
$spacing-xs: 4px;
$spacing-sm: 8px;
$spacing-md: 16px;
$spacing-lg: 24px;
$spacing-xl: 32px;
$spacing-xxl: 48px;
// 边框
$border-color: #dee2e6;
$border-radius: 4px;
$border-radius-lg: 8px;
// 断点
$breakpoint-sm: 576px;
$breakpoint-md: 768px;
$breakpoint-lg: 992px;
$breakpoint-xl: 1200px;
// 容器宽度
$container-max-width: 1200px;_mixins.scss
// 清除浮动
@mixin clearfix {
&::after {
content: "";
display: table;
clear: both;
}
}
// 圆角
@mixin border-radius($radius: $border-radius) {
-webkit-border-radius: $radius;
-moz-border-radius: $radius;
border-radius: $radius;
}
// 阴影
@mixin box-shadow($shadow...) {
-webkit-box-shadow: $shadow;
-moz-box-shadow: $shadow;
box-shadow: $shadow;
}
// 过渡
@mixin transition($transition...) {
-webkit-transition: $transition;
-moz-transition: $transition;
transition: $transition;
}
// 变换
@mixin transform($transform) {
-webkit-transform: $transform;
-moz-transform: $transform;
-ms-transform: $transform;
transform: $transform;
}
// 弹性布局居中
@mixin flex-center {
display: flex;
justify-content: center;
align-items: center;
}
// 文本截断
@mixin text-truncate {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
// 多行文本截断
@mixin text-clamp($lines: 2) {
display: -webkit-box;
-webkit-line-clamp: $lines;
-webkit-box-orient: vertical;
overflow: hidden;
}
// 响应式媒体查询
@mixin respond-to($breakpoint) {
@if $breakpoint == sm {
@media (min-width: $breakpoint-sm) {
@content;
}
} @else if $breakpoint == md {
@media (min-width: $breakpoint-md) {
@content;
}
} @else if $breakpoint == lg {
@media (min-width: $breakpoint-lg) {
@content;
}
} @else if $breakpoint == xl {
@media (min-width: $breakpoint-xl) {
@content;
}
}
}_base.scss
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
font-size: $font-size-base;
-webkit-text-size-adjust: 100%;
}
body {
font-family: $font-family-sans;
font-size: $font-size-base;
line-height: $line-height-base;
color: $text-color;
background-color: $bg-color;
}
a {
color: $primary-color;
text-decoration: none;
@include transition(color 0.3s ease);
&:hover {
color: darken($primary-color, 10%);
text-decoration: underline;
}
}
img {
max-width: 100%;
height: auto;
vertical-align: middle;
}
ul, ol {
list-style: none;
}
h1, h2, h3, h4, h5, h6 {
font-weight: 600;
line-height: 1.2;
margin-bottom: $spacing-md;
}
h1 { font-size: 2.5rem; }
h2 { font-size: 2rem; }
h3 { font-size: 1.75rem; }
h4 { font-size: 1.5rem; }
h5 { font-size: 1.25rem; }
h6 { font-size: 1rem; }
p {
margin-bottom: $spacing-md;
}_layout.scss
.container {
width: 100%;
max-width: $container-max-width;
margin: 0 auto;
padding: 0 $spacing-md;
}
.row {
@include clearfix;
margin: 0 (-$spacing-md / 2);
}
.col {
float: left;
padding: 0 ($spacing-md / 2);
width: 100%;
@include respond-to(md) {
&.col-6 { width: 50%; }
&.col-4 { width: 33.333333%; }
&.col-3 { width: 25%; }
&.col-8 { width: 66.666667%; }
&.col-9 { width: 75%; }
}
}
// 头部
.header {
background-color: $bg-color;
border-bottom: 1px solid $border-color;
padding: $spacing-md 0;
.header-inner {
@include clearfix;
}
.logo {
float: left;
font-size: $font-size-lg;
font-weight: 600;
color: $primary-color;
}
.nav {
float: right;
li {
display: inline-block;
margin-left: $spacing-lg;
a {
color: $text-color;
&:hover {
color: $primary-color;
}
}
}
}
}
// 主内容
.main {
padding: $spacing-xl 0;
}
// 侧边栏
.sidebar {
padding: $spacing-lg;
background-color: $bg-color-light;
@include border-radius;
}
// 底部
.footer {
background-color: $dark-color;
color: $light-color;
padding: $spacing-xl 0;
text-align: center;
a {
color: $light-color;
&:hover {
color: $primary-color;
}
}
}_components.scss
// 按钮
.button {
display: inline-block;
padding: $spacing-sm $spacing-md;
font-size: $font-size-sm;
font-weight: 500;
text-align: center;
vertical-align: middle;
cursor: pointer;
border: 1px solid transparent;
@include border-radius;
@include transition(all 0.3s ease);
&:hover {
text-decoration: none;
}
&.button-primary {
background-color: $primary-color;
color: #fff;
&:hover {
background-color: darken($primary-color, 10%);
}
}
&.button-secondary {
background-color: $secondary-color;
color: #fff;
&:hover {
background-color: darken($secondary-color, 10%);
}
}
&.button-outline {
background-color: transparent;
border-color: $primary-color;
color: $primary-color;
&:hover {
background-color: $primary-color;
color: #fff;
}
}
&.button-lg {
padding: $spacing-md $spacing-lg;
font-size: $font-size-base;
}
&.button-sm {
padding: $spacing-xs $spacing-sm;
font-size: $font-size-xs;
}
}
// 卡片
.card {
background-color: $bg-color;
border: 1px solid $border-color;
@include border-radius($border-radius-lg);
@include box-shadow(0 2px 4px rgba(0, 0, 0, 0.1));
overflow: hidden;
@include transition(box-shadow 0.3s ease);
&:hover {
@include box-shadow(0 4px 12px rgba(0, 0, 0, 0.15));
}
.card-header {
padding: $spacing-md $spacing-lg;
border-bottom: 1px solid $border-color;
background-color: $bg-color-light;
font-weight: 600;
}
.card-body {
padding: $spacing-lg;
}
.card-footer {
padding: $spacing-md $spacing-lg;
border-top: 1px solid $border-color;
background-color: $bg-color-light;
}
.card-title {
font-size: $font-size-lg;
font-weight: 600;
margin-bottom: $spacing-sm;
}
.card-text {
color: $text-color-light;
margin-bottom: 0;
@include text-clamp(3);
}
}
// 标签
.tag {
display: inline-block;
padding: 2px $spacing-sm;
font-size: $font-size-xs;
color: $text-color-light;
background-color: $bg-color-light;
@include border-radius;
margin-right: $spacing-xs;
margin-bottom: $spacing-xs;
&.tag-primary {
background-color: $primary-color;
color: #fff;
}
&.tag-success {
background-color: $success-color;
color: #fff;
}
&.tag-warning {
background-color: $warning-color;
color: $dark-color;
}
&.tag-danger {
background-color: $danger-color;
color: #fff;
}
}
// 分页
.pagination {
@include clearfix;
margin: $spacing-lg 0;
li {
display: inline-block;
margin-right: $spacing-xs;
a {
display: block;
padding: $spacing-xs $spacing-sm;
border: 1px solid $border-color;
@include border-radius;
color: $text-color;
@include transition(all 0.3s ease);
&:hover {
background-color: $primary-color;
color: #fff;
border-color: $primary-color;
}
}
&.active a {
background-color: $primary-color;
color: #fff;
border-color: $primary-color;
}
&.disabled a {
color: $text-color-muted;
cursor: not-allowed;
&:hover {
background-color: transparent;
color: $text-color-muted;
border-color: $border-color;
}
}
}
}style.scss
// 导入所有模块
@import "variables";
@import "mixins";
@import "base";
@import "layout";
@import "components";编译
sass --watch scss/style.scss:css/style.css --style compressed这样我们就用Sass写了一个完整的响应式布局的基础框架。代码结构清晰模块化易维护比原生CSS高效很多。
写在最后
CSS预处理器是前端开发的利器它能让我们写CSS更高效更优雅更易维护。不管是Sass还是Less都值得学习和使用。
这篇文章介绍了CSS预处理器的基本概念Sass和Less的基本语法以及一个实战例子。希望能帮到大家入门CSS预处理器。
当然CSS预处理器的内容还有很多比如Compass框架Sass的高级函数Less的插件等这篇文章只是入门介绍。如果大家想深入学习可以去看官方文档或者相关的书籍和教程。
最后记住:工具只是辅助关键还是在于写好CSS的思想和习惯。 即使用了CSS预处理器如果没有好的CSS架构和命名规范代码还是会很乱很难维护。
希望大家都能用好CSS预处理器写出优雅高效易维护的CSS。
如果大家有什么问题或者经验欢迎在评论区留言和我一起讨论。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录