CSS架构及Scss简单入门

github项目地址

一、架构的重要性

  • 前期编程不重视
  • 后期重构累秃头

二、为什么要做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

这里的样式只会对标签元素本身做设定,不会出现任何classid,但是可以有属性选择器或是伪类

3.3.1.2 Layout
  • 对页面布局的一些功能

元素是有层级级别之分的,Layout属于较高的一层,可以作为层级较低的如:Module元素的容器

3.3.1.3 Module
  • 公共的复用的一些小模块
  • 样式模块化达到 复用可维护 的目的
3.3.1.4 State
  • 不同状态下的一些效果
  • 更强的复用性

任意元素在特定状态下的外观,如信息框可能有successerror等状态

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
  • mixinfunction 主要结合预处理器使用
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工具库

git
文档

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...);
}

十一、XMind

css架构.png

本文章由javascript技术分享原创和收集

发表评论 (审核通过后显示评论):