You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何阻止Emotion样式注入影响页面其他元素?

解决JsonForms+Emotion全局样式污染问题

问题场景

我在服务端渲染的Web应用中通过JsonForms React组件动态生成表单,用npm run build编译React组件得到main.js后,按以下方式引入页面:

<html>
  <head>
    ...
    <script type="text/javascript" src="main.js"></script>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

功能正常,但页面中组件外的元素CSS被修改——Chrome计算样式显示有Emotion注入的<style>标签覆盖了body的font-family,删除该标签后样式恢复正常。

我的JsonForms组件代码和官方seed应用基本一致:

import { Fragment, useState, useMemo } from 'react';
import { JsonForms } from '@jsonforms/react';
import Grid from '@mui/material/Grid';
import Button from '@mui/material/Button';
import Typography from '@mui/material/Typography';
import logo from './logo.svg';
import './App.css';
import schema from './schema.json';
import uischema from './uischema.json';
import {
  materialCells,
  materialRenderers,
} from '@jsonforms/material-renderers';
import RatingControl from './RatingControl';
import ratingControlTester from './ratingControlTester';
import { makeStyles } from '@mui/styles';

const useStyles = makeStyles({
  container: {
    padding: '1em',
    width: '100%',
  },
  title: {
    textAlign: 'center',
    padding: '0.25em',
  },
  dataContent: {
    display: 'flex',
    justifyContent: 'center',
    borderRadius: '0.25em',
    backgroundColor: '#cecece',
    marginBottom: '1rem',
  },
  resetButton: {
    margin: 'auto !important',
    display: 'block !important',
  },
  demoform: {
    margin: 'auto',
    padding: '1rem',
  },
});

const initialData = {
  name: 'Send email to Adrian',
  description: 'Confirm if you have passed the subject\nHereby ...',
  done: true,
  recurrence: 'Daily',
  rating: 3,
};

const renderers = [
  ...materialRenderers,
  //register custom renderers
  { tester: ratingControlTester, renderer: RatingControl },
];

const App = () => {
  const classes = useStyles();
  const [data, setData] = useState<any>(initialData);
  const stringifiedData = useMemo(() => JSON.stringify(data, null, 2), [data]);

  const clearData = () => {
    setData({});
  };

  return (
    <Fragment>
      <div className='App'>
        <header className='App-header'>
          <img src={logo} className='App-logo' alt='logo' />
          <h1 className='App-title'>Welcome to JSON Forms with React</h1>
          <p className='App-intro'>More Forms. Less Code.</p>
        </header>
      </div>

      <Grid
        container
        justifyContent={'center'}
        spacing={1}
        className={classes.container}
      >
        <Grid item sm={6}>
          <Typography variant={'h4'} className={classes.title}>
            Bound data
          </Typography>
          <div className={classes.dataContent}>
            <pre id='boundData'>{stringifiedData}</pre>
          </div>
          <Button
            className={classes.resetButton}
            onClick={clearData}
            color='primary'
            variant='contained'
          >
            Clear data
          </Button>
        </Grid>
        <Grid item sm={6}>
          <Typography variant={'h4'} className={classes.title}>
            Rendered form
          </Typography>
          <div className={classes.demoform}>
            <JsonForms
              schema={schema}
              uischema={uischema}
              data={data}
              renderers={renderers}
              cells={materialCells}
              onChange={({ errors, data }) => setData(data)}
            />
          </div>
        </Grid>
      </Grid>
    </Fragment>
  );
};

export default App;

解决方案

一、定位Emotion的CSS修改定义

  • Chrome DevTools溯源:
    1. 打开Chrome DevTools,找到Emotion生成的<style>标签,右键选择「检查」,在Styles面板找到对应的body样式规则。
    2. 点击规则右侧的文件链接(类似emotion-styles-xxx.js),直接跳转到生成该样式的代码位置。
  • 排查依赖链:
    项目中使用的@mui/material和@jsonforms/material-renderers会通过Emotion注入全局重置样式(比如MUI的CssBaseline组件),可以检查JsonForms的material渲染器是否自动引入了这类组件。

二、配置组件避免影响全局元素

方法1:限定MUI全局样式作用范围

给React应用根节点加唯一类名(比如jsonforms-container),通过MUI的ThemeProvider自定义主题,把全局样式限制在容器内:

import { createTheme, ThemeProvider } from '@mui/material/styles';
import CssBaseline from '@mui/material/CssBaseline';

const theme = createTheme({
  components: {
    MuiCssBaseline: {
      styleOverrides: {
        '.jsonforms-container': {
          // 自定义局部重置样式,或留空避免全局覆盖
          fontFamily: 'inherit',
        },
      },
    },
  },
});

const WrappedApp = () => (
  <ThemeProvider theme={theme}>
    <div className="jsonforms-container">
      <CssBaseline />
      <App />
    </div>
  </ThemeProvider>
);

export default WrappedApp;

方法2:用Emotion的CacheProvider隔离样式

通过CacheProvider指定样式只注入到React根容器内:

import { CacheProvider } from '@emotion/react';
import createCache from '@emotion/cache';

// 创建自定义缓存,限定样式注入容器
const cache = createCache({
  key: 'jsonforms-cache',
  container: document.getElementById('root'),
});

const WrappedApp = () => (
  <CacheProvider value={cache}>
    <App />
  </CacheProvider>
);

export default WrappedApp;

方法3:修改JsonForms渲染器配置

查阅@jsonforms/material-renderers文档,看是否有开关可以禁用默认的全局样式注入,部分渲染器会提供此类配置项。


内容的提问来源于stack exchange,提问作者Bioman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 08:13:18