React-样式汇总

2,044 阅读4分钟

项目中会经常使用css样式来修饰页面效果

也可以结合css预编译器进行使用

css预编译器(变量、嵌套、混入、函数) 最终要编译为css

常用css预编译器:

sass、scss是一种 scss是sass的第三个版本 编译器发生了改变 node-sass dart-sass

less

stylus

1、行内样式

使用标签的style属性,JSX语法中style属性的值的为对象结构,css属性的名称为大驼峰,如果值为非数字则使用引号包裹

import React, { Component } from 'react'export default class App extends Component {
  render() {
    return (
      // style行内样式
      <div
        style={{
          border: '1px solid #ccc',
          width: '25%',
          marginTop: 10,
          marginLeft: 10,
          display: 'flex',
          flexDirection:'column',
          alignItems:'center'
        }}
      >
        <div>名称:皮卡丘</div>
        <div>技能:十万伏特</div>
        <div>体态:黄色</div>
      </div>
    )
  }
}

2、使用className属性

可以将样式进行抽离出来,并且可以进行复用。但是会存在样式污染的情况,也就是选择器名称不能够重名。

.card {
  border: 1px solid #ccc;
  width: 25%;
  margin-top: 10px;
  margin-left: 10px;
  display: flex;
  flex-direction: column;
  align-items: center;
}
​
import React, { Component } from 'react'
import './index.css'
export default class App extends Component {
  render() {
    return (
      <div>
        <div className="card">
          <div>名称:皮卡丘</div>
          <div>技能:十万伏特</div>
          <div>体态:黄色</div>
        </div>
        <Child></Child>
      </div>
    )
  }
}

3、css module模块化

当然,在 vue 里可以选择 scoped css 或者 css modules,而在 react 里就只能用 css modules 了。

css modules 是通过 postcss-modules 这个包实现的,vite 也对它做了集成。

底层脚手架(webpack)在加载样式文件时,通过module模块化,编译后,把css选择器相同的生成一个唯一的名称,这样就可以避免由于选择名称相同,导致样式的覆盖和污染了。

src\Child.module.css

.card {
  border: 1px solid red;
  width: 25%;
  margin-top: 10px;
  margin-left: 10px;
  display: flex;
  flex-direction: column;
  align-items: center;
}
​

src\Child.jsx

import React, { Component } from 'react'
//module模块化css后  实际文件会当做一个对象加载进来
import styles from './index.module.css'
export default class Child extends Component {
  render() {
    return <div className={styles.card}>Child</div>
  }
}
​

不管是index.module.css还是index.module.scss,他们导入的时候,都需要又一个东西接受才能生效,这样导入(import 'index.module.css')是无效的。

正确使用方式:

import styles from './index.module.css'

同一个文件,不同组件使用,生成的hash值是一样的

image.png 测试如下

image.png 打包的时候,和其他样式打在一起

image.png

4、styled-components

在react中为了能够使样式进行动态变化,需要在js中完成css的设置。css-in-js技术,在react社区中有多种样式编写的方案。

styled-components是其中优秀方案之一,将样式同时编写在组件的jsx文件中,以达到编写和管理方便的情况。

继承、变量等写法

安装

npm i styled-components

src\App.js

import React, { Component } from 'react'
import Child from './Child'
// 1、引入styled-components 样式库
import styled from 'styled-components'
// 2、创建一个组件容器 并编写样式
const Card = styled.div`
  border: 1px solid #ccc;
  width: 25%;
  margin-top: 10px;
  margin-left: 10px;
  display: flex;
  flex-direction: column;
  align-items: center;
`
export default class App extends Component {
  render() {
    return (
      <div>
        {/* 3、将编写好的组件样式 进行套用 和组件标签的使用方式基本一致 */}
        <Card>
          <div>名称:皮卡丘</div>
          <div>技能:十万伏特</div>
          <div>体态:黄色</div>
        </Card>
        <Child></Child>
      </div>
    )
  }
}

​ 样式继承和属性传递

import React, { Component } from 'react'
import styled from 'styled-components'
const Title = styled.div`
  width: 200px;
  height: 100px;
  border: 1px solid black;
`
// 样式继承  将原有的样式进行复用  没有设置的复用  有设置的的以自身为准
const Title1 = styled(Title)`
  height: 50px;
  color: red;
`
// 属性传递  变量使用
const Color = styled.div`
  color: ${(props) => props.color || 'red'};
`export default class App extends Component {
  render() {
    return (
      <div>
        App
        <Title>标题内容一</Title>
        <Title1>标题内容二</Title1>
        <Color>红色文字</Color>
        <Color color="green">绿色文字</Color>
      </div>
    )
  }
}

5、scss的使用

