Material UI 容器查询实战:theme.containerQueries 与 sx “@” 简写语法

📅 发布时间:2026/9/7 9:25:29
Material UI 容器查询实战:theme.containerQueries 与 sx “@” 简写语法 Material UI 容器查询实战theme.containerQueries 与 sx “” 简写语法【免费下载链接】material-uiMaterial UI: Comprehensive React component library that implements Googles Material Design. Free forever.项目地址: https://gitcode.com/GitHub_Trending/ma/material-ui本文基于 Material UI 官方文档 container-queries.md系统讲解theme.containerQueries的完整 API、sx属性中size/size/name简写语法的规则与陷阱并结合 packages/mui-system 源码揭示其底层实现机制。读完本文你可以直接在组件库中写出“根据父容器宽度而非视口宽度”进行响应的样式并理解 Media Query 方法如何被复用到 Container Query 场景。为什么需要容器查询传统的theme.breakpoints生成的media规则判断的是浏览器视口宽度而 CSS Container Query 判断的是元素所在容器的宽度。这使得同一组件放在侧边栏、主内容区或弹层中时能各自独立地调整布局——这正是 BasicContainerQueries.tsx 演示的“卡片在 350px / 500px 容器断点处切换横排/竖排”的场景。Material UI 的用法约定很直接使用theme.containerQueries加上theme.breakpoints的任意方法即可。传入的取值支持三种形式无单位数字按像素渲染350等价于350px字符串如500px、40rem断点键如sm、md复用主题断点的像素值。theme.containerQueries.up(sm); // container (min-width: 600px)前置条件必须有一个祖先元素声明了容器类型如containerType: inline-size否则容器查询不生效。官方演示中是在外层Box上通过sx写入containerType: inline-size来启用该能力。完整的 API与 breakpoints 一一对应容器查询支持断点 API 的全部方法且断点取值直接继承主题的breakpoints.values默认为xs: 0, sm: 600, md: 900, lg: 1200, xl: 1536单位px调用输出默认断点theme.containerQueries.up(sm)container (min-width: 600px)theme.containerQueries.down(md)container (max-width: 899.95px)theme.containerQueries.only(md)container (min-width: 600px) and (max-width: 1199.95px)theme.containerQueries.between(sm, lg)container (min-width: 600px) and (max-width: 1199.95px)theme.containerQueries.not(sm)container (max-width: 600px)见下文范围语法说明这里有一个值得注意的细节down/between/not生成的max-width会减去step / 100默认step: 5即减0.05。这个机制源自 createBreakpoints.ts 中down的实现(value) - step / 100目的是让相邻断点互斥up(sm)与down(sm)不重叠。单元测试 cssContainerQueries.test.ts 明确断言了down(sm)等于container (max-width:599.95px)所以文档示例中书写的900px只是约数实际渲染值是899.95px。命名容器Named containment contexts若 DOM 中存在命名容器可以在调用containerQueries时传入容器名称访问同一套断点方法theme.containerQueries(sidebar).up(500px); // container sidebar (min-width: 500px)从源码结构看实现位于 cssContainerQueries.tscontainerQueries本身既是对象直接调用up/down/...又是一个函数——传入name后返回一个“附着”了同名方法的节点。核心的toContainerQuery只做字符串替换把断点方法生成的media ...替换为container ...或container name ...因此它能天然继承 breakpoints 的全部取值逻辑包括断点键解析、step偏移等。实战示例一styled 方式配合主题断点以下代码完整来自 BasicContainerQueries.tsx展示了一张房产卡片随容器宽度变化的布局容器小于 350px 时图片在上、内容在下flexDirection: column达到 350px 时切换为横排达到 500px 时图片宽度锁定为 240px、内容区内边距加大。import { styled } from mui/material/styles; import Box from mui/material/Box; import Card from mui/material/Card; import CardContent from mui/material/CardContent; const DynamicCard styled(Card)(({ theme }) ({ display: flex, flexDirection: column, [theme.containerQueries.up(350)]: { flexDirection: row, }, })); const Image styled(img)(({ theme }) ({ alignSelf: stretch, aspectRatio: 16 / 9, objectFit: cover, width: 100%, maxHeight: 160, transition: 0.4s, [theme.containerQueries.up(350)]: { maxWidth: 36%, maxHeight: initial, }, [theme.containerQueries.up(500)]: { maxWidth: 240, }, })); const Content styled(CardContent)(({ theme }) ({ display: flex, flexDirection: column, gap: theme.spacing(1), padding: theme.spacing(2), flex: auto, transition: padding 0.4s, [theme.containerQueries.up(500)]: { padding: theme.spacing(3), }, })); export default function BasicContainerQueries() { return ( Box sx{{ overflow: auto, resize: horizontal, // 允许用户拖动改变容器宽度 width: 400, maxWidth: min(80vw, 600px), containerType: inline-size, // required for container queries }} DynamicCard variantoutlined Image altThe house from the offer. src... / Content{/* ... 卡片内容 ... */}/Content /DynamicCard /Box ); }演示页面配套的 ResizableDemo.js 会在 0px、350px、500px 三个位置画出虚线参考线方便读者拖动容器时直观看到两个断点的触发位置。实战示例二sx 属性的简写语法在sx中使用时不必显式引用主题直接在样式值对象里用size或size/name作为键即可生成容器查询无需引用主题。size一个宽度值数字或带单位字符串或断点键name可选命名容器上下文。以下代码取自 SxPropContainerQueries.tsx与上一节的 styled 版本等价但完全内联在sx中Card variantoutlined sx{{ display: flex, flexDirection: { : column, // 容器任意宽度时等价 container 0px 起点 350: row, // 容器 350px 时 }, }} Box componentimg sx{{ maxHeight: { : 160, 350: initial }, maxWidth: { 350: 36%, 500: 240 }, }} / CardContent sx{{ padding: { : 2, 500: 3 }, // 简写值 2/3 走 spacing 换算 }} / /Card简写语法的三个关键规则Caveats无单位数值按px渲染500等价于500px但500px是错误写法不会被正确渲染——前缀场景下不要再带px单位。裸渲染为0px: value表示“容器查询始终命中”的基准样式min-width: 0px。同一组容器查询必须使用相同单位且排序按数值大小而非单位换算// ✅ 单位一致能按 0 20 40 正确升序排列 padding: { 40em: 4, 20em: 2, : 0, } // ❌ 40em 与 50px 单位不一致排序会出错 // 40em 通常大于 50px但按数值 40 50 排序 padding: { 40em: 4, 50: 2, : 0, }第 3 条规则直接对应源码cssContainerQueries.ts 中的sortContainerQueries用正则min-width:\s*([0-9.])提取min-width的数值部分做纯数字排序源码注释也明确警告 “this function does not work and will not support multiple units”不支持混合单位。该函数由 styleFunctionSx.js 引入在sx处理流程中对以container开头的键重新排序保证输出的 CSS 按宽度从低到高排列、后写覆盖前写。源码实现解析1. 主题的注入点。在 createTheme.js 中createTheme流程末尾执行muiTheme cssContainerQueries(muiTheme)因此每个通过createTheme创建的主题都自动获得containerQueries无需手动配置其类型声明则放在createTheme.d.ts中合并进主题对象。2. 断点方法的容器化包装。cssContainerQueries函数为up/down/between/only/not五个方法各生成一个包装版本统一调用toContainerQueryconst toContainerQuery (mediaQuery: string, name?: string) mediaQuery.replace(media, name ? container ${name} : container);3.not()的特殊处理。media not all and (...)的写法在container中不合法源码对not单独做了逻辑反转检测到not all and时把min-width:替换为width、max-width:替换为width、and替换为or生成 CSS 容器查询范围语法。因此文档中not(sm)对中间断点的语义是“容器宽度小于 600px 或大于 900px”。4.简写的识别与解析。sx 的响应式键处理breakpoints.ts中先经isCqShorthand判断键是否为容器查询简写、断点键或匹配/^\d/的数字开头再交给getContainerQuery用正则/^([^/])?\/?(.)?$/拆出size与name最终调用theme.containerQueries(name).up(value)。注意两点简写语法固定走up()即350生成的是min-width查询无效简写在开发环境非 production会抛出带格式提示的错误说明合法格式为breakpoint | number或breakpoint | number/container例如sm、600、40rem/sidebar。5. 测试佐证。cssContainerQueries.test.ts 覆盖了各方法在默认断点下的精确输出如only(sm)→container (min-width:600px) and (max-width:899.95px)、命名容器containerQueries(sidebar).up(sm)→container sidebar (min-width:600px)以及isCqShorthand对、xs、200、15.5rem判真对media (min-width:600px)、page判假的边界用例可视为该功能的验收基准。小结Material UI 的容器查询方案可概括为三点theme.containerQueries复用断点 API 的全部方法up/down/between/only/not取值可为断点键、无单位数字或带单位字符串支持命名容器上下文sx中可用size/size/name简写免主题引用但注意“无单位即 px”“裸即 0px”“同一组查询单位必须一致”三条规则使用前提是 DOM 中存在声明了containerType如inline-size的祖先元素且容器查询本身依赖浏览器的 CSS 容器查询支持。若需要回顾断点方法本身的取值语义可继续阅读 breakpoints 文档 及其实现 createBreakpoints.ts。【免费下载链接】material-uiMaterial UI: Comprehensive React component library that implements Googles Material Design. Free forever.项目地址: https://gitcode.com/GitHub_Trending/ma/material-ui创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考