React中CSS使用方法

css modules

什么是 css modules

因为 React 没有Vue的Scoped,但是React又是SPA(单页面应用),所以需要一种方式来解决css的样式冲突问题,也就是把每个组件的样式做成单独的作用域,实现样式隔离,而css modules就是一种解决方案,但是我们需要借助一些工具来实现,比如webpackpostcsscss-loadervite等。

如何在Vite中使用css modules

css modules,可以配合各种css预处理去使用,例如lesssassstylus等。

sh 复制代码
npm install less -D # 安装less 任选其一
npm install sass -D # 安装sass 任选其一
npm install stylus -D # 安装stylus 任选其一

在Vite中css Modules 是开箱即用的,只需要把文件名设置为xxx.module.[css|less|sass|stylus],就可以使用css modules了

  • src/components/Button/index.module.scss
scss 复制代码
.button {
  color: red;
}
  • src/components/Button/index.tsx
tsx 复制代码
//使用方法,直接引入即可
import styles from './index.module.scss';

export default function Button() {
  return <button className={styles.button}>按钮</button>;
}
  • 编译结果, 可以看到button类名被编译成了button_pmkzx_6,这就是css modules的实现原理,通过在类名前添加一个唯一的哈希值,来实现样式隔离。
html 复制代码
<button class="button_pmkzx_6">按钮</button>

修改css modules 规则

  • 在vite.config.ts中配置css modules的规则
ts 复制代码
export default defineConfig({
  css: {
    modules: {
      localsConvention: 'dashes', // 修改css modules的类名规则 可以改成驼峰命名 或者 xxx-xxx命名等
      generateScopedName: '[name]__[local]___[hash:base64:5]', // 修改css modules的类名规则 name 是文件名 local 是类名 hash 是hash值
    },
  },
});

例子 例如设置为(localsConvention:camelCaseOnly)

!WARNING

camelCase 和 camelCaseOnly 区别在于,camelCase 会把非驼峰的命名转为驼峰,并保留之前的类名,而 camelCaseOnly 只会把非驼峰的命名转为驼峰,并删除之前的类名。

  • src/components/Button/index.module.scss
scss 复制代码
.button-red {
  color: red;
}
  • src/components/Button/index.tsx

设置为驼峰之后,使用的时候需要使用驼峰命名,例如buttonRed,而不是button-red

tsx 复制代码
import styles from './index.module.scss';

export default function Button() {
  return <button className={styles.buttonRed}>按钮</button>;
}

例子 例如设置为(localsConvention:dashesOnly)会将所有-的类名转化为驼峰,并且原始的类名会被删除

!WARNING

dashes 和 dashesOnly 区别在于,dashes 会保留原始的类名,而 dashesOnly 会删除原始的类名。

  • src/components/Button/index.module.scss
scss 复制代码
.button-red {
  color: red;
}
  • src/components/Button/index.tsx

设置为原始命名之后,使用的时候需要使用驼峰命名,例如buttonRed,而不是button-red

tsx 复制代码
import styles from './index.module.scss';

export default function Button() {
  return <button className={styles.buttonRed}>按钮</button>;
}

!CAUTION

如果想同时支持驼峰命名和-连接的命名,可以设置为localsConvention:[camelCase|dashes],这样就可以同时支持驼峰命名和-连接的命名。

例子 修改css modules的类名规则

  • 在vite.config.ts中配置css modules的规则
ts 复制代码
export default defineConfig({
  css: {
    modules: {
        generateScopedName: '[local]_[hash:base64:5]' // 只保留类名和哈希值
        // 或者
        generateScopedName: '[hash:base64:8]' // 只使用哈希值
        // 或者
        generateScopedName: '[name]_[local]' // 只使用文件名和类名,没有哈希
        // 或者
        generateScopedName: '[local]--[hash:base64:4]' // 自定义分隔符
    },
  },
});

编译结果

html 复制代码
<button class="button_pmkzx_6">类名 + 哈希值</button>
<button class="pmkzx_6">哈希值</button>
<button class="index-module_button">文件名 + 类名</button>
<button class="button--pmkzx_6">类名 + 分隔符 + 哈希值</button>

维持类名

在样式文件中的某些样式,不希望被编译成css modules,可以设置为global

scss 复制代码
解释

