Material-ui 样式在使用 useMediaQuery 挂钩切换 light/dark 主题时被覆盖
Material-ui style getting overwritten when switching light/dark theme using useMediaQuery hook
我正在使用 next.js 和 material-ui,并根据用户偏好更改主题。
但是似乎当切换到灯光模式时,我设置的样式(使用 JSS)将被覆盖,只有在使用灯光模式时才会发生这种情况我什至试图反转两个主题,但它不起作用。经过大量尝试后,我发现当更改 system/browser 以使用不同于 useMediaQuery() 挂钩中设置的主题时,问题就会发生。
const isInDarkMode = useMediaQuery("(prefers-color-scheme: dark)");
(比如set prefers-color-scheme to dark, light theme会导致Styles被覆盖。)但是我还是不知道为什么会这样,如何避免。
编辑:手动设置 isInDarkMode = false 后,无论模式如何,样式都会被覆盖..所以可能 useMediaQuery 没有导致问题但实际上有点解决问题..?
编辑我尝试将此应用程序部署到vercel后,主页在所有颜色模式下都完全正常,通过getStaticPaths()生成的部分页面仍然存在问题。
这在 iOS 上的 Safari 和 Windows 上的 Chrome 上都进行了测试,所有问题都出现了。
我用来设置主题的代码(我在_app.js中设置):
import Header from "../components/Header";
import React from "react";
import useMediaQuery from "@material-ui/core/useMediaQuery";
import { createTheme, ThemeProvider } from "@material-ui/core/styles";
import CssBaseline from "@material-ui/core/CssBaseline";
import "../styles/global.css";
function MyApp({ Component, pageProps }) {
const isInDarkMode = useMediaQuery("(prefers-color-scheme: dark)");
const theme = React.useMemo(
() =>
createTheme({
spacing: 8,
palette: {
type: isInDarkMode ? "dark" : "light",
primary: {
main: isInDarkMode ? "#8A6BBE" : "#6F3381",
},
secondary: {
main: "#CB4042",
},
background: {
default: isInDarkMode ? "#1c1c1c" : "#fffffb",
},
},
typography: {
h3: {
fontFamily: "Source Serif Pro, serif",
fontWeight: "600",
fontSize: "2.2rem",
"@media (min-width:600px)": {
fontSize: "3rem",
},
},
},
}),
[isInDarkMode]
);
return (
<>
<ThemeProvider theme={theme}>
<CssBaseline />
<Header isInDarkMode={isInDarkMode} />
<Component {...pageProps} />
</ThemeProvider>
</>
);
}
export default MyApp;
(试过不用useMemo,但没有解决问题。)
const useStyles = makeStyles({
root: {
maxWidth: 345,
backgroundColor: "rgba(255, 255, 255, 0)",
border: "1px solid rgba(138, 107, 190, 0.7)",
borderRadius: "8px",
},
});
(Style的一个例子,该问题会导致所有样式被覆盖,包括maxWidth、BackgroundColor和border/borderRadius)
问题解决了!它似乎是由于没有删除服务器端注入 CSS 引起的。我按照教程 Here
供参考,这些是我的 _document.js
import React from "react";
import Document, { Html, Head, Main, NextScript } from "next/document";
import { ServerStyleSheets } from "@material-ui/core/styles";
export default class MyDocument extends Document {
render() {
return (
<Html lang="en">
<Head></Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
// `getInitialProps` belongs to `_document` (instead of `_app`),
// it's compatible with server-side generation (SSG).
MyDocument.getInitialProps = async (ctx) => {
// Resolution order
//
// On the server:
// 1. app.getInitialProps
// 2. page.getInitialProps
// 3. document.getInitialProps
// 4. app.render
// 5. page.render
// 6. document.render
//
// On the server with error:
// 1. document.getInitialProps
// 2. app.render
// 3. page.render
// 4. document.render
//
// On the client
// 1. app.getInitialProps
// 2. page.getInitialProps
// 3. app.render
// 4. page.render
// Render app and page and get the context of the page with collected side effects.
const sheets = new ServerStyleSheets();
const originalRenderPage = ctx.renderPage;
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) => sheets.collect(<App {...props} />),
});
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
// Styles fragment is rendered after the app and page rendering finish.
styles: [
...React.Children.toArray(initialProps.styles),
sheets.getStyleElement(),
],
};
};
和_app.js
import Header from "../components/Header";
import React from "react";
import useMediaQuery from "@material-ui/core/useMediaQuery";
import { createTheme, ThemeProvider } from "@material-ui/core/styles";
import CssBaseline from "@material-ui/core/CssBaseline";
import { lightTheme, darkTheme } from "../utils/themes/Theme";
import "../styles/global.css";
function MyApp({ Component, pageProps }) {
const isInDarkMode = useMediaQuery("(prefers-color-scheme: dark)");
React.useEffect(() => {
// Remove the server-side injected CSS.
const jssStyles = document.querySelector("#jss-server-side");
if (jssStyles) {
jssStyles.parentElement.removeChild(jssStyles);
}
}, []);
return (
<ThemeProvider theme={isInDarkMode ? darkTheme : lightTheme}>
<CssBaseline />
<Header isInDarkMode={isInDarkMode} />
<Component {...pageProps} />
</ThemeProvider>
);
}
export default MyApp;
(我改为在不同的文件中创建主题,但它应该是可选的)
我正在使用 next.js 和 material-ui,并根据用户偏好更改主题。
但是似乎当切换到灯光模式时,我设置的样式(使用 JSS)将被覆盖,只有在使用灯光模式时才会发生这种情况我什至试图反转两个主题,但它不起作用。经过大量尝试后,我发现当更改 system/browser 以使用不同于 useMediaQuery() 挂钩中设置的主题时,问题就会发生。
const isInDarkMode = useMediaQuery("(prefers-color-scheme: dark)");
(比如set prefers-color-scheme to dark, light theme会导致Styles被覆盖。)但是我还是不知道为什么会这样,如何避免。
编辑:手动设置 isInDarkMode = false 后,无论模式如何,样式都会被覆盖..所以可能 useMediaQuery 没有导致问题但实际上有点解决问题..?
编辑我尝试将此应用程序部署到vercel后,主页在所有颜色模式下都完全正常,通过getStaticPaths()生成的部分页面仍然存在问题。
这在 iOS 上的 Safari 和 Windows 上的 Chrome 上都进行了测试,所有问题都出现了。
我用来设置主题的代码(我在_app.js中设置):
import Header from "../components/Header";
import React from "react";
import useMediaQuery from "@material-ui/core/useMediaQuery";
import { createTheme, ThemeProvider } from "@material-ui/core/styles";
import CssBaseline from "@material-ui/core/CssBaseline";
import "../styles/global.css";
function MyApp({ Component, pageProps }) {
const isInDarkMode = useMediaQuery("(prefers-color-scheme: dark)");
const theme = React.useMemo(
() =>
createTheme({
spacing: 8,
palette: {
type: isInDarkMode ? "dark" : "light",
primary: {
main: isInDarkMode ? "#8A6BBE" : "#6F3381",
},
secondary: {
main: "#CB4042",
},
background: {
default: isInDarkMode ? "#1c1c1c" : "#fffffb",
},
},
typography: {
h3: {
fontFamily: "Source Serif Pro, serif",
fontWeight: "600",
fontSize: "2.2rem",
"@media (min-width:600px)": {
fontSize: "3rem",
},
},
},
}),
[isInDarkMode]
);
return (
<>
<ThemeProvider theme={theme}>
<CssBaseline />
<Header isInDarkMode={isInDarkMode} />
<Component {...pageProps} />
</ThemeProvider>
</>
);
}
export default MyApp;
(试过不用useMemo,但没有解决问题。)
const useStyles = makeStyles({
root: {
maxWidth: 345,
backgroundColor: "rgba(255, 255, 255, 0)",
border: "1px solid rgba(138, 107, 190, 0.7)",
borderRadius: "8px",
},
});
(Style的一个例子,该问题会导致所有样式被覆盖,包括maxWidth、BackgroundColor和border/borderRadius)
问题解决了!它似乎是由于没有删除服务器端注入 CSS 引起的。我按照教程 Here
供参考,这些是我的 _document.js
import React from "react";
import Document, { Html, Head, Main, NextScript } from "next/document";
import { ServerStyleSheets } from "@material-ui/core/styles";
export default class MyDocument extends Document {
render() {
return (
<Html lang="en">
<Head></Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
}
// `getInitialProps` belongs to `_document` (instead of `_app`),
// it's compatible with server-side generation (SSG).
MyDocument.getInitialProps = async (ctx) => {
// Resolution order
//
// On the server:
// 1. app.getInitialProps
// 2. page.getInitialProps
// 3. document.getInitialProps
// 4. app.render
// 5. page.render
// 6. document.render
//
// On the server with error:
// 1. document.getInitialProps
// 2. app.render
// 3. page.render
// 4. document.render
//
// On the client
// 1. app.getInitialProps
// 2. page.getInitialProps
// 3. app.render
// 4. page.render
// Render app and page and get the context of the page with collected side effects.
const sheets = new ServerStyleSheets();
const originalRenderPage = ctx.renderPage;
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) => sheets.collect(<App {...props} />),
});
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
// Styles fragment is rendered after the app and page rendering finish.
styles: [
...React.Children.toArray(initialProps.styles),
sheets.getStyleElement(),
],
};
};
和_app.js
import Header from "../components/Header";
import React from "react";
import useMediaQuery from "@material-ui/core/useMediaQuery";
import { createTheme, ThemeProvider } from "@material-ui/core/styles";
import CssBaseline from "@material-ui/core/CssBaseline";
import { lightTheme, darkTheme } from "../utils/themes/Theme";
import "../styles/global.css";
function MyApp({ Component, pageProps }) {
const isInDarkMode = useMediaQuery("(prefers-color-scheme: dark)");
React.useEffect(() => {
// Remove the server-side injected CSS.
const jssStyles = document.querySelector("#jss-server-side");
if (jssStyles) {
jssStyles.parentElement.removeChild(jssStyles);
}
}, []);
return (
<ThemeProvider theme={isInDarkMode ? darkTheme : lightTheme}>
<CssBaseline />
<Header isInDarkMode={isInDarkMode} />
<Component {...pageProps} />
</ThemeProvider>
);
}
export default MyApp;
(我改为在不同的文件中创建主题,但它应该是可选的)