相关文章
如何避免 css 污染
一、命名约定
使用一致的命名约定来避免命名冲突。可以采用 BEM(块、元素、修饰符)等命名规范,确保每个 CSS 类都有清晰的命名空间,减少命名冲突的可能性。
示例
1 2 3 4 5 6 7 8 9 10
| <div class="header"> <div class="header__logo"></div> <nav class="header__nav"> <ul class="header__nav-list"> <li class="header__nav-item"></li> <li class="header__nav-item"></li> <li class="header__nav-item"></li> </ul> </nav> </div>
|
在这个示例中,.header 是块,.header__logo 和 .header__nav 是元素,.header__nav-list、.header__nav-item 是嵌套元素。这种命名约定使得 CSS 类名更具有语义化,便于开发者理解和维护。
二、使用命名空间
为每个模块添加一个命名空间或前缀,以区分不同模块的选择器。这样可以确保即使选择器相同,也不会发生冲突。例如,给每个模块添加一个唯一的前缀:
1 2 3 4 5 6 7 8 9
| .header { background-color: #333; color: #fff; }
.header .logo { font-size: 24px; }
|
1 2 3 4 5 6 7 8 9 10 11 12
| // _button.scss .button { padding: 10px 20px; border: none; background-color: #007bff; color: #fff; cursor: pointer; }
.button:hover { background-color: #0056b3; }
|
三、CSS Modules
使用 CSS Modules 技术,将样式文件转换为具有局部作用域的模块,避免全局污染和命名冲突。在 CSS Modules 中,每个类名都会自动添加一个唯一的哈希值,以确保其在局部作用域内的唯一性。
JSX语法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
.button { padding: 10px 20px; border: none; background-color: #007bff; color: #fff; cursor: pointer; }
.button:hover { background-color: #0056b3; }
|
1 2 3 4 5 6 7 8 9 10 11 12
|
import React from 'react'; import styles from './button.module.css';
const Button = () => { return ( <button className={styles.button}>Click me</button> {} ); };
export default Button;
|
Template语法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| <template> <button :class="$style.button" @click="handleClick">{{ text }}</button> </template>
<script> export default { name: 'Button', props: { text: { type: String, default: 'Click me' } }, methods: { handleClick() { alert('Button clicked'); } } }; </script>
<style module> .button { padding: 10px 20px; border: none; background-color: #007bff; color: #fff; cursor: pointer; }
.button:hover { background-color: #0056b3; } </style>
|
四、CSS-in-JS
使用 CSS-in-JS 的解决方案,确保每个组件的样式只在其作用域内有效,避免全局污染和命名冲突。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
import React from 'react';
const buttonStyle = { padding: '10px 20px', border: 'none', backgroundColor: '#007bff', color: '#fff', cursor: 'pointer', };
const Button = ({ primary, children }) => { const style = primary ? { ...buttonStyle } : {};
return ( <button style={style} > {children} </button> ); };
export default Button;
|
五、Shadow DOM
使用 Web Components 中的 Shadow DOM 技术,将组件的样式封装在 Shadow DOM 内部,确保样式只对组件内部有效,避免与外部样式发生冲突。
原生
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| // custom-button.js
// 创建一个自定义按钮组件 class CustomButton extends HTMLElement { constructor() { super(); // 创建 Shadow DOM this.attachShadow({ mode: 'open' }); // 在 Shadow DOM 中添加按钮元素和样式 this.shadowRoot.innerHTML = ` <style> button { padding: 10px 20px; border: none; background-color: #007bff; color: #fff; cursor: pointer; } button:hover { background-color: #0056b3; } </style> <button><slot></slot></button> `; } }
// 注册自定义按钮组件 customElements.define('custom-button', CustomButton);
|
react
定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import React, { useEffect, useRef } from 'react'; import ReactDOM from 'react-dom';
function ShadowDOMComponent({ children }) { const containerRef = useRef(null);
useEffect(() => { const shadowRoot = containerRef.current.attachShadow({ mode: 'open' }); ReactDOM.createPortal(children, shadowRoot); }, [children]);
return <div ref={containerRef}></div>; }
export default ShadowDOMComponent;
|
使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| import React from 'react'; import ShadowDOMComponent from './ShadowDOMComponent';
function App() { return ( <div> <h1>React App</h1> <ShadowDOMComponent> <div> <style> {` .container { background-color: #eee; } .button { color: blue; } `} </style> <div className="container"> <button className="button">Click me</button> </div> </div> </ShadowDOMComponent> </div> ); }
export default App;
|