.app{
    background: red;
    width: 200px;
    height: 200px;
    :global(.button){
        background: blue;
        width: 100px;
        height: 100px;
    }
}
tsx 复制代码
//在使用的时候,就可以直接使用原始的类名 button
import styles from './index.module.scss';
const App: React.FC = () => {
  return (
    <>
      <div className={styles.app}>
        <button className='button'>按钮</button>
      </div>
    </>
  );
}

css-in-js

css-in-js 是将 CSS 代码 跟 JS 代码 混合在一起,通过 JS 来动态的生成 CSS 样式,但是这样的话与我们的认知是背道而驰的,正常应该是 CSS JS HTML 分离的,但是由于 CSS 缺乏作用域,所以形成了 css-in-js 这种写法,注意 css-in-js 并不是一种技术,而是一种思想。

优缺点

优点:

  • 可以让 CSS 拥有独立的作用域,阻止 CSS 泄露到组件外部,防止冲突。
  • 可以动态的生成 CSS 样式,根据组件的状态来动态的生成 CSS 样式。
  • CSS-in-JS 可以方便地实现主题切换功能,只需更改主题变量即可改变整个应用的样式。

缺点:

  • css-in-js 是基于运行时,所以会损耗一些性能(电脑性能高可以忽略)
  • 调试困难,CSS-in-JS 的样式难以调试,因为它们是动态生成的,而不是在 CSS 文件中定义的。

styled-components

1.安装

sh 复制代码
npm install styled-components

2.创建一个 Button 组件

tsx 复制代码
import styled from 'styled-components';

const Button = styled.button`
  background: red;
  color: white;
  border: 2px solid skyblue;
`;
function App() {
  return (
    <>
      <Button>我是按钮</Button>
    </>
  );
}

export default App;

我们可以看到,Button 组件的类名是通过js随机生成的的,这样就避免了类名冲突的问题。

3.更多用法

继承
tsx 复制代码
import styled from 'styled-components';

const Button = styled.button`
  background: red;
  color: white;
  border: 2px solid skyblue;
`;
// 继承上面的样式,然后再添加新的样式
const BlueButton = styled(Button)`
  background: blue;
`;
function App() {
  return (
    <>
      <Button>我是按钮</Button>
      <BlueButton>我是蓝色按钮</BlueButton>
    </>
  );
}

export default App;
属性

我们可以通过 attrs 来给组件添加属性,比如 defaultValue,然后通过 props 来获取属性值。

tsx 复制代码
import React from 'react';
import styled from 'styled-components';
interface DivComponentProps {
  defaultValue: string;
}
// 通过 .attrs 方法设置默认属性和类型
const InputComponent = styled.input.attrs<DivComponentProps>((props) => ({
  type: 'text',
  defaultValue: props.defaultValue, // 从 props 中获取默认值
}))`
  border: 1px solid skyblue;
  margin: 20px;
`;

const App: React.FC = () => {
  const defaultValue = '张三';
  return (
    <>
      {/* 渲染带样式的输入框组件并传入默认值 */}
      <InputComponent defaultValue={defaultValue}></InputComponent>
    </>
  );
};

export default App;
全局样式

我们可以通过 createGlobalStyle 来创建全局样式, 然后放到 App 组件中。

tsx 复制代码
import React from 'react';
import styled, { createGlobalStyle } from 'styled-components';
// 通过createGlobalStyle设置全局样式,一般放在一个单独的文件里
const GlobalStyle = createGlobalStyle`
  body {
    background-color: #f0f0f0;
  },
  * {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
  }
  ul,ol{
      list-style: none;
  }
`;
const App: React.FC = () => {
  return (
    <>
      <GlobalStyle />
    </>
  );
};

export default App;
动画

我们可以通过 keyframes 来创建动画。

tsx 复制代码
import React, { } from 'react';
import styled, { createGlobalStyle,keyframes } from 'styled-components';


const move = keyframes`
  0%{
    transform: translateX(0);
  }
  100%{
    transform: translateX(100px);
  }
`
const Box = styled.div`
  width: 100px;
  height: 100px;
  background-color: red;
  animation: ${move} 1s linear infinite;
`
const App: React.FC = () => {
  return (
    <>
      <Box></Box>
    </>
  );
}

export default App;

原理剖析

这个技术叫标签模板, 是ES6 新增的特性,它可以紧跟在函数后面,该函数将被用来调用这个字符串模板

