首頁  >  文章  >  web前端  >  淺析CSS中的5種設計模式,聊聊vue專案中CSS目錄程式碼的作用

淺析CSS中的5種設計模式,聊聊vue專案中CSS目錄程式碼的作用

青灯夜游
青灯夜游轉載
2022-02-08 10:30:492873瀏覽

這篇文章帶大家聊聊CSS中的5種設計模式,並介紹一下vue3專案中個CSS style目錄中的程式碼作用,希望對大家有幫助!

淺析CSS中的5種設計模式,聊聊vue專案中CSS目錄程式碼的作用

工作了幾年,發現在專案中經常存在以下問題:

  • 1.模組分割不合理
  • 2.變數和函數命名不知所雲
  • 3.缺少註解或是寫了一堆描述不清的內容
  • 4.重複的程式碼遍布各個角落等

因為這些不良的程式設計習慣,導致了專案越來越難以維護,程式效能越來越低,大大降低了日常的工作效率以及提高了公司的開發成本。

下面就以CSS在Vue3專案中的架構為切入點,透過減少CSS程式碼的冗餘度和增強CSS程式碼的維護性、擴展性來提高我們的程式設計能力和專案架構能力。

技術儲備:

  • Sass(https://www.sass.hk/docs/)
  • Vue3(https://v3.cn.vuejs .org/)

CSS的設計模式

在學習CSS架構之前,我們先簡單看一下常見的5種CSS設計模式,這些設計模式都為我們的CSS架構提供了一定的開發思路。

1.OOCSS模式

OOCSS(Object-Oriented CSS)字面意思是物件導向的CSS,在開發中它有如下的規範約定

  • 減少對HTML 結構的依賴
# bad
# 1.匹配效率低,影响css性能
# 2.和html耦合度高,维护性和扩展性低
.container-list ul li a {}

<div class="container-list">
  <ul>
    <li>
      <a>...</a>
    </li>
  </ul>
</div>


# good
.container-list .list-item {}

<div class="container-list">
  <ul>
    <li>
      <a class="list-item">...</a>
    </li>
  </ul>
</div>
  • #增加樣式的重複使用性
.label {
  # 公共代码
}
.label-danger {
  # 特定代码
}
.label-info {
  # 特定代码
}
<div>
  <p class="label label-danger"></p>
  <p class="label label-info"></p>
</div>

2.BEM模式

BEM 是進階版的OOCSS,是一個分層系統,它把我們的網站分成三層,這三層正好對應著BEM 三個英文單字的簡寫block, element, modifier,分為為區塊層、元素層、修飾符層。

把BEM 體現到程式碼上,我們需要遵循三個原則:

  • 使用__兩個底線將區塊名稱與元素名稱分開
  • #使用- -兩個破折號分隔元素名稱及其修飾符
  • 一切樣式都是一個類,不能嵌套。
<div class="menu">
  <div class="menu__tab menu__tab--style1">tab1</div>
  <div class="menu__tab menu__tab--style1">tab2</div>
</div>

但是,由於兩個底線__和兩個破折號--在實際開發中不是那麼的順手,影響開發效率,不過要嚴格控制CSS命名規範的話,這無疑是一個好的選擇。並且在寫CSS的時候我們可以透過Sass的混合指令封裝一個BEM.scss檔來減少類別名稱的輸入以及增強CSS結構

3.SMACSS模式

BEM 簡單的三層分法,在處理小中型網站沒有問題,但是去應對複雜網站的樣式可能就比較困難了,我們需要尋求一個更好的辦法。

SMACSS(Scalable and Modular Architecture for CSS)是要寫模組化、結構化和可擴充的 CSS。它對專案中的CSS分為五大類

  • Base: 預設屬性樣式重置,知名庫為normalize.css
  • Layout:佈局樣式
  • Modules :可重複使用模組的樣式,例如一些清單展示
  • State:狀態樣式,例如按鈕的置灰或高亮的展示
  • Theme:皮膚樣式,例如有些網站具有換膚的功能

4.ITCSS模式

ITCSS(Inverted Triangle Cascading Style Sheets)可以翻譯為"倒三角CSS",它基於分層的概念把我們項目中的樣式分為七層

  • Settings: 項目樣式變量,如主題色、字體等
  • Tools:工具類樣式,例如定義函數,表示字數過多出現省略號等
  • Generic:重置和/或標準化樣式、框大小定義等,對應的是normalize.css
  • Base:重置瀏覽器元素屬性預設值
  • Objects:維護OOCSS的樣式
  • Components:公共元件樣式
  • Trumps:讓樣式權重變得最高,實用程式和輔助類,能夠覆蓋三角形中前面的任何內容,唯一important!的地方

#5.ACSS模式

ACSS(Atomic CSS)翻譯為"原子化CSS",是一種CSS 的架構方式,它傾向於小巧且用途單一的class,並且會以視覺效果命名。是一個不強調邏輯,而更著重表現的一門所見即所得的語言,它出現的背景是──前端組件化時代的到來,各個組件的CSS可以做到互相獨立,互不影響。因此就有這樣的程式碼出現

<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">按钮</button>

目前市面上比較成熟的ACSS函式庫有:Tailwind CSSWindi CSS

ACSS的優點

  • CSS文件停止增长:使用传统方法,每次添加新功能时,您的 CSS 文件都会变大。使用实用程序,一切都是可重用的,因此您很少需要编写新的 CSS,一套样式全局通用。
  • 不再浪费精力命名,不再添加愚蠢的类名:例如 sidebar-inner-wrapper 只是为了能够设置样式,也不再为真正只是一个 flex 容器的东西的完美抽象名称而苦恼。
  • 灵活,易读:CSS 是全球性的,当你做出改变时,你永远不知道你破坏了什么。HTML 中的类是本地的,因此可以 插拔式改变样式 而不必担心其他问题,CSS 样式很多缩写更加符合大脑的记忆。
  • 永远不用担心命名冲突,永远不用担心样式覆盖。

ACSS的缺点

  • 会增加HTML 的体积
  • 破坏了CSS命名的语义化
  • 熟悉命名 ACSS 命名会有一定成本

综上,我们可以看出ACSS 劣处是非常小的,而好处有非常大,没有理由在项目中不适用。下面我们通过使用BEM、ITCSS和ACSS模式打造一套CSS架构方案。

项目搭建

创建vue3项目和安装依赖

  • 1.创建vue3项目
  • 2.安装:npm i sass@1.26.5 sass-loader@8.0.2 --save

CSS目录结构展示与说明

src
  style
    acss         # 存放boder、margin、padding等基于acss模式的代码
    base         # 存放元素(input、p、h1等)的重置样式
    settings     # 存放项目统一规范的文本颜色、边框颜色等变量
    theme        # 存放项目特定主题下的元素样式
    tools        # 存放封装好的mixin(混合指令)和function(函数)样式
    global.scss  # 需要项目全局引用的CSS
    index.scss   # 需要Vue文件引用的CSS

1.关于mixin(混合指令)和function(函数)的区别

  • 函数是有计算逻辑,返回计算的结果,不输出css块
  • mixin主要是根据计算结果输出css块
/* mixin */
@mixin center-translate($direction: both) {
  position: absolute;
  @if $direction == both {
    top: 50%;
    left: 50%;
    transform: translate3d(-50%, -50%, 0);
  } @else if $direction == horizontal {
    left: 50%;
    transform: translate3d(-50%, 0, 0);
  } @else if $direction == vertical {
    top: 50%;
    transform: translate3d(0, -50%, 0);
  }
}

/* function */
@function am($module, $trait: false) {
  @if $trait==false {
    @return &#39;[am-&#39; + $module + &#39;]&#39;;
  } @else {
    @return &#39;[am-&#39; + $module + &#39;~="&#39; + $trait + &#39;"]&#39;;
  }
}

2.关于style/global.scss和style/index.scss

  • global.scss中导入的代码不仅在Vue文件中使用,而且在style中scss定义文件里也会被引用到
# style/global.scss
@import "./settings/var.scss";

# style/settings/var.scss
$background-color-primary: #F1F1F1;
$background-color-secondary: $color-white;

# style/acss/color.scss
@each $style in (primary $background-color-primary, secondary $background-color-secondary) {
  [bg-#{nth($style, 1)}] {
    background-color: #{nth($style, 2)};
  }
}
  • 全局引入style/global.scss
// 根目录下:vue.config.js
module.exports = {
  css: {
    loaderOptions: {
      scss: {
        // @/ 是 src/ 的别名
        // 注意:在 sass-loader v8 中,这个选项名是 "prependData"
        prependData: `@import "@/style/global.scss";`
      },
    }
  }
}
  • style/index.scss定义的代码只是不被style中其他css文件引用到而已,其他的都和global.scss一致
  • 引入style/index.scss
// src/main.js
import { createApp } from &#39;vue&#39;
import App from &#39;./App.vue&#39;
import router from &#39;./router&#39;
import &#39;./style/index.scss&#39;

createApp(App).use(router).mount(&#39;#app&#39;)

下面简单分析和演示下各个style目录中的代码作用。

1.acss

该目录主要是定义一些简单的border、color、font-size、margin和padding等代码

/* style/acss/border.scss */
@for $i from 1 through 100 {
  [radius#{$i}] { 
    border-radius: #{$i}Px;
    overflow: hidden;
  }
}
[circle] {
  border-radius: 50%;
}

/* style/acss/font-size.scss */
@for $i from 12 through 30 {
  [fz#{$i}] { 
    font-size: #{$i}px;
  }
}

使用acss代码

<div class="container">
  <div class="item" radius20>border-radius: 20px;</div>
</div>
<div class="container">
  <div class="item" circle>border-radius: 50%;</div>
</div>
<div class="container">
  <div class="item" fz30>font-size: 30px;</div>
</div>

2.base

该目录主要是重置项目中一些元素的默认样式,比如input、hn、p、a等元素

/* style/base/form.scss */
input {
  padding: 0;
  outline: none;
  border: none;
}

/* style/base/link.scss */
a {
  color: #ccc;
  text-decoration: none;
}

3.settings

该目录是定义全局的、项目统一规范的文本颜色、边框颜色等变量

/* style/settings/var.scss */
/* 主题色调 */
$color-primary: #FF5777;
$color-white: #FFFFFF;

/* 文本色调 */
$color-text-primary: green;
$color-text-secondary: #FF4533;
$color-text-tertiary: $color-white;
$color-text-quaternary: $color-primary;

/* 盒子边框色调 */
$border-color-base: #E5E5E5;

/* 盒子背景色色调 */
$background-color-primary: #F1F1F1;
$background-color-secondary: $color-white;
$background-color-tertiary: $color-primary;


/* 盒子默认边框 */
$border-width-base: 1Px !default;
$border-style-base: solid !default;
$border-base: $border-width-base $border-style-base $border-color-base !default;

4.theme

该目录定义项目各个主题下相关模块的样式

/* style/theme/default.scss */
[data-theme=&#39;default&#39;] .header {
  background: #FF5777;
}
[data-theme=&#39;default&#39;] .footer {
  color: #FF5777;
  border: 2px solid #FF5777;;
}

/* style/theme/cool.scss */
[data-theme=&#39;cool&#39;] .header {
  background: #409EFF;
}
[data-theme=&#39;cool&#39;] .footer {
  color: #409EFF;
  border: 2px solid #409EFF;;
}

我们通过添加html元素上的data-theme属性和值,即可达到项目主题的变换

<!-- Theme.vue -->
<template>
  <div class="theme">
    <div class="header"></div>
    <div class="theme__set">
      <div class="set set--default" @click="changeTheme(&#39;default&#39;)"></div>
      <div class="set set--cool" @click="changeTheme(&#39;cool&#39;)"></div>
    </div>
    <div class="footer"></div>
  </div>
</template>

<script>
export default {
  name: "Theme",
  setup() {
    const changeTheme = (theme = &#39;default&#39;) => {
      window.document.documentElement.setAttribute("data-theme", theme);
    }
    return {
      changeTheme
    }
  }
}
</script>


<!-- Other.vue -->
<template>
  <div class="about">
    <div class="header"></div>
    <div class="about-title">This is an about page title</div>
    <div class="about-content">This is an about page content</div>
    <div class="footer"></div>
  </div>
</template>

5.tools

该目录是定义一些全局的公共mixin和function,目前这块内容比较完善就是SassMagic,感兴趣的可以点进来看一下。下面简单看一下BEM模式的应用

$elementSeparator: &#39;__&#39;;
$modifierSeparator: &#39;--&#39;;

// 判断`$selector`中是否包含BEM中Modify
@function containsModifier($selector) {
  $selector: selectorToString($selector);
  @if str-index($selector, $modifierSeparator) {
    @return true;
  } @else {
    @return false;
  }
}

// 将`$selector`转换成String
@function selectorToString($selector) {
  $selector: inspect($selector); //cast to string
  $selector: str-slice($selector, 2, -2); //remove brackets
  @return $selector;
}

// @param  {String}  $selector
@function getBlock($selector) {
  $selector: selectorToString($selector);
  $modifierStart: str-index($selector, $modifierSeparator) - 1;
  @return str-slice($selector, 0, $modifierStart);
}

@mixin b($block) {
  .#{$block} {
    @content;
  }
}

@mixin e($element) {
  $selector: &;
  @if containsModifier($selector) {
    $block: getBlock($selector);
    @at-root {
      #{$selector} {
        #{$block + $elementSeparator + $element} {
          @content;
        }
      }
    }
  } @else {
    @at-root {
      #{$selector + $elementSeparator + $element} {
        @content;
      }
    }
  }
}

@mixin m($modifier) {
  @at-root {
    #{&}#{$modifierSeparator + $modifier} {
      @content;
    }
  }
}

// @param {string} $block - BEM中的Block
// <div class="block">
//   <div class="block__header">
//     <div class="block__header--css"></div>
//   </div>
// </div>

//  @include b(block) {
//    background: red;
//    @include e(header){
//       font-size: 14px;
//       @include m(css) {
//         font-size: 18px;
//      }
//   };
// }

// 编译后
// .block {
//   background: red;
// }
// .block__header {
//   font-size: 14px;
// }
// .block__header--css {
//   font-size: 18px;
// }

尾声

暂时先讲这么多,更多内容可以关注下这个仓库vue3-css-architecture,会持续更新完善,补充更多的mixin、function,以及在项目中的应用。

(学习视频分享:css视频教程

以上是淺析CSS中的5種設計模式,聊聊vue專案中CSS目錄程式碼的作用的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:juejin.cn。如有侵權,請聯絡admin@php.cn刪除