css样式私有化

435 阅读5分钟

前言

单页应用开发中,所有组件的css最终会整合到一个html中,样式就容易出现冲突(两个组件有相同的类名,出现样式错误)。样式私有化在单页应用中是一个需要去解决的问题。

vue css样式私有化

做法:style上加入scoped即可。要覆盖第三方样式使用::v-deep即可

原理:

  • 加上scoped之后,当前组件下的节点都会加上一个自定义的属性(这个唯一!!)。
  • 当前组件的css选择器采用了属性选择器,属性就是上一步自定义的唯一的属性。

第三方组件无法覆盖的原因:

.van-tabs__line  {
    background: yellow;
 }

在某一个组件里面,加了scoped,覆盖第三方ui库的样式(自己写的代码)

.van-tabs__line[data-v-7a7a37b1]  {
    background: yellow;
}

因为加了scoped,所以最终会编译成上诉的样子,有一个属性选择器

<div  class="van-tabs__line" style="transform: translateX(51px) translateX(-50%);"></div>

很明显,你写的样式无法适配上诉节点

react css样式私有化

react并没有vue这一套机制,目前没有一个特定的方式。所以当前市面上流行的有如下几种,这几种各有优缺点,请根据实际应用场景进行选择。

行内样式

优点:

  • 使用简单: 简单的以组件为中心来实现样式的添加
  • 扩展方便,使用灵活: 通过使用对象进行样式设置,可以方便的扩展对象来扩展样式
  • 避免冲突: 最终都编译为元素的行内样式,不存在样式冲突的问题

局限性,(不适合大型项目)

  • 不能使用伪类: 这意味着 :hover、:focus、:actived、:visited 等都将无法使用
  • 不能使用媒体查询: 媒体查询相关的属性不能使用
  • 减低代码可读性: 如果使用很多的样式,代码的可读性将大大降低
  • 没有代码提示: 当使用对象来定义样式时,是没有代码提示的
  • js文件过大: css全写在了js中,导致js过大,js过大(白屏问题)

总结:

不是主流,一些情况下可以使用(你的一个div的背景图片是从后端来的)

样式表

CSS样式表应该是我们最常用的定义样式的方式!但多人协作开发中,很容易导致组件间的样式类名冲突,从而导致样式冲突;所以此时需要我们人为有意识的避免冲突

具体做法

  • 保证组件最外层的类名比较独特:路径名称-组件名称的方式
  • 组件的其他样式以嵌套的方式写在最外成那个独特的类名之下

优点:

  • 样式与js分离:(不会存在js比较大)
  • 能使用所有css的功能
  • 容易编写

缺点:

  • 人为的规避,还是可能出现冲突
  • 性能低:css选择器可能过长,性能低(css解析顺序是从右到左)

css-modules

原理:

CSS的规则都是全局的,任何一个组件的样式规则,都对整个页面有效;产生局部作用域的唯一方法,就是使用一个独一无二的class名字;这就是 CSS Modules 的做法!

创建module文件:xxx.module.css

.personal {
    width: 300px;
    height: 200px;
}
.personal span {
    color: green;
}
.title {
    color: red;
    font-size: 16px;
}
.subTitle {
    color: red;
    font-size: 14px;
}

使用es6的方式导入及使用

import React from 'react';
import sty from './demo.module.css';
​
<div classname={sty.title}></div>

不经过编译的类名

:global(.fl) {
    display: flex;
}

CSS Modules 允许使用 :global(.className) 的语法,声明一个全局规则。凡是这样声明的class,都不会被编译成哈希字符串。

继承(类似于sass中的mixin)

.title {
    font-size: 20px;
    color: pink;
}
​
.til {
    composes: title;
    border: 1px solid red;
}

composes类似于mixin(scss)

优点:

  • 不需要人为去约束

缺点:

  • 稍显麻烦
  • 不能使用sass,less等高级语法

React-JSS

JSS: css in js(在js里面写css)

React-JSS 使用新的 Hooks API 将 JSS 与 React 结合使用。 使用步骤如下:

  • 安装react-jss: yarn add react-jss
  • 借助它的方法createUseStyles ,返回一个hook函数
  • 执行hook函数,得到一个一个的类
const userStyle = createUseStyles({
    box: {
        width: '300px',
        border: '1px solid red',
    },
    title: {
        color: '#ff6900',
        display: 'flex',
        justifyContent: 'space-between',
        '& span': {
            '&:nth-child(1)': {
                color: 'yellow'
            }
        }
    }
})
​
export default function ChildJss() {
    const { box, title } = userStyle()
    return (
        <div className={box}>
            <p className={title}>
                <span>我是</span>
                <span>title</span>
            </p>
        </div>
    )
}

优点

  • 功能强大: 不仅支持css的所有东西,也能和js想结合
  • 灵活: 样式可以根据传入的props生成

缺点:

  • 只能在hook组件中使用

    • 如果硬要在类组件中使用它,请使用函数组件将其包一层(高阶组件的使用)

styled-components

基本用法

  • 安装

    • yarn add styled-components
  • 创建一个样式js文件,编写样式。基本语法如下:

    import styled from 'styled-components'// 安装插件:vscode-styled-components
    export const ChildComWrapper = styled.div`
        .title {
            color: red;
        }
        .sub-title {
            color: ${props => {
                console.log(props)
                if(props.theme === 'gray') return 'gray'
                return 'green'
            }};
            &:hover {
                color: red;
            }
        }
    `

    返回的是一个组件哟

  • 在组件中使用

    import React from 'react'
    import { ChildComWrapper } from './style'// style-component
    export default function ChildCom() {
      return (
        <ChildComWrapper theme={'gray'}>
            <p className='title'>我是title</p>
            <p className='sub-title'>我是sub-title</p>
        </ChildComWrapper>
      )
    }
    

扩展用法(抽取变量,抽取公共的组件)

  • 创建一个公共样式文件

    import styled from 'styled-components'
    ​
    ​
    export const NavWrapper = styled.ul`
        display: flex;
        color: #000;
        li {
            margin-right: 10px;
            list-style-type: none;
            &.active {
                color: red;
            }
        }
    `
    
  • 需要的地方使用

    import React from "react";
    import { ChildComWrapper } from "./style";
    import { NavWrapper } from '../../assets/common'// style-component
    export default function ChildCom() {
      return (
        <>
          <ChildComWrapper theme={"gray"}>
            <p className="title">我是title</p>
            <p className="sub-title">我是sub-title</p>
          </ChildComWrapper>
          <NavWrapper>
            <li className="active">登录</li>
            <li>我的</li>
            <li>秒杀</li>
          </NavWrapper>
        </>
      );
    }