模块化面向对象的css写法规范策略。适用于大中小型C端项目样式开发,旨在提高开发和维护效率。
MIT License
以样式自动化为目标,模块化面向对象的css写法规则策略Moo-CSS, 以及通用Base层样式库moo-css-base。Moo-CSS文档地址>>, English introduce>>,Moo-CSS生态(建设中)>>
主要目录结构:
Moo-CSS
├─moo-css-base
│ ├─less // less base
│ ├─sass // sass base
│ └─stylus // stylus base
├─docs // documents
└─demo // demos
css代码/moo-css选择器的相互转换
虚拟dom -> 符合moo-css规范的web代码
虚拟dom -> 符合moo-css规范的小程序代码
sketch -> web/weapp
Moo-CSS中的M(Module),模块化。Moo-CSS的模块化主要体现在样式属性的模块化以及样式层级的模块化。
根据样式属性的特征,Moo-CSS将样式属性分类样式划分为以下模块,并根据模块特征给定命名前缀(命名规则-标志前缀):
另外两种特殊模块:
更多样式属性归类可参考样式模块词典>>
注意,Moo-CSS推荐其中 grid, module, unit, component, status, animation通常由className实现; skin通常由属性(attribute)实现,*小程序通过className实现; function大部分由className实现,部分低权重样式由属性实现。
使用className以及attribute来确认样式可以较好避免权重问题,且从中我们可以得知skin作为辅助样式而样式权重相比较低。Moo-CSS推荐避免ID以及!important进行样式开发,有且仅有一个!important样式用于元素隐藏(
.z-hide { display: none !important }
)。
根据样式属性的特征,将项目样式分层为以下模块层级:
其中,Base、Component、Skin、Layout中样式作用域为全局,Module层样式保持私有性。各层级保持独立性,满足SRP(单一功能原则)。
详细介绍可见文档-样式分层
权重计算参考公式:
1 / (样式资源量 / 样式属性耦合度 * 0.4 + 0.3 / 样式使用率 ^ 2 + 选择器权重 * 0.3)
数值越大权重越高,高权重可归入Base层。
其中,样式资源量可由样式代码量和引入资源大小进行衡量;样式属性耦合度是指在多样式属性的样式中,属性直接的耦合度,如溢出显示'...'这样的耦合度就非常高;样式使用率主要考虑多页面(包括路由页面)的样式使用率;选择器权重计算值越小越好。权重公式仅做参考,简单来说就是提取高频使用且不占用大量资源的原子样式/方法。
Moo-CSS中的OO(Object-Oriented),面向对象。Moo-CSS的面向对象主要体现在Component和Module层。
同OOCSS,Moo-CSS中的CSS对象由以下4部分内容组成:
分离结构和皮肤意味着要将重复的样式特征(如背景和边框等样式)定义为单独的“皮肤”,通过和其他各种CSS“对象”的混合及匹配,使得在没有太多代码的情况下实现大量的视觉变化。
比如说一个渐变按钮,那么 .btn 的 class 是不会包含渐变相关的属性的,而是需要单独抽取出一个渐变的 class,然后让 .btn 去扩展从而得到一个渐变的按钮。
区分容器和内容意味着将很少使用位置相关的样式,一个CSS“对象”应该不管放到哪里看起来都一样。所以不要用.myObject h2{ ... }
来设置特定的<h2>
样式,而是应该创建并应用一个描述与<h2>
相关的class,如<h2 class="category">
。
总得来说,就是满足SRP(单一职责)、OCP(开放封闭)
Moo-CSS的封装特性一方面体现在Module/Component中对象内容的封装,保持对象之间的独立性; 另一方面,各样式属性/方法的封装以及各样式层级的封装均体现了其封闭性。
页面Module层/Component层可由其他Component层进行样式继承和拓展,各模块符合开闭原则(The Open/Closed Principle)
Moo-CSS所说的多态一方面是指对应平台的多态样式/方法。比如moo-css-base移动端和PC端的Component层分别提供了rem换算方法torem
,调用方式相同而移动端进行了1:75的单位换算,而PC端进行了1:54的单位换算。
选择器命名由小写字母,_
、-
符号组成,并通过标志前缀来确定样式命名空间。
className或attribute的写法为:
prefix-className/attribute_字母值
或
prefix-className/attribute数字值
_
、-
符号组成,不包含大写字母;-
),以代替驼峰式命名。如:head-menu;_
)。如:color_red;__
)。如:nav__item。其中标志前缀prefix由样式模块确认:
g-
:gridf-
: functionu-
: unit、Component unitz-
: statuss-
: skina-
: animationm-
: Module特殊样式模块前缀:
j-
: JavaScript DOMv*-
: VueJS专用,如VueJS专用动画.va-fadein
r*-
: ReactJS专用,如ReactJS专用宽度.ru-w100
a*-
: Angular专用,如Angular专用皮肤.as-cr_red
属性简写规则,通常由属性单词首字母组成,部分较长的样式属性单词或避免重复可取首字母和中间字母。如margin-top
-> mt
,background-color
-> bgc
;属性值单位值为px时,省略px;为rem/vw时,数值转为px并省略rem/vw;为%
时,则%
换为per
,
如padding-left: 30px
-> pl30
,width: 1rem
-> w75
,margin-top: 2vw
-> mt15
,left: 50%
-> l50per
。更多属性简写可参考样式属性命名>>
属性值为非模块时,名字为标识,如icon
、ovhidden
。
结合标志,如下
.u-w30per
.g-mt30
.f-blod
.s-bgc_red
[s-cr_red]
类名为module时,按照如下命名规则
Module结合Base层、Component层、Skin层、Layout层完成整个样式。其命名通常与项目业务耦合,部分命名可参考Module命名词典>>
(标志前缀)-类块__类元素
其中标识前缀可省略
Module分为块(Block)及元素(Element),
Block,即OO中的容器,是用来标识一个具体块的关键字其实就是这个块的名字,如:头->head, 内容->content, 导航->nav, 尾->foot。一个块必须有一个唯一的名字(类),这样才能保证块的独立性。 块由gird来控制其布局。
Element,依赖于块的元素。是用来标识一个元素的关键字也是这个元素的名字。如导航栏链接或菜单的每一项->item 我们在长名称中使用连字符分隔单词(例如,block-name),使用两个下划线来分隔块名和元素名(block-name__element-name)。 块名称为其元素和专属修饰符定义命名空间。
如
<nav class="m-nav">
<a class="m-nav__item">nav 1</a>
<a class="m-nav__item">nav 2</a>
</nav>
如
<section class="g-pr">
<nav class="m-nav f-tc g-pa g-t50l100" u-size="big" s-bgc_yellow>
<a class="m-nav__item">nav 1</a>
<a class="m-nav__item nav_type_selected">nav 2</a>
</nav>
</section>
/* layout */
.g-pr { position: relative; }
.g-pa { position: absolute; }
/* function */
.f-tc { text-align: center; }
/* unit */
[u-size="big"] { width: 500px; font-size: 30px; }
[u-size="small"] { width: 50px; font-size: 10px; }
/* skin */
[s-bgc_yellow] { background-color: yellow; }
/* module */
.m-nav { /*...*/ }
.m-nav__item { /*...*/ }
如果使用了CSS in JS或者css modules来指定Module的话,则可避免模块元素及修饰符的依赖式写法。(避免BE写法)
VueJS(vue-cli)可直接在style标签中设置module属性完成css module的设置(可见文档) ReactJS需要设置webpack配置文件中cssOptions参数的modules为true。
如:
<template>
<section :class="$style.foot">
<p>
<img :class="$style.img" src="@/images/i-logo_b.png">
</p>
<p>@All right reserved | Design by <a href="https://github.com/MichealWayne/">Micheal Wayne</a></p>
</section>
</template>
<style lang="less" module>
.foot {
line-height: 10vw;
word-break: keep-all;
white-space: nowrap;
.img {
width: 10px;
height: 10px;
}
}
</style>
<template>
<section :class="[$style.foot, 'f-tc']">
<p class="u-pt80">
<img :class="[$style.img, 'g-mb20']" src="@/images/i-logo_b.png">
</p>
<p class="g-fs22 u-pb100" s-cr_sub>@All right reserved | Design by <a class="f-unl" s-cr_blue href="https://github.com/MichealWayne/">Micheal Wayne</a></p>
</section>
</template>
<style lang="less" module>
.foot {
line-height: 10vw;
word-break: keep-all;
white-space: nowrap;
.img {
width: 10px;
height: 10px;
}
}
</style>
import React, {Component} from 'react';
import classnames from 'classnames';
import style from './index.scss';
export default function Footer () {
return (
<footer>
<p class="u-pt80">
<img className={classnames(style.img, 'g-mb20')} src={require('@/images/i-logo_b.png')}>
</p>
MIT Licensed | Copyright © 2019-present MichealWayne
</footer>
)
}
// index.scss
.foot {
padding: 40px;
.img {
width: 10px;
height: 10px;
}
}
moo-css-base为本人从团队多年项目中抽离的公用CSS样式/方法库,遵守Moo-CSS规范,作为页面样式的Base层在全局使用。
具体使用和介绍请前往Moo-CSS moo-css-base