CSS架构及Scss简单入门
一、架构的重要性
- 前期编程不重视
- 后期重构累秃头
二、为什么要做CSS架构
日益膨胀的CSS代码,无计可施
项目长期处于无CSS架构维护状态
- 导致的结果
css代码极度混乱
css难复用、难扩展、难维护
- 预期达到的目的
掌握各种CSS设计模式、解决难复用、难扩展等问题
搭建企业级css结构、解决代码混乱问题
三、CSS设计模式
3.1 OOCSS
oo
面向对象
3.1.1 原则
- 容器与内容分离
<!-- 容器与内容分离 -->
<!-- post中的meta-data -->
<div class="post">
<p class="metadata"><span>AAA</span><span>2022-01-01</span></p>
</div>
<!-- comment中的meta-data -->
<div class="comment">
<p class="metadata"><span>AAA</span><span>2022-01-01</span></p>
</div>
<!--
内容在不同容器中的展示是一致的 这样写css 会导致metadata不能进行复用
.post .metadata{ css code }
.comment .metadata{ css code }
优化成 => 容器写容器的代码 内容写内容的代码
.post {css code }
.comment {css code }
.metadata{ css code }
-->
- 结构(基础对象)与皮肤分离
<!-- 结构(基础对象)与皮肤分离 -->
<div class="menu fix fix1"></div>
<!--
不用修改基础对象 可以多次新增多个皮肤对象进行修改
.menu{
color: green;
font-size: 14px;
}
.fix{
color: red;
}
.fix1{
font-size: 24px;
}
-->
- 面向对象开发
vue中的组件 == oocss
页面中引入同一个组件多次,可以为每个组件新增不同的class,来实现每个组件的样式区别
3.1.2 总结
追求元件的复用,其class命名更为抽象,一般不体现具体的事物,而注重表现层的抽取
3.2 BEM
- B
块Block-
- E
元素Element__
- M
修饰Modifier--
3.2.1 作用
命名规范、让页面结构清晰,进阶版的OOCSS
<!-- BEM -->
<div class="menu">
<div class="menu__table menu__tab--style1">tab1</div>
<div class="menu__table menu__tab--style2">tab2</div>
<div class="menu__table menu__tab--style3">tab3</div>
<div class="menu__table menu__tab--style4">tab4</div>
</div>
3.3 SMACSS
3.3.1 分层
3.3.1.1 Base
- 对浏览器的默认样式进行重置
normalize.css
CSS Tools
这里的样式只会对标签元素本身做设定,不会出现任何
class
或id
,但是可以有属性选择器或是伪类
3.3.1.2 Layout
- 对页面布局的一些功能
元素是有层级级别之分的,Layout属于较高的一层,可以作为层级较低的如:Module元素的
容器
3.3.1.3 Module
- 公共的复用的一些小模块
- 样式模块化达到
复用
和可维护
的目的
3.3.1.4 State
- 不同状态下的一些效果
- 更强的复用性
任意元素在特定状态下的外观,如信息框可能有
success
和error
等状态
3.3.1.5 Theme
- 不同的一些皮肤
不要求使用单独的class命名,如可以在Module中定义
.header
,在Theme中也定义.header
来切换样式(换肤),后加载覆盖前加载的样式
3.3.2 命名规范
如:
- Layout
.l-header
.l-layout-header
- Module
.todoList
.todoList-title
.todoList-img
- State
.is-hidden
.is-active
- Theme
.theme-nav
.theme-header
3.3.3 总结
易维护、易复用、易扩展
3.4 ITCSS
3.4.1 分层
3.4.1.1 Settings
- 包含字体、颜色定义等,通常定义可以自定义模版的变量
3.4.1.2 Tools
-
mixin
、function
主要结合预处理器使用
3.4.1.3 Generic
- 对浏览器的默认样式进行重置
normalize.css
CSS Tools
3.4.1.4 Elements/Base
- 定义网站
HTML
元素的样式
3.4.1.5 Objects
- 类名样式中,不允许出现外观属性,例如:
Color
3.4.1.6 Components
- UI组件
3.4.1.7 Trumps/Utilities
- 实用程序和辅助类,能够覆盖三角形中的任何层,唯一写
important!
的地方
3.4.2 与SMCSS的区别
层次分得更细
3.5 ACSS
一个样式属性一个类
TailWind 框架
3.5.1 好处
- 极强的复用性、维护成本低
3.5.2 坏处
- 破坏了css命名的语义化
结合多个设计模式总结的常用层
四、整合设计模式
4.1 Settings层代码实现
- 定义一些公共的变量(某个样式经常出现)
- 颜色、边框、文字大小、阴影、层级......
- var.scss
/* Color */
// 基础颜色 不区分类别 服务于其他类型的所有颜色
$color-primary: #ff5777;
$color-white: #fff;
$color-black: #000;
// 字体颜色
$color-text-primary: #333;
$color-text-secondary: #666;
$color-text-tertiary: $color-white;
$color-text-quaternary: $color-primary;
// 边框颜色
$border-color-base: #e5e5d5;
// 背景颜色
$background-color-primary: #f1f1f1;
$background-color-secondary: $color-white;
$background-color-tertiary: $color-primary;
/* Border */
$border-width-base: 1px !default;
$border-style-base: solid !default;
$border-base: $border-width-base $border-style-base $border-color-base !default;
- 在vue.config.js中全局引入
// vue.config.js
module.exports = {
css: {
loaderOptions: {
// @/ 是 src/ 的别名
// 注意:在 sass-loader v8 中,这个选项名是 "prependData"
scss: {
additionalData: `@import "@/style/settings/var.scss";`
},
}
}
}
4.1 Tools层代码实现
4.1.1 SassMagic工具库
4.1.1.1 直接在github
下载至本地
4.1.1.2 将src内的文件复制进自己项目的tools文件夹内
- functions
- minxins
- _sassMagic.scss
注意:需要根据启动项目的提示去掉functions和minxins中未存在且在_sassMagic.scss中引入的文件
// Import Functions
@import "functions/_amcss.scss";
// @import "functions/_calc-percent.scss";
@import "functions/_convert.scss";
@import "functions/_decimal.scss";
@import "functions/_exponent.scss";
@import "functions/_leastSquaresFit.scss";
@import "functions/_linear-interpolation.scss";
@import "functions/_list-remove.scss";
@import "functions/_list-sort.scss";
@import "functions/_map-sort.scss";
@import "functions/_number.scss";
@import "functions/_polygon.scss";
@import "functions/_strip-units.scss";
@import "functions/_unit-length.scss";
@import "functions/_z-index.scss";
// Import Mixins
// @import "mixins/_alerts.scss";
@import "mixins/_amcss.scss";
@import "mixins/_angled-edges.scss";
@import "mixins/_animation.scss";
@import "mixins/_BEM.scss";
@import "mixins/_box-center.scss";
@import "mixins/_box-clamp.scss";
@import "mixins/_burger.scss";
// @import "mixins/_buttons.scss";
@import "mixins/_calc.scss";
@import "mixins/_caret.scss";
@import "mixins/_corners.scss";
@import "mixins/_equal-parts.scss";
@import "mixins/_fade-text.scss";
@import "mixins/_flex-grid.scss";
@import "mixins/_fluid-ratio.scss";
@import "mixins/_full-width.scss";
@import "mixins/_geometric-size.scss";
// @import "mixins/_gradient.scss";
@import "mixins/_haslines.scss";
@import "mixins/_HolyGrail-layout.scss";
@import "mixins/_media-queries.scss";
@import "mixins/_open-color.scss";
@import "mixins/_palettetown.scss";
@import "mixins/_plumber-box.scss";
@import "mixins/_plumber.scss";
@import "mixins/_poly-fluid-sizing.scss";
@import "mixins/_polygon.scss";
@import "mixins/_position.scss";
// @import "mixins/_resize.scss";
// @import "mixins/_ribbon.scss";
@import "mixins/_scrollbars.scss";
@import "mixins/_selector.scss";
@import "mixins/_sprite-spirit.scss";
@import "mixins/_sticky-footer.scss";
@import "mixins/_tilted.scss";
// @import "mixins/_triangle.scss";
@import "mixins/_typographic.scss";
// @import "mixins/_visuallyhidden.scss";
4.1.1.3 全局导入_sassMagic.scss
// vue.config.js
module.exports = {
css: {
loaderOptions: {
// @/ 是 src/ 的别名
// 注意:在 sass-loader v8 中,这个选项名是 "prependData"
scss: {
additionalData: `@import "@/style/tools/_sassMagic.scss";`
},
}
}
}
4.1.1.4 可以对SassMagic瘦身,根据项目定制化需要的功能
4.2 Base层代码实现
4.2.1 Generic层
- 引入
normalize.css
,重置浏览器默认样式
npm install --save normalize.css
main.js =>import "normalize.css/normalize.css"
4.2.2 Base层
对各类元素基础样式进行补充
根据当前自己的项目进行设计
- article.scss
- form.scss
- images.scss
- link.scss
- page.scss
- ...
统一导入在一个scss文件中,然后再main.js中引入
4.3 Components层代码实现
4.3.1 OOCSS => BEM (进阶版 OOCSS)
4.3.2 经典组件
4.3.2.1 栅格组件
配置按需使用vant
- 在components下进行配置(新建index.js)
import {
Col,
Row
} from 'vant';
const components = {
CCol: Col,
CRow: Row
}
const install = (app) => {
Object.keys(components).forEach(key => {
app.component(key, components[key])
});
}
const mgjUI = {
install
}
export default mgjUI
- 在main.js中引入
import mgjUI from '@/components/index.js'
createApp(App).use(mgjUI)
- 使用
这里的 c-row、c-col 是在 index.js 中进行了修改名称
<c-row>
<c-col span="8">span: 8</c-col>
<c-col span="8">span: 8</c-col>
<c-col span="8">span: 8</c-col>
</c-row>
4.3.2.2 布局组件
按照BEM的规范
component => layout
- layout
<template>
<section class="c-layout" :class="{ 'c-layout--horizontal': horizontal }">
<slot></slot>
</section>
</template>
<script>
export default {
name: "CLayout",
props: {
horizontal: {
type: Boolean,
default: false
}
}
}
</script>
<style lang="scss">
@include b(c-layout) {
display: flex;
flex-direction: column;
@include m(horizontal) {
flex-direction: row;
}
}
</style>
- header
<template>
<header class="c-header" :class="fixed && 'c-header--fixed'">
<slot></slot>
</header>
</template>
<script>
export default {
name: "CHeader",
props: {
fixed: {
type: Boolean,
default: false
}
}
}
</script>
<style lang="scss">
@include b(c-header) {
@include m(fixed) {
position: fixed;
top: 0;
width: 100%;
z-index: 10;
}
}
</style>
- content
<template>
<main class="c-content"><slot></slot></main>
</template>
<script>
export default {
name: "CContent"
}
</script>
<style lang="scss">
@include b(c-content) {
overflow: auto;
flex: 1;
}
</style>
- aside
<template>
<div class="c-aside">
<slot></slot>
</div>
</template>
<script>
export default {
name: "CAside"
}
</script>
<style lang="scss">
@include b(c-aside) {
overflow: auto;
flex-shrink: 0;
}
</style>
- footer
<template>
<footer class="c-footer">
<slot></slot>
</footer>
</template>
<script>
export default {
name: "cFooter"
}
</script>
<style lang="scss">
@include b(c-footer) {
position: fixed;
bottom: 0;
width: 100%;
z-index: 10;
}
</style>
- 引入(统计新增index.js)
import Layout from "./layout.vue"
import Header from "./header.vue"
import Content from "./content.vue"
import Footer from "./footer.vue"
import Aside from "./aside.vue"
export {
Layout,
Header,
Content,
Footer,
Aside
}
- 优化components下的index.js
import {
Col,
Row
} from 'vant';
import {
Layout,
Header,
Content,
Footer,
Aside
} from './layout';
const components = {
CCol: Col,
CRow: Row,
Layout,
Header,
Content,
Footer,
Aside
}
const install = (app) => {
Object.keys(components).forEach(key => {
// 使用第三方组件
if (key === 'CRow' || key === 'CCol') {
app.component(key, components[key])
} else {
// 第一个参数获取当前vue中的name 赋值给组件的key
app.component(components[key]['name'], components[key])
}
});
}
const mgjUI = {
install
}
export default mgjUI
- 使用
<template>
<!-- <c-layout class="home__layout">
<c-header style="background: #ff5777">header</c-header>
<c-content style="background: #ff0">
<div style="height: 2000px">123123</div>
</c-content>
<c-footer style="background: #666">footer</c-footer>
</c-layout> -->
<c-layout horizontal class="home__layout">
<c-aside style="background: #ff5777">123</c-aside>
<c-content style="background: #ff0">
<div style="height: 2000px">123123</div>
</c-content>
</c-layout>
</template>
<script>
export default {
name: 'Home'
}
</script>
<style lang="scss">
@include b(home) {
@include e(layout) {
height: 100vh;
}
}
</style>
4.3.3 自定义组件
4.4 Acss层代码实现
- 让样式极限复用
- 解决Acss无语义化缺点:属性选择器
<div class="c-layout" fl p10></div>
[fl]{
float: left;
}
[p10]{
padding:10px;
}
- Settings 与 Acss 层的关系
大多数基于settings中的var.scss中进行属性选择器的封装
4.5 Theme层代码实现
在html标签上新增一个属性,然后通过js改变这个属性实现换肤功能,(在属性下针对页面的class进行颜色大小等元素的修改即可)
4.6 两种不同的引入方式的区别
4.6.1 在vue.config.js
中引入
- 相当于在任何scss和vue(style)的文件内都引入了配置的scss
- vue.config.js
module.exports = {
css: {
loaderOptions: {
scss: {
prependData: `
@import "@/style/settings/var.scss";
@import "@/style/tools/_sassMagic.scss";
`
},
}
}
}
xxx.scss
@import "@/style/settings/var.scss";
@import "@/style/tools/_sassMagic.scss";
.a{}
xxx.vue
<style lang="scss">
@import "@/style/settings/var.scss";
@import "@/style/tools/_sassMagic.scss";
.a{}
</style>
- 变量、minxins、function...
4.6.2 在main.js
中引入
纯样式
五、响应式布局
5.1 什么是响应式布局
网页的元素会随着屏幕大小的变化而变化
5.2 方案
5.2.1 REM
- 安装
npm install lib-flexible
main.js中导入
import 'lib-flexible/flexible.js'
- 安装
npm install postcss-plugin-px2rem -D
配置 vue.config.js
module.exports = {
css: {
loaderOptions: {
postcss: {
plugins: [
require('postcss-plugin-px2rem')({
rootValue: 37.5,
exclude: /(node_module)/,
minPixelValue: 3,
selectorBlackList: ['van']
})
]
},
}
}
}
- 正常编写css即可,不需要转换为rem的可以将
px
单位首字母大写Px
5.2.2 VW
5.2.3 REM+VW
六、SvgIcon多色图标
6.1 有什么优势?
- Svg 支持多色图标
- Svg 可以控制图标不同部分、加入动画
- Svg 是矢量图标、图标锐利、体积更小
6.2 IconPark
- install
npm install @icon-park/vue-next --save
- 使用
<template>
<home theme="filled"/>
</template>
<script>
import {Home} from '@icon-park/vue-next';
export default {
components: {
Home
}
}
</script>
七、Css中文字体压缩: 字蛛(font-spider)
八、Css Scroll Snap 优化滚动(移动端)
九、border-radius 原理及实现复杂图形
9.1 水平上的半径 / 垂直上的半径
9.2 简写
- 一个值全对其
border-radius: 5px;
=>border-radius: 5px 5px 5px 5px / 5px 5px 5px 5px;
- 奇对奇补齐、偶对偶补齐
border-radius: 5px 10px;
=>border-radius: 5px 10px 5px 10px / 5px 10px 5px 10px;
border-radius: 5px 10px 15px;
=>border-radius: 5px 10px 15px 10px / 5px 10px 15px 10px;
- 百分比
先补齐,相当于盒子的宽度和高度来计算
border-radius: 10%; 假设:width = 600px ; height = 300px;
=>
border-radius: 10% 10% 10% 10% / 10% 10% 10% 10%;
border-radius: 60px 60px 60px 60px / 30px 30px 30px 30px;
9.3 示例
十、Scss
10.1 Sacc和Scss的区别
- 文件扩展名不同
sass是以.sass后缀为扩展名
scss是以.scss后缀为扩展名
- 语法不同
sass是以严格的缩进式语法规则来书
scss的语法以css语法非常相似
10.2 特色功能
- 完全兼容css3
- 在css基础上增加了
变量(variables)
嵌套(nesting)
混合(mixins)
等
- 通过函数进行颜色值与属性值的运算
- 提供控制指令等高级功能
- 自定义输出形式
10.3 css功能扩展
10.3.1 嵌套规则
.home {
height: 100px;
.redbox {
background-color: red;
}
}
10.3.2 父类选择器
.home {
height: 100px;
background: #000;
&:hover {
height: 200px;
}
}
扩展
.home {
height: 100px;
background: #000;
&-red {
color: red;
}
}
// ==
.home {
height: 100px;
background: #000;
}
.home-red {
color: red;
}
10.3.3 属性嵌套
.home {
height: 100px;
background: #000;
color: red;
font: {
size: 24px;
weight: 400;
}
}
// ==
.home {
height: 100px;
background: #000;
color: red;
font-size: 24px;
font-weight: 400;
}
10.3.4 变量
.home {
height: 100px;
background: #000;
&-red {
$homeColor: red !global;
color: $homeColor;
}
&-red-new {
color: $homeColor;
}
}
!global
将局部变量转换为当前页面的全局变量
10.3.5 数据类型
- 数字
1,2,13,10px
- 字符串
"foo","bus","bar"
foo,bus,bar
有引号字符串与无引号字符串
在编译css文件时不会改变其类型
使用 #{} 时除外,有引号字符串将被编译为无引号字符串,这样便于mixin中引用选择器名
@mixin homePage($name) {
.home #{$name} {
font: {
size: 40px;
}
}
}
@include homePage(".home-red-new");
// ==
.home .home-red-new {
font-size: 40px;
}
- 颜色
blue,#ff000,rgba(255,255,255,0)
- 布尔值
true,false
- 空值
null
- 数组
1em 0 2em 10em
1em,Arial,Hellow
用空格或逗号作分隔符
- maps
(key1: value1, key2: value2)
相当于javascript的 object
10.3.6 运算
10.3.6.1 数字运算
- 加减乘除
$home-width: 600px;
.home {
height: 100px + 1px;
width: 100px - 50px;
width: 200px * 2;
width: (300px/2);
width: $home-width/2;
}
“除”需要用括号包裹或者直接用变量相除
10.3.6.2 颜色值运算
10.3.6.3 字符串运算
- 有引号字符串位于+左侧连接无引号字符串,运算结果是有引号字符串,无引号字符串位于+左侧连接有引号字符串,运算结果为无引号字符串
.home {
&::before {
content: "Foo " + Bar;
font: {
family: sans- + "serif";
}
}
}
.home::before {
content: "Foo Bar";
font-family: sans-serif;
}
- 运算表达式与其他值连用时,用空格做连接符
.home {
margin: 100px + 3px auto;
}
- 在有引号的文本字符串中使用
#{}
插值语句可以添加动态的值
.home {
&::before {
content: "1+1= #{1+1}";
}
&::before {
content: "1+1= 2";
}
}
- 空的值被视作插入了空字符串
.home {
&::before {
content: "1+1=#{$value}?";
}
&::before {
content: "1+1=?";
}
}
- 支持布尔 and or not
- 数组不支持任何运算方式,只能使用 list functions 控制
所有的数据类型均支持相等运算 == 或 !==
10.3.6.4 圆括号
- 圆括号可以用来影响运算顺序
.home {
height: 100px * (1+1);
}
// ==
.home {
height: 200px;
}
10.3.7 函数
@function grid-width($n) {
@return $n * 100px;
}
.home {
width: grid-width(4);
}
10.3.7.1 关键词参数
- 虽然不够简明,但阅读起来会更加方便
- 可以打乱顺序使用,并且可以使用默认参数的默认值
@mixin bordered($color, $width: 2px) {
border: $width solid $color;
}
.home {
@include bordered($width: 10px, $color: red);
}
10.3.7.2 变量参数
@mixin bordered($color, $width: 2px) {
border: $width solid $color;
}
$colorValues: 10px yellow;
.home {
@include bordered($colorValues...);
}