scss是成熟、稳定的流行的css预编译处理器

在react使用create-react-app脚手架中,内部已经将scss的样式编译配置完成,但是编译器的依赖需要自行安装。

安装sass编译器

npm i -D sass

src\App.scss

$pramiry-color: red;
.item {
  display: flex;
  justify-content: space-between;
  padding: 5px;
  // scss嵌套写法
  > div:first-child {
    width: 30%;
  }
  > div:nth-child(2) {
    width: 60%;
    margin-left: 10px;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    > div:first-child {
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    > div:nth-child(2) {
      // 变量使用
      color: $pramiry-color;
    }
  }
}

​ src\App.js

import React, { Component } from 'react'
import './App.scss'

export default class App extends Component {
  render() {
    return (
      <div className="item">
        <div>
          <img
            src="http://dingyue.ws.126.net/2021/0201/b63f2e50j00qntwfh0020c000hs00npg.jpg?imageView&thumbnail=140y88&quality=85"
            alt=""
          />
        </div>
        <div>
          <div>被指偷拿半卷卫生纸 63岁女洗碗工服药自杀 酒店回应</div>
          <div>2021-02-02 10:00:51</div>
        </div>
      </div>
    )
  }
}

6、less的使用

less支持浏览器和开发者服务器编译两种方式。

默认react脚手架create-react-app默认只支持scss,如果使用less需要解构配置文件,并安装编译器和加载器进行使用

npm i less -D

src\App.less

// 变量声明定义
@pramiry-color: red;
.item {
  display: flex;
  justify-content: space-between;
  padding: 5px;
  > div:first-child {
    width: 30%;
  }
  > div:nth-child(2) {
    width: 60%;
    margin-left: 10px;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    > div:first-child {
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    > div:nth-child(2) {
      // 变量使用
      color:@pramiry-color;
    }
  }
}

src/App.jsx

import React, { Component } from 'react'
import './App.less'

export default class App extends Component {
  render() {
    return (
      <div className="item">
        <div>
          <img
            src="http://dingyue.ws.126.net/2021/0201/b63f2e50j00qntwfh0020c000hs00npg.jpg?imageView&thumbnail=140y88&quality=85"
            alt=""
          />
        </div>
        <div>
          <div>被指偷拿半卷卫生纸 63岁女洗碗工服药自杀 酒店回应</div>
          <div>2021-02-02 10:00:51</div>
        </div>
      </div>
    )
  }
}

sass和less在webpack里面都需要具体的加载器:sass-loader和less-loader,配置下就好了

image.png

7、tailwind的使用

tailwind它依赖postcss存在。

按照 tailwind 文档里的步骤安装 tailwind:

npm install -D tailwindcss postcss autoprefixer

npx tailwindcss init -p

会生成 tailwind 和 postcss 配置文件:

image.png

tailwind.config.js这个文件里,修改下 content 配置,也就是从哪里提取 className

javascript
复制代码
/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

tailwind 会提取className之后按需生成最终的 css。

改下index.css引入 tailwind 基础样式:

@tailwind base;
@tailwind components;
@tailwind utilities;

在 main.tsx 里引入:

如果你没安装 tailwind 插件,需要安装一下:

这样在写代码的时候就会提示 className 和对应的样式值:

不知道 className 叫啥的样式,还可以在 tailwind 文档里搜:

注意: 安装 tailwind 以后请重启项目,才会生效,不然不会生效

8.Unocss

从官网我们可以看出,Unocss 将自己定位为一款原子化引擎,而不是像 TailwindCSS 那样只是一款 PostCSS 的插件,这说明 UnoCSS 不会依靠别的工具或者平台去执行,自己就可以完成像 TailwindCSS 那样的功能。

相比 TailwindCSS 来说,UnoCSS 扩展性和灵活性也更加强大,我们几乎不需要任何的配置就是可以完成原子化样式的生成。

npm install unocss @unocss/cli -D

创建文件

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" type="text/css" href="./dist/output.css" />
</head>
<body>
  <div class="flex justify-center text-red p-100 m-0 text-lg">
    hello, UnoCSS
  </div>
</body>
</html>

编译

npx unocss ./index.html --out-file ./dist/output.css

在命令执行完成之后,就可在根目录下面生成一个 dist 文件夹,里面有一个 output.css 文件。

/* layer: preflights */
*,
::before,
::after {
  --un-rotate: 0;
  --un-rotate-x: 0;
  --un-rotate-y: 0;
  --un-rotate-z: 0;
  --un-scale-x: 1;
  --un-scale-y: 1;
  --un-scale-z: 1;
  --un-skew-x: 0;
  --un-skew-y: 0;
  --un-translate-x: 0;
  --un-translate-y: 0;
  --un-translate-z: 0;
  --un-pan-x: ;
  --un-pan-y: ;
  --un-pinch-zoom: ;
  --un-scroll-snap-strictness: proximity;
  --un-ordinal: ;
  --un-slashed-zero: ;
  --un-numeric-figure: ;
  --un-numeric-spacing: ;
  --un-numeric-fraction: ;
  --un-border-spacing-x: 0;
  --un-border-spacing-y: 0;
  --un-ring-offset-shadow: 0 0 rgb(0 0 0 / 0);
  --un-ring-shadow: 0 0 rgb(0 0 0 / 0);
  --un-shadow-inset: ;
  --un-shadow: 0 0 rgb(0 0 0 / 0);
  --un-ring-inset: ;
  --un-ring-offset-width: 0px;
  --un-ring-offset-color: #fff;
  --un-ring-width: 0px;
  --un-ring-color: rgb(147 197 253 / 0.5);
  --un-blur: ;
  --un-brightness: ;
  --un-contrast: ;
  --un-drop-shadow: ;
  --un-grayscale: ;
  --un-hue-rotate: ;
  --un-invert: ;
  --un-saturate: ;
  --un-sepia: ;
  --un-backdrop-blur: ;
  --un-backdrop-brightness: ;
  --un-backdrop-contrast: ;
  --un-backdrop-grayscale: ;
  --un-backdrop-hue-rotate: ;
  --un-backdrop-invert: ;
  --un-backdrop-opacity: ;
  --un-backdrop-saturate: ;
  --un-backdrop-sepia: ;
}
::backdrop {
  --un-rotate: 0;
  --un-rotate-x: 0;
  --un-rotate-y: 0;
  --un-rotate-z: 0;
  --un-scale-x: 1;
  --un-scale-y: 1;
  --un-scale-z: 1;
  --un-skew-x: 0;
  --un-skew-y: 0;
  --un-translate-x: 0;
  --un-translate-y: 0;
  --un-translate-z: 0;
  --un-pan-x: ;
  --un-pan-y: ;
  --un-pinch-zoom: ;
  --un-scroll-snap-strictness: proximity;
  --un-ordinal: ;
  --un-slashed-zero: ;
  --un-numeric-figure: ;
  --un-numeric-spacing: ;
  --un-numeric-fraction: ;
  --un-border-spacing-x: 0;
  --un-border-spacing-y: 0;
  --un-ring-offset-shadow: 0 0 rgb(0 0 0 / 0);
  --un-ring-shadow: 0 0 rgb(0 0 0 / 0);
  --un-shadow-inset: ;
  --un-shadow: 0 0 rgb(0 0 0 / 0);
  --un-ring-inset: ;
  --un-ring-offset-width: 0px;
  --un-ring-offset-color: #fff;
  --un-ring-width: 0px;
  --un-ring-color: rgb(147 197 253 / 0.5);
  --un-blur: ;
  --un-brightness: ;
  --un-contrast: ;
  --un-drop-shadow: ;
  --un-grayscale: ;
  --un-hue-rotate: ;
  --un-invert: ;
  --un-saturate: ;
  --un-sepia: ;
  --un-backdrop-blur: ;
  --un-backdrop-brightness: ;
  --un-backdrop-contrast: ;
  --un-backdrop-grayscale: ;
  --un-backdrop-hue-rotate: ;
  --un-backdrop-invert: ;
  --un-backdrop-opacity: ;
  --un-backdrop-saturate: ;
  --un-backdrop-sepia: ;
}
/* layer: default */
.m-0 {
  margin: 0;
}
.flex {
  display: flex;
}
.justify-center {
  justify-content: center;
}
.p-100 {
  padding: 25rem;
}
.text-lg {
  font-size: 1.125rem;
  line-height: 1.75rem;
}
.text-red {
  --un-text-opacity: 1;
  color: rgb(248 113 113 / var(--un-text-opacity));
}

预览页面

image.png

相比 TailwindCSSUnoCSS 使用起来确实更加的方便,它不需要我们再单独提供一个样式文件,也不需要创建任何的配置文件(当然,官方更建议我们作用配置文件)就可以生成我们想要的样式,而且只生成我们入口文件中所需要的样式,尽量减少包体积。

和 TailwindCSS 相比,我们通过上面的叙述也可以看出来几点不同。

  • TailwindCSS 本质上是一款 PostCSS 插件,它运行需依赖 PostCSS ,而 UnoCSS 是一款引擎,无需借助任何其它工具或者平台即可执行构建。

presetUno 预设提供了一个包含 TailwindCS、WindiCSS、Boostrap 和 Tachyons 等框架的超集。我们通过配置文件可以配置预设。默认本来就有,你可以配置关闭也可以配置启用。

import { defineConfig, presetUno } from 'unocss'
export default defineConfig({
  presets: [
    presetUno()
  ]
})

如果我们想在 UnoCSS 中使用了一个预设中没有提供的样式该怎么办?比如说我起一个样式名为:aa-bb-cc,这很明显在预设中没有,我们可以在配置文件中添加自定义 Rules

import { defineConfig } from 'unocss'
export default defineConfig({
  // 配置自定义 rule
  rules: [
    ['aa-bb-cc', {
      'display': 'fixed',
      'top': '10px',
      'left': '10px'
    }]
  ]
})

集成webpack

npm install -D @unocss/webpack @unocss/preset-uno

配置

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

// 引入 UnoCSS 依赖
const UnoCSS = require('@unocss/webpack').default

module.exports = {
  mode: 'production',
  entry: './src/index.js',
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
    clean: true
  },
  module: {
    rules: [
      {
        test: /.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'postcss-loader',
        ]
      },
      {
        test: /.(scss|sass)$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'postcss-loader',
          'sass-loader',
        ],
      },
      {
        test: /.(less)$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'postcss-loader',
          'less-loader',
        ],
      },
      {
        test: /.(styl)$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'postcss-loader',
          'stylus-loader',
        ],
      },
    ]
  },
  plugins: [
    new MiniCssExtractPlugin(),
    new HtmlWebpackPlugin({
      template: 'index.html'
    }),
    // 配置 UnoCSS 插件
    UnoCSS(),
  ],
};

