Material UI组件中的媒体查询

98

我在一个React.js项目中使用Material UI组件,由于某些原因,我需要对一些组件进行自定义以使其根据屏幕宽度响应。

我已经添加了媒体查询并将其作为样式属性传递给组件,但不起作用,有什么想法吗?

我正在使用类似这样的代码:

const drawerWidth = {
  width: '50%',
  '@media(minWidth: 780px)' : {
    width: '80%'
  }
}

<Drawer
  .....
  containerStyle = {drawerStyle}
 >
 </Drawer>

这段代码只在网页上有效,在移动设备上没有效果。即使我在开发者控制台中检查了CSS代码也没有应用。我正在使用Material UI版本0.18.7

任何帮助将不胜感激。

PS:根据屏幕大小的要求,我需要使用CSS进行一些更改。


如何在声明块中定义React,您能举个例子吗?我对React还很陌生。 - Pardeep Jain
10个回答

160
通过使用主题的断点属性,您可以直接在组件中利用网格和隐藏组件中使用的相同断点。 API
theme.breakpoints.up(key) => media query

参数

key (字符串 | 数字): 断点键(xs,sm等)或屏幕宽度像素数。

返回值 媒体查询: 一个可用于 JSS 的媒体查询字符串。

示例

const styles = theme => ({
  root: {
    backgroundColor: 'blue',
    [theme.breakpoints.up('md')]: {
      backgroundColor: 'red',
    },
  },
});

欲了解更多信息请查看此处


5
这应该是答案。 - AndrewMcLagan
13
["@media (min-height:800px)"]: { marginTop: 10 } 译作:["@media (min-height:800px)"]:{marginTop:10} - Deepak Singh

94

你的理解基本正确,但需要使用 min-width 而不是 minWidth


const styles = {
  drawerWidth: {
    width: '50%',
    '@media (min-width: 780px)': {
      width: '80%'
    }
  }
}

3
好的回答。请参考 https://github.com/mui-org/material-ui/blob/master/packages/material-ui/src/styles/createBreakpoints.js#L24,可以看到 up()down() 方法输出的字符串与答案中所示的一样,都在方括号内。 - nbkhope
16
在数组中使用媒体查询@media (min-width:780px)会产生no-useless-computed-key警告。只需使用@media (min-width:780px)即可解决问题。 - Deke
这个对我有用:const sx = {'@media (min-width: 780px)': { width: '80%' }}; 返回<Box sx={sx}>...</Box>; - Damien Golding

42

您在媒体查询中有一个错别字。您应该使用以下语法,它会按预期工作:

const drawerWidth = {
  width: '50%',
  '@media (min-width: 780px)' : {
    width: '80%'
  }
}

代替

const drawerWidth = {
  width: '50%',
  '@media(minWidth: 780px)' : {
    width: '80%'
  }
}

亲爱的@croraf,请将您的答案放在大括号中,就像这样:['@media (min-width: 780px)']。如果没有大括号,您的答案还不能正常工作。谢谢。 - AmerllicA
3
谢谢你的建议。我觉得没有它们也可以运行。只有在字符串内包含变量时才需要花括号,这样它才能被解析,但是在这种情况下是一个字符串,所以不需要花括号。 - croraf
这是正确的答案。 - Mattia Rasulo
这确实是正确的答案。 - AndrewLeonardi

30
MUI v5 中,可以通过指定一个对象来声明断点,其中键是断点名称,值是 CSS 值,在sx props 中。您可以在此处查看 MUI 的默认断点。使用createTheme(),可以覆盖断点名称和值:
const theme = createTheme({
  breakpoints: {
    values: {
      xxs: 0, // small phone
      xs: 300, // phone
      sm: 600, // tablets
      md: 900, // small laptop
      lg: 1200, // desktop
      xl: 1536 // large screens
    }
  }
});
return (
  <ThemeProvider theme={theme}>
    <Box
      sx={{
        // specify one value that is applied in all breakpoints
        color: 'white',
        // specify multiple values applied in specific breakpoints
        backgroundColor: {
          xxs: "red",
          xs: "orange",
          sm: "yellow",
          md: "green",
          lg: "blue",
          xl: "purple"
        }
      }}
    >
      Box 1
    </Box>
  </ThemeProvider>
);
在上面的示例中,xs: "orange" 表示如果屏幕宽度在 [300, 600) 范围内,则将 Box 的颜色设置为橙色。您还可以使用由最小断点到最大断点值组成的数组来设置断点大小:
return (
  <ThemeProvider theme={theme}>
    <Box
      sx={{
        backgroundColor: [
          "red",
          "orange",
          // unset, screen width inside this breakpoint uses the last non-null value
          null,
          "green",
          "blue",
          "purple"
        ]
      }}
    >
      Box 2
    </Box>
  </ThemeProvider>
);

Edit 45847090/media-queries-in-material-ui-components