调用完成之后,这个函数的第一个参数是模板字符串的静态字符串,从第二个参数开始,是模板字符串中变量值,也就是${}里面的值

  • strArr:['\n color:red;\n width:', 'px;\n height:', 'px;\n', raw: Array(3)]
  • args:[30, 50]
tsx 复制代码
const div = function (strArr: TemplateStringsArray, ...args: any[]) {
   return strArr.reduce((result, str, i) => {
    return result + str + (args[i] || '')
   }, '')
}

const a = div`
  color:red;
  width:${30}px;
  height:${50}px;
`
console.log(a)
//  输出结果
//  color:red;
//  width:30px;
//  height:50px;

原子化 css

什么是原子化 css

原子化 CSS 是一种现代 CSS 开发方法,它将 CSS 样式拆分成最小的、单一功能的类。比如一个类只负责设置颜色,另一个类只负责设置边距。这种方式让样式更容易维护和复用,能提高开发效率,减少代码冗余。通过组合这些小型样式类,我们可以构建出复杂的界面组件。

原子化 css 基本概念

原子化 css 是一种css的编程范式,它将css的样式拆分成最小的单元,每个单元都是一个独立的css类,通过这些独立的css类来构建整个页面的样式,简单举个例子:

其核心思想就是无需重复定义样式,只需定义一次,然后通过组合这些小型样式类,来构建出复杂的界面组件。

html 复制代码
解释

<style>
  .color-red { color: red }
  .text-center { text-align: center }
  .p-10 { padding: 10px }
</style>
<section class="bg-red text-center p-10">
    原子化 css
</section>

TailWind Css

TailWind Css 官网

TailWind 是原子化 css 的一种实现方式,它内置了许多细粒度的 class 类,这些细粒度的 class 类可以组合使用,来构建出复杂的界面组件。

如何使用 TailWind Css 4.0.1 最新版

  • vite 项目
sh 复制代码
npm install tailwindcss @tailwindcss/vite

1. vite.config.ts

引入 tailwindcss 插件,然后配置 tailwindcss 插件

ts 复制代码
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
  plugins: [react(), tailwindcss()],
})

2.src/tailwind.css (新建一个文件) 引入 tailwindcss 的样式

css 复制代码
@import "tailwindcss";

3.src/main.tsx

引入 tailwindcss 的样式

tsx 复制代码
import './tailwind.css'

4.src/App.tsx 试用 tailwindcss 的样式

tsx 复制代码
<section class="bg-red text-center p-10">
    原子化 css
</section>

5.打开Vscode或者Cursor,安装 TailWind Css 插件,这样编写代码的时候,会自动提示 tailwindcss 的样式

进阶用法@apply

上述代码中,类名用了很多都是堆在一起的,这样看起来很不美观,我们可以使用 tailwindcss@apply 来解决这个问题。

  • src/tailwind.css
css 复制代码
@import "tailwindcss";

.text-bg {
    @apply bg-amber-300 w-100 h-100  text-center justify-center;
}
  • src/App.tsx

效果是一样的,但是看起来更美观了

tsx 复制代码
      <div className="text-bg">使用原子化CSS</div>

更多用法请参考 tailwindcss 自定义样式

!CAUTION

本文内容参考小满大佬

相关推荐
小小小小宇26 分钟前
前端国际化看这一篇就够了
前端
大G哥29 分钟前
PHP标签+注释+html混写+变量
android·开发语言·前端·html·php
whoarethenext31 分钟前
html初识
前端·html
小小小小宇43 分钟前
一个功能相对完善的前端 Emoji
前端
m0_6278275244 分钟前
vue中 vue.config.js反向代理
前端
Java&Develop1 小时前
onloyoffice历史版本功能实现,版本恢复功能,编辑器功能实现 springboot+vue2
前端·spring boot·编辑器
白泽talk1 小时前
2个小时1w字| React & Golang 全栈微服务实战
前端·后端·微服务
摆烂工程师1 小时前
全网最详细的5分钟快速申请一个国际 “edu教育邮箱” 的保姆级教程!
前端·后端·程序员
HhhDreamof_1 小时前
云贝餐饮 最新 V3 独立连锁版 全开源 多端源码 VUE 可二开
前端·vue.js·开源
Simaoya1 小时前
【vue】【element-plus】 el-date-picker使用cell-class-name进行标记,type=year不生效解决方法
前端·javascript·vue.js