如何使用Tailwind为Material UI Dialog组件正确设置样式?
问题根源
Tailwind 类名模式的深色变体默认生成的是后代选择器规则,比如你写的dark:bg-zinc-700最终编译出来的CSS是:
.dark .dark\:bg-zinc-700 { background-color: rgb(63 63 70); }
这个规则要求带dark:xxx类名的元素,必须是携带dark类元素的后代节点才能命中样式。
MUI Dialog 基于Portal实现,默认会把DOM结构插到body标签的末尾,完全脱离了你添加dark类的root内部顶层容器的DOM树,Dialog元素的祖先链里根本找不到带dark类的节点,哪怕类名已经正确加到了DOM上,样式规则也匹配不上,自然不会生效。
可行解决方案
以下方案全部不需要使用MUI的sx属性,完全保留Tailwind的原有写法习惯,按推荐度从高到低排序:
- 全局调整dark类挂载位置(最推荐,一劳永逸)
把深色模式的标识类dark从root容器内的顶层元素,转移到<html>或者<body>标签上。这也是Tailwind官方对类名模式深色模式的标准推荐用法,所有页面元素——包括通过Portal挂载的弹窗、下拉菜单、全局提示这类脱离原DOM层级的组件——都属于html/body的后代节点,dark变体规则可以正常命中,不需要修改任何现有业务组件的写法,切换主题时直接操作html或body的类名即可。 - 单独指定Dialog的挂载容器
如果因为项目架构原因不方便调整全局dark类的挂载位置,可以给Dialog组件加container属性,手动指定它通过Portal渲染到你已经加了dark类的顶层容器内部,让Dialog重新处于dark类的DOM子树中,参考写法:
注意要确保传入import { useRef, useState } from 'react' import Dialog from '@mui/material/Dialog' export default function Page() { const [open, setOpen] = useState(false) // 绑定项目中携带dark类的顶层容器 const appRootRef = useRef(null) return ( <div ref={appRootRef} className="dark"> <button onClick={() => setOpen(true)}>打开弹窗</button> <Dialog open={open} onClose={() => setOpen(false)} // 指定弹窗挂载到带dark类的容器下 container={appRootRef.current} PaperProps={{ className: "dark:bg-zinc-700" }} > 弹窗内容 </Dialog> </div> ) }container的时候目标DOM节点已经完成挂载,避免出现节点不存在的运行时报错。 - 全局配置MUI Portal默认挂载点
如果项目中大量使用Dialog、Popover、Tooltip这类带Portal的MUI浮层组件,可以通过MUI的主题配置统一修改所有Portal组件的默认挂载容器,不用给每个组件单独加container属性,配置完成后所有浮层都会默认渲染到你指定的带dark类的容器下,dark变体可以正常生效。
内容的提问来源于stack exchange,提问作者Hossein Fallah
相关产品推荐
相关产品推荐

