参考:
copy form
CSS之路:css->less->moudleCss->styleComponet
OOCSS
面向对象的 CSS
,独立于应用逻辑书写,鼓励 html
与 css
分离和代码的复用
OOCSS
遵循两个原则:
- 独立的结构和样式
- 独立的容器和内容
具体实现上可以是拆分为基类和修饰类,将尽可能多的公共属性抽象到基础类,然后将每个变体的样式归类为修饰符类。
<div class="container">
<div class="row">
<div class="col-4">
<button type="button" class="btn btn-success hidden">Success</button>
</div>
<div class="col-8">
<button type="button" class="btn btn-primary">Primary</button>
</div>
</div>
</div>
优点:
css
复用率高,扩展性好;- 具备良好的可读性和可维护性;
- 代码量比较少,天然
Atomic CSS
;
缺点:
- 多人协作模式下,class 选择器容易冲突,没有解决命名空间的问题
- 基础类库开发周期时间偏长
SMACSS
通过结构化命名,将类名模组分组,达到可扩展的目的。与OOCSS
相比,SMACSS
更像是一套模板指导 CSS
的书写。
<div id="section">
<div class="l-flex">
<div class="l-col l-col-4">
<button type="button" class="btn-success is-hidden">Success</button>
</div>
<div class="l-col l-col-8">
<!-- 扩展btn样式,创建子模块 -->
<button type="button" class="btn-primary">Primary</button>
</div>
</div>
</div>
分类:
- Base:重置元素的基本样式,保证元素在任意浏览器中,视觉样式具有一致性。实现如:reset.css、normalize.css;
- Layout:布局规则将页面分块,将一个或多个模块组合在一起,命名以
l-
开头; - Module:模块是设计中可重用的模块化部分,也是 SMACSS 里最重要的一部分,不强制以
m-
开头; - State:状态规则是描述我们的模块或布局在特定状态下的外观的方式。比如 Tab 是否选中,命名一般以
is-
开头; - Theme:主题规则与状态规则相似,它们描述了模块或布局的外观;
优缺点:同 OOCSS
BEM
Block__Element—Modifier
使用 Block、Element、Modifier 描述页面结构
Block
即为区块,可以独立存在;Element
可以理解为元素,它依附于Block
存在,与Block
使用__
连接;Modifier
用于描述Block
或Element
的外观或状态,与他们使用--
连接;
<form class="form form--theme-xmas form--simple">
<input class="form__input" type="text" />
<input class="form__submit form__submit--disabled" type="submit" />
</form>
优点:
- 制定了一套易与理解的
CSS
编码规范; - 可读性高,通过 class 的命名,可以得知元素的结构;
- 很大程度解决了命名冲突的问题;
缺点:
- 重新定义
Block
与Element
的含义,容易造成混淆; - 需要与页面结构并行维护一套
CSS
逻辑; - 命名过长,产出的
size
偏大;
Shadow DOM
Web components
标准的一部分,将封装的 Showdow DOM
附加到元素并控制其关联的功能。
在 Shadow DOM
中定义的 CSS
样式只会在 ShadowRoot
下生效,很好的实现了代码的隔离。
// js
let tmp1 = document.createElement('template');
tmp1.innerHTML = `
<style>
.btn {
display: inline-block;
font-weight: 400;
line-height: 1.5;
text-align: center;
text-decoration: none;
vertical-align: middle;
user-select: none;
border: 1px solid transparent;
padding: .375rem .75rem;
font-size: 1rem;
border-radius: .25rem;
transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;
}
.btn-primary {
color: #fff;
background-color: #0d6efd;
border-color: #0d6efd;
}
</style>
<button type="button" class="btn btn-primary">I'm in shadow dom!</button>
<slot></slot>
`;
customElements.define('x-button', class extends HTMLElement {
constructor() {
super();
let shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.appendChild(tmp1.content.cloneNode(true));
}
});
// html
<x-button></x-button>
优点:
- 面向未来的原生组件写法
- 与页面的其他代码天然隔离
- 可增强现有
HTML
标签,创建可重用的新标签(Custom Element)
缺点:
- 对平台实现有强依赖,浏览器支持度一般
- 目前只能使用
link
标签引入外部样式 (存在绘制闪烁的问题),其他形式的外部样式 (例如全局的CSS
重置) 无法渗透进shadowDOM
内部 (已有提案解决)
CSS-in-JS
React原生自带内联样式属于CSS-In-Js的一种,
同时还有其他几种方案
styled-componentsnts
借助 js
语言的灵活性,使用 js
样式化组件,在组件的运行时,将CSS
附加到 DOM
当中。
import React from 'react';
import styled, { css } from 'styled-components';
const Button = styled.button`
display: inline-block;
font-weight: 400;
line-height: 1.5;
text-align: center;
text-decoration: none;
vertical-align: middle;
user-select: none;
border: 1px solid transparent;
padding: .375rem .75rem;
font-size: 1rem;
border-radius: .25rem;
transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;
${props => props.primary && css`
color: #fff;
background-color: #0d6efd;
border-color: #0d6efd;
`}
`
// OR
// A new component based on Button, but with some override styles
const PrimaryButton = styled(Button)`
color: #fff;
background-color: #0d6efd;
border-color: #0d6efd;
`;
export default ShowButton() {
return (
<div>
<Button>Normal</Button>
<Button primary>Primary</Button>
<PrimaryButton>Primary</PrimaryButton>
</div>
)
}
优点:
- 很轻松的实现
css
与js
变量共享,易于维护; - 代码中只存在
javaScript
,具有跨平台优势; - 不需借助编译工具,即可提取
Critical CSS
;
缺点:
- 风格比较激进
- 有一定学习理解门槛
- 没有统一的标准约束
styled-jsx
nextjs捆绑自带的css in js 方案
https://nextjs.org/docs/basic-features/built-in-css-support#css-in-js
https://github.com/vercel/styled-jsxtailwind css
https://tailwindcss.com/
CSS modules
https://github.com/camsong/blog/issues/5
http://www.ruanyifeng.com/blog/2016/06/css_modules.html
利用 webpack
之类的工具,编译阶段将类名加上随机的 hash
值,以回避命名冲突的问题
比如在某个nextjs项目上,使用less+moudle,解决组件和页面类名冲突
:global 设置成全局class(不加hash值)
CSS Houdini
开放 css 底层 api,开发者可通过接口自行扩展 css
文章介绍了几种前端发展中出现的 css 方案,其实在解决的下面提及的几个问题:
- 作用域(全局 -> 组件)
- 模块化与代码复用(提高可维护性)
- CSS Atomic 化(更小的代码尺寸)
- 提取 Critical CSS(更快的首屏加载体验)
- 跨平台(Write once,run every where)
方案可能会过时,但其中折射隐含的思想,会以新的形式流传进化,它值得每个前端开发人员深入学习与思考。总而言之,技术没有银弹,实际开发中亦需要不断权衡利弊,明确使用场景,选择合适的方法维护项目。
参考链接:
https://caniuse.com/
http://oocss.org/
http://smacss.com/
https://github.com/Polymer/polymer
https://www.cssinjsplayground.com/
https://styled-components.com/
https://github.com/webpack-contrib/css-loader#modules
https://github.com/WICG/webcomponents/blob/gh-pages/proposals/css-modules-v1-explainer.md
https://developer.mozilla.org/zh-CN/docs/Web/Houdini
https://www.smashingmagazine.com/2016/03/houdini-maybe-the-most-exciting-development-in-css-youve-never-heard-of/