然后我们再创建一个 uno.config.js 配置文件:

const { defineConfig } = require('@unocss/webpack')
const presetUno = require('@unocss/preset-uno')
module.exports = defineConfig({
  content: {
    pipeline: {
      include: [
        'src/**/*.{js,ts}',
      ],
    },
  },
  presets: [
    presetUno()
  ]
})

// 引入 uno.css 
import 'uno.css'
import { sassComponent, lessComponent, stylusComponent } from "./component";

function component() {
  const element = document.createElement('div');
  element.id = 'app'

  // 创建一个 div 用于显示,在添加上相关的样式
  const unoElement = document.createElement('div')
  unoElement.innerText = 'hello, Weback + UnoCSS'
  unoElement.classList = ['text-red']

  element.appendChild(unoElement)
  return element;
}

document.body.appendChild(component());

vite集成

npm install -D unocss

vite配置文件

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// 引入 UnoCSS 依赖
import unoCSS from 'unocss/vite'


// https://vitejs.dev/config/
export default defineConfig({
  // 配置插件
  plugins: [vue(), unoCSS()]
})

main。tsx

import { createApp } from 'vue'
import './style.css'
import './test.scss'

//引
import 'virtual:uno.css'

import App from './App.vue'

createApp(App).mount('#app')

9.提取共用样式