1
谢谢!这对于简洁的语法非常好。 - artidataio
1
这应该是被批准的答案! - hahuaz
非常棒的解决方案。只有 xxs 断点不是默认值,也许需要从示例中删除它。 - Karl Adler
它可以工作,但我建议使用Croraf的媒体查询答案。 - AndrewLeonardi

11

基于@nbkhope的评论,类似于@Lipunov的答案

const styles = {
  drawerWidth: {
    width: '50%',
    [theme.breakpoints.up(780)]: {
      width: '80%'
    }
  }
}

5
我通过以下方式解决了这个问题:
const dropzoneStyles = 
window.screen.availWidth < 780 ? 
{ 'width': '150px', 'height': '150px', 'border': 'none', 'borderRadius': '50%' }
: { 'width': '200px', 'height': '200px', 'border': 'none', 'borderRadius': '50%' };

然后将其作为属性附加到Material UI元素中:

<Dropzone style={dropzoneStyles} onDrop={this.handleDrop.bind(this)}>

因此,关键是找出窗口屏幕使用window.screen.availWidth。您将在render()函数中执行此操作。希望这可以帮助!


5
在我的情况下,我只需要在一个组件上设置断点,因此我认为使用createTheme有点过于繁琐。我最终使用了useMediaQueryuseTheme
我发现使用useMediaQuery可以非常精细地设置断点。
import { useTheme } from '@mui/material/styles';
import useMediaQuery from '@mui/material/useMediaQuery';

const Component = () => {
  const theme = useTheme();
  const matchesSM = useMediaQuery(theme.breakpoints.down('sm'));
  const matchesMD = useMediaQuery(theme.breakpoints.only('md'));
  const dynamicStyles = {
    ...matchesSM && {margin: '10px 0'},
    ...matchesMD && {margin: '20px 0'}
  }

  return (
    <Grid item xs={12} md={4} sx={{...dynamicStyles}}>
      <div>Children</div>
    </Grid>
  )
}

3

在React的样式属性中,您只能定义普通DOM元素中可以定义的属性(例如,您不能包含媒体查询)

您可以通过向抽屉组件传递类名的方式来包含该组件的媒体查询。

<Drawer containerClassName="someClass" /> 

在 CSS 文件中,您需要执行以下操作:
@media(min-width: 780px){
  .someClass {
    width: 50%!important;
  }
}

我知道这一点,但这没有任何意义,它只会将CSS类添加到那个容器而不是内部元素或需要的容器,不是吗? - Pardeep Jain
抱歉,应该使用containerClassName而不是className(更新答案),这将向抽屉容器添加类,然后您可以轻松地使用CSS修改其宽度。 - Miguel
我只是举了这个(抽屉)作为例子,在任何情况下我的媒体查询都不起作用。 - Pardeep Jain
似乎抽屉向容器添加了内联样式,以便样式具有更高的优先级,你可以尝试在宽度末尾使用!important。 - Miguel
是的,我同意它可以在父容器上工作,但不适用于该容器的子元素。而且这也不是首选的方法。 - Pardeep Jain
这个答案应该被删除,它依赖于外部CSS文件而不是正确使用主题断点。如果你只是使用纯CSS,就不需要使用框架。 - Husk Rekoms

2
CSS媒体查询是使您的UI响应的惯用方法。该主题提供了五个样式助手来实现:

theme.breakpoints.up(key)
theme.breakpoints.down(key)
theme.breakpoints.only(key)
theme.breakpoints.not(key)
theme.breakpoints.between(start, end)

在下面的压力测试中,您可以实时更新主题颜色和background-color属性:
const styles = (theme) => ({
  root: {
    padding: theme.spacing(1),
    [theme.breakpoints.down('md')]: {
      backgroundColor: theme.palette.secondary.main,
    },
    [theme.breakpoints.up('md')]: {
      backgroundColor: theme.palette.primary.main,
    },
    [theme.breakpoints.up('lg')]: {
      backgroundColor: green[500],
    },
  },
});

<Root>
  <Typography>down(md): red</Typography>
  <Typography>up(md): blue</Typography>
  <Typography>up(lg): green</Typography>
</Root>

了解更多


1
创建一个变量,然后在函数中任何地方使用该变量。
import React from 'react';
import { createMuiTheme, ThemeProvider, useTheme } from '@materialui/core/styles';
import useMediaQuery from '@material-ui/core/useMediaQuery';
    

function MyComponent() {
  const theme = useTheme();
  const matches = useMediaQuery(theme.breakpoints.up('sm')); // Variable for media query 
  return <span hidden={matches}>Hidden on screen size greater then sm </span>;
}

const theme = createMuiTheme();

export default function ThemeHelper() {
  return (
    <ThemeProvider theme={theme}>
      <MyComponent />
    </ThemeProvider>
  );
}

阅读 Material ui 文档 https://material-ui.com/components/use-media-query/ - Syed Ali Shahzil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接