问题描述
序言
我问了类似的问题追溯到这几天,尽管本质上是相关的,但我认为解决方案最终将有所不同,因此我在不同的话题中再次提出疑问.
I asked a similar question to this several days back and while related in nature I believe the solution will ultimately be different, so I am asking again in a different thread.
CodeSanbox 示例(已更新以反映已接受的答案)
CodeSanbox Example (Has Been updated to reflect the accepted answer)
问题:
我希望通过className
道具传递的任何外部样式都比我的自定义组件内部样式具有更高的特异性.这样,使用它的人就可以调整边距和填充.但是,我组件的默认内部样式会覆盖我的外部样式,我希望反之亦然.
I'd like any external styles passed in with the className
prop to have higher specificity than my custom components internal style. That way someone using it can adjust margins and padding. However, my components default internal style is overwriting my external style and I would like it to be the other way around.
详细信息:
我正在创建一个基于material-ui的自定义组件库.我想使自定义组件api与@material-ui
类似,以便我们的开发人员可以更轻松地使用它们.我正在构建的每个组件都具有其自己的内部样式,该样式将覆盖默认的material-ui样式,在这种情况下,它定义为类button
.另外,像@material-ui
一样,我接受颜色道具<TestButton color={'default'}/>
.最后,如果需要,我希望可以使用外部样式覆盖自定义按钮.我正在使用clsx
库来构建className字符串.
I am creating a custom component library built on top of material-ui. I'd like to make the custom components api similar to @material-ui
so that our devs will find them easier to use. Each component I am building has it's own internal style overwriting the default material-ui styles in this case it is defined as class button
. Additionally, like @material-ui
I am accepting a color prop <TestButton color={'default'}/>
. Finally, I'd like my custom button to be allowed to be overwritten with external styles if the need ever arises. I am using the clsx
library to build the className strings.
代码:
import React, { useState } from "react";
import { makeStyles } from "@material-ui/styles";
import InputLabel from "@material-ui/core/InputLabel";
import MenuItem from "@material-ui/core/MenuItem";
import FormControl from "@material-ui/core/FormControl";
import { Button } from "@material-ui/core";
import clsx from "clsx";
const useAppStyles = makeStyles({
gButton: { margin: "150px" }
});
export default function App() {
const classes = useAppStyles();
return (
<div className={classes.example}>
<div className={classes.separator}>
<div>Buttons:</div>
<TestButton
className={classes.gButton}
color={"default"}
>
Default
</TestButton>
<TestButton
className={classes.gButton}
color={"primary"}
>
Primary
</TestButton>
</div>
);
}
function TestButton(props) {
const classes = GrangeButtonStyles();
let color = props.color === 'default' ? classes.default : classes.primary
const GrangeButtonStyles = makeStyles({
button: {
height: "45px",
padding: "13px 30px 13px 30px",
borderRadius: "5px",
border: "none",
margin: "15px",
},
default: {
backgroundColor: "black",
border: 'solid #2e7d32 1px',
color: "white",
},
primary: {
backgroundColor: 'white',
color: 'black',
fontFamily: 'Montserrat, sans-serif',
border: 'solid black 1px',
}
});
return (
<Button
className={clsx(classes.button, color, props.className)}
variant="contained"
disabled={props.disabled}
disableElevation
>
{props.children}
</Button>
);
}
注意:
在这个问题和代码沙箱示例中,我大大简化了空间代码.请不要发表评论,因为这个例子,您认为我在做什么并没有意义.
I have simplified the code greatly for space in this question and in the code sandbox example. Please don't comment that you think what I'm doing doesn't make sense because of the example.
推荐答案
来自 https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity :
因此,在您要在自定义组件(例如TestButton
)和使用该组件的代码中定义CSS类的情况下,其特异性取决于这些CSS类在<head>
中出现的顺序.元素.此顺序由在调用makeStyles时设置的索引,因此以后调用makeStyles
定义的类将稍后出现在<head>
元素中,因此具有更大的特异性.
So in your case where you are defining CSS classes in your custom component (e.g. TestButton
) and in the code that uses that component, the specificity is determined by the order in which those CSS classes appear within the <head>
element. This order is determined by an index that is set when makeStyles is called, so classes defined by later calls to makeStyles
will appear later in the <head>
element and thus have greater specificity.
在您的示例中有两个问题:
There are two issues then in your example:
-
TestButton
是在使用它的代码之后定义的,因此在makeStyles
调用之后定义了旨在覆盖TestButton
中的样式的样式.由于对gButton
的makeStyles
调用首先发生,因此相应的CSS类将首先在<head>
元素中.但是,在实际使用中,TestButton
(您的自定义组件)将在单独的文件中定义并导入.由于导入必须位于最顶层,因此在使用导入的组件对文件中的任何makeStyles
调用之前,将执行导入文件的所有makeStyles
顶级调用.
TestButton
is defined after the code that uses it and therefore after themakeStyles
call that is defining styles intended to override styles inTestButton
. Since themakeStyles
call forgButton
occurs first, the corresponding CSS class will be first in the<head>
element. In real-world usage though,TestButton
(your custom component) would be defined in a separate file and be imported. Since imports have to be at the top, anymakeStyles
calls at the top level of the imported file will be executed before anymakeStyles
calls in the file using the imported component.
TestButton
的makeStyles
调用不是在最顶层完成的.相反,它是在TestButton
函数内部完成的,这意味着它将在呈现TestButton
时而不是在导入TestButton
时执行.对makeStyles
的调用应始终位于顶层,而不是嵌套在组件函数中.另一个较小的问题是从makeStyles
返回的变量的名称(在您的示例中为GrangeButtonStyles
).由于makeStyles
返回自定义钩子,因此您应始终以"use"开头的名称(例如useGrangeButtonStyles
).这样可以确保挂钩的限制规则将其识别为挂钩并警告您任何钩子滥用.
The makeStyles
call for TestButton
is not being done at the top level. Instead it is being done inside the TestButton
function which means it will be executed when TestButton
is rendered instead of when TestButton
is imported. Calls to makeStyles
should always be at the top level rather than nested within a component function. One other minor issue is the name of the variable returned from makeStyles
(i.e. GrangeButtonStyles
in your example). Since makeStyles
returns a custom hook, you should always have a name that starts with "use" (e.g. useGrangeButtonStyles
). This will ensure that the eslint rules for hooks recognize it as a hook and warn you of any hook misuse.
相关答案和参考文献:
- 从单个文件导出的材料UI v4 makeStyles不会在刷新时保留样式
- 内部实现"makeStyles"在React Material-UI中?
- https://developer.mozilla.org/zh-CN /docs/Web/CSS/Specificity
- Material UI v4 makeStyles exported from a single file doesn't retain the styles on refresh
- Internal implementation of "makeStyles" in React Material-UI?
- https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity
这篇关于样式被Material-UI样式覆盖的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!