工程与架构✅
什么是 CSS 工程化?
答案
CSS 工程化是旨提升 CSS 代码的可维护性、可复用性等的一系列实践和方法论。设计如下核心逻辑
- 命名和组织,例如
- BEM(块-元素-修饰符)贴近组件风格,按照模块/元素/修饰符的方式命名
- Atomic(原子化)— 将样式拆分为最小不可分的原子单元,tailwind css 就是一个原子化的框架
- OOCSS(面向对象的CSS)— 通过CSS“对象”分离容器和内容
- SMACSS(可扩展和模块化的CSS架构)— 将CSS规则分为五类的风格指南,更细化的组织包括
- BASE — 全局元素样式
- LAYOUT — 布局样式
- MODULE — 组件样式
- STATE — 状态样式
- THEME — 主题样式
- 模块化,涉及预处理器/后处理器
- Sass/SCSS/Less/Stylus 支持变量、嵌套、混入、函数等
- PostCSS 支持自动添加浏览器前缀、变量、嵌套等
- 逻辑复用框架
- CSS Modules 支持局部作用域和可组合性
- CSS-in-JS(如 Styled Components、Emotion) 支持动态样式和组件化
- Utility-First 框架(如 Tailwind CSS) 提供大量原子类
- 设计系统(如 Material-UI、Ant Design) 提供统一的设计规范和组件库
- 构建/性能等
- Webpack、Rollup、Vite 等打包工具 支持 CSS 预处理、后处理、Tree Shaking 等
- CSS 构建工具(PurgeCSS) — 删除未使用的 CSS
- lint 工具(如 stylelint) — 代码风格检查
延伸阅读
- css architecture CSS 架构实践
- BEM 对比了不对命名风格
- Atomic Design 原子设计方法论
- awsome css 列举了一系列 css 工具
用过哪些 CSS 预处理器?
答案
CSS 预处理器是对 CSS 语言的扩展,提供了变量、嵌套、混入、函数等功能,使得 CSS 更加灵活和可维护。
常见的 CSS 预处理器包括:
- Sass/SCSS:最流行的预处理器,支持变量、嵌套、混入、函数等。SCSS 是 Sass 的一种语法,是 CSS3 的超集,语法更接近 CSS。
- Less:另一个流行的预处理器,语法类似于 Sass,支持变量、嵌套、混入等。
- Stylus:一个功能强大的预处理器,支持更灵活的语法和功能,如函数、条件语句等。
这里以 Stylus 为例说明常用核心功能
核心功能 | 说明 |
---|---|
变量 | 直接定义变量,无需特殊符号,如 primaryColor = #3498db ,使用时直接写变量名,如 background-color: primaryColor 。支持字符串、数字、颜色等类型。 |
变量插值 | 变量可用于选择器和属性名,如 .{name} 会动态拼接变量 name 的值作为类名。 |
嵌套规则 | 支持 CSS 规则嵌套,简化层级关系书写,如 nav { ul { margin: 0 } } 编译成 nav ul { margin: 0 } 。 |
混入(Mixin) | 通过函数定义可复用的样式块,如 border-radius(n) 定义并调用 border-radius(5px) 。支持参数和默认值。 |
运算 | 支持数学运算,如 width = 100px / 2 ,也支持字符串连接和颜色运算。 |
条件语句 | 支持 if 语句控制样式生成,如 if isPrimary then color = red else color = blue 。 |
循环 | 支持 for 、each 循环迭代生成样式,如 for i in 1..3 生成多个类。 |
函数 | 支持自定义函数,封装复杂逻辑返回值,增强样式的动态能力。 |
引入(Import) | 支持引入其他 Stylus 文件或 CSS 文件,如 @import 'variables.styl' 。 |
颜色函数 | 内置丰富颜色处理函数,如 lighten() , darken() , saturate() 等,方便颜色调整。 |
有用过 PostCSS 吗?
答案
PostCSS 是 CSS 的处理器,可以类比为 Babel 对 JavaScript 的处理。通过插件机制实现对 CSS 的转换和增强。常见的插件包括
- autoprefixer:自动添加浏览器前缀,兼容性处理。
- cssnano:CSS 压缩和优化。
- postcss-preset-env:允许使用未来的 CSS 特性,自动转换为当前浏览器支持的语法。
- postcss-import:支持 CSS 文件的导入,类似于 Sass 的
@import
。 - postcss-nested:支持嵌套规则,类似于 Sass 的嵌套语法。
参考 PostCSS Plugin 一个简单的 PostCSS 插件示例
module.exports = (opts = {}) => {
return {
postcssPlugin: 'postcss-example',
Once (root, { result }) {
root.walkDecls(decl => {
if (decl.prop === 'example') {
decl.cloneBefore({ prop: 'color', value: 'red' })
decl.remove()
}
})
}
}
}
module.exports.postcss = true
通过如下方式消费插件
const postcss = require('postcss')
const example = require('postcss-example')
postcss([example])
.process(css, { from: undefined })
.then(result => {
console.log(result.css)
})
如何优化CSS性能?
答案
核心概念
CSS性能优化涉及选择器优化、渲染性能、文件大小等多个方面。
选择器优化
-
避免过度嵌套
/* 差:过度嵌套 */
.container .wrapper .content .item .link { color: blue; }
/* 好:直接选择 */
.link { color: blue; } -
使用高效的选择器
/* 选择器性能排序(从快到慢) */
#id { } /* 最快 */
.class { } /* 很快 */
element { } /* 快 */
[attribute] { } /* 中等 */
:pseudo-class { } /* 中等 */
element element { } /* 较慢 */
渲染性能优化
-
使用transform和opacity
/* 差:触发重排 */
.animate {
left: 100px;
top: 100px;
}
/* 好:只触发重绘 */
.animate {
transform: translate(100px, 100px);
} -
避免强制同步布局
// 差:强制同步布局
const width = element.offsetWidth
element.style.width = width + 100 + 'px'
// 好:使用requestAnimationFrame
requestAnimationFrame(() => {
element.style.width = element.offsetWidth + 100 + 'px'
})
文件大小优化
-
压缩CSS
/* 压缩前 */
.container {
margin: 10px;
padding: 20px;
background-color: #ffffff;
}
/* 压缩后 */
.container{margin:10px;padding:20px;background-color:#fff} -
移除未使用的CSS
/* 使用PurgeCSS等工具移除未使用的样式 */
/* 只保留实际使用的样式 */
实际应用
/* 性能优化的CSS示例 */
/* 使用CSS变量减少重复 */
:root {
--primary-color: #007bff;
--border-radius: 4px;
}
/* 高效的选择器 */
.button {
background: var(--primary-color);
border-radius: var(--border-radius);
}
/* 使用will-change优化动画 */
.optimized-animation {
will-change: transform;
transition: transform 0.3s ease;
}
面试官视角
- 差:不了解性能优化,使用低效的CSS
- 良:知道基本优化方法,能避免明显的性能问题
- 优:深入理解性能机制,能系统性地优化CSS
延伸阅读
- CSS性能优化 - 官方文档
CSS动画性能如何优化?
答案
核心概念
CSS动画性能直接影响用户体验,优化动画可以提升页面流畅度和响应性。
性能优化策略
-
使用transform和opacity
/* 差:改变布局属性 */
.animate {
left: 100px;
top: 100px;
}
/* 好:使用transform */
.animate {
transform: translate(100px, 100px);
} -
避免触发重排和重绘
/* 差:触发重排 */
.animate {
width: 200px;
height: 200px;
margin: 10px;
}
/* 好:只改变transform */
.animate {
transform: scale(1.2);
} -
使用will-change属性
.optimized {
will-change: transform;
transition: transform 0.3s ease;
} -
合理使用GPU加速
.gpu-accelerated {
transform: translateZ(0); /* 强制GPU加速 */
}
实际应用
/* 高性能动画示例 */
.slide-in {
transform: translateX(-100%);
transition: transform 0.3s ease;
will-change: transform;
}
.slide-in.active {
transform: translateX(0);
}
/* 避免性能问题的动画 */
.fade-in {
opacity: 0;
transition: opacity 0.3s ease;
}
.fade-in.visible {
opacity: 1;
}
面试官视角
- 差:不了解动画性能问题,使用会触发重排的属性
- 良:知道使用transform和opacity,了解基本优化方法
- 优:深入理解渲染机制,能系统性地优化动画性能
延伸阅读
- MDN: CSS动画性能 - 官方文档
- CSS动画性能优化 - 学习指南
重置 css 和标准化 css 的区别?你会选择哪种?为什么?
答案
- 重置是为了统一不同浏览器器的默认样式,需要重新定制所有元素的基础表现
- 标准化是部分保留默认样式,并修复不同浏览器的显示差异 典型应用例如 normalize css
延伸阅读