This article will talk about the 5 design patterns in CSS, and introduce the code functions in the CSS style directory in the vue3 project. I hope it will be helpful to everyone!
After working for several years, I found that the following problems often exist in projects:
Because of these bad programming habits, projects have become increasingly difficult to maintain and program performance has become lower and lower, greatly reducing daily work efficiency and increasing the company's development costs.
The following will take the CSS architecture in the Vue3 project as an entry point to improve our programming capabilities and project architecture capabilities by reducing the redundancy of CSS code and enhancing the maintainability and scalability of CSS code.
Technical reserves:
Before learning the CSS architecture, let’s take a brief look at the five common CSS design patterns. These design patterns are Our CSS architecture provides certain development ideas.
OOCSS (Object-Oriented CSS) literally means object-oriented CSS, and it has the following specifications during development
# 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>
BEM is an advanced version of OOCSS, a layered system that divides our website into three layers. These three layers correspond to the abbreviations of the three English words BEM: block, element, Modifier is divided into block layer, element layer and modifier layer.
To embody BEM into code, we need to follow three principles:
<div class="menu"> <div class="menu__tab menu__tab--style1">tab1</div> <div class="menu__tab menu__tab--style1">tab2</div> </div>
However, due to the two underscores __ and two dashes - it is not so smooth in actual development and affects development efficiency. However, if the CSS naming convention must be strictly controlled, this is undoubtedly a problem. Good choice. And when writing CSS, we can encapsulate a BEM.scss file through Sass’s mixed instructions to reduce the input of class names and enhance the CSS structure
BEM's simple three-layer classification method has no problem in dealing with small and medium-sized websites, but it may be more difficult to deal with the styles of complex websites. We need to find a better way.
SMACSS (Scalable and Modular Architecture for CSS) is about writing modular, structured and extensible CSS. It divides the CSS in the project into five categories
ITCSS (Inverted Triangle Cascading Style Sheets) can be translated as"Inverted Triangle CSS"
, which divides the styles in our project into seven layers based on the concept of layering
ACSS (Atomic CSS) is translated as "Atomic CSS"
is a CSS architecture method that favors small and single-purpose classes and is named after visual effects. It is a WYSIWYG language that does not emphasize logic but focuses more on performance. The background of its emergence is the arrival of the era of front-end componentization. The CSS of each component can be independent of each other and do not affect each other. Therefore, such code appears
<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">按钮</button>
The more mature ACSS libraries currently on the market include: Tailwind CSS and Windi CSS
Advantages of ACSS
ACSS的缺点
综上,我们可以看出ACSS 劣处是非常小的,而好处有非常大,没有理由在项目中不适用。下面我们通过使用BEM、ITCSS和ACSS模式打造一套CSS架构方案。
npm i sass@1.26.5 sass-loader@8.0.2 --save
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(函数)的区别
/* 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 '[am-' + $module + ']'; } @else { @return '[am-' + $module + '~="' + $trait + '"]'; } }
2.关于style/global.scss和style/index.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)}; } }
// 根目录下:vue.config.js module.exports = { css: { loaderOptions: { scss: { // @/ 是 src/ 的别名 // 注意:在 sass-loader v8 中,这个选项名是 "prependData" prependData: `@import "@/style/global.scss";` }, } } }
// src/main.js import { createApp } from 'vue' import App from './App.vue' import router from './router' import './style/index.scss' createApp(App).use(router).mount('#app')
下面简单分析和演示下各个style目录中的代码作用。
该目录主要是定义一些简单的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>
该目录主要是重置项目中一些元素的默认样式,比如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; }
该目录是定义全局的、项目统一规范的文本颜色、边框颜色等变量
/* 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;
该目录定义项目各个主题下相关模块的样式
/* style/theme/default.scss */ [data-theme='default'] .header { background: #FF5777; } [data-theme='default'] .footer { color: #FF5777; border: 2px solid #FF5777;; } /* style/theme/cool.scss */ [data-theme='cool'] .header { background: #409EFF; } [data-theme='cool'] .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('default')"></div> <div class="set set--cool" @click="changeTheme('cool')"></div> </div> <div class="footer"></div> </div> </template> <script> export default { name: "Theme", setup() { const changeTheme = (theme = 'default') => { 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>
该目录是定义一些全局的公共mixin和function,目前这块内容比较完善就是SassMagic,感兴趣的可以点进来看一下。下面简单看一下BEM模式的应用
$elementSeparator: '__'; $modifierSeparator: '--'; // 判断`$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视频教程)
The above is the detailed content of Briefly analyze the 5 design patterns in CSS and talk about the role of CSS directory code in the vue project. For more information, please follow other related articles on the PHP Chinese website!