/* styles.css */

.text-blue {

  color: blue;

}

.text-bold {

  font-weight: bold;

}

export const sharedStyles = {

  textBlue: 'text-blue',

  textBold: 'text-bold',

};

在app.tsx文件里面使用

// MyComponent.js
import React from 'react';
import styles, { sharedStyles } from './styles.css';
 
const MyComponent = () => {
  return (
    <div className={styles[sharedStyles.textBlue]}>
      This text is blue.
    </div>
    <div className={styles[sharedStyles.textBold]}>
      This text is bold.
    </div>
  );
};
 
export default MyComponent;

10 提取样式变量

参考文章:www.jianshu.com/p/0099fd124…

创建一个CSS文件(例如styles.css),并定义变量,:root是body的意思。

/* styles.css */

:root {
  --primary-color: #3498db;
  --font-size-large: 18px;
}

使用

// MyComponent.js
import React from 'react';
// 导入CSS变量文件
import './styles.css';
 
const MyComponent = () => {
  return (
    <div
      style={{
        color: 'var(--primary-color)',
        fontSize: 'var(--font-size-large)',
      }}
    >
      这是一个使用共用样式变量的组件。
    </div>
  );
};
 
export default MyComponent;

10.样式切换 利用classnames

import React, { useState } from 'react';
import classNames from 'classnames';

const ToggleButton = () => {
  const [isToggled, setIsToggled] = useState(false);

  const handleToggle = () => {
    setIsToggled(!isToggled);
  };
  const buttonClass = classNames({
    'btn': true, 
    'btn-active': isActive, 
    'btn-inactive': !isActive, 
  });

  return (
    <button className={buttonClass} onClick={handleToggle}>
      {isToggled ? 'ON' : 'OFF'}
    </button>
  );
};

export default ToggleButton;