【问题标题】:CSS native variables not working in media queriesCSS本机变量在媒体查询中不起作用
【发布时间】:2021-11-05 15:55:54
【问题描述】:

我正在尝试在媒体查询中使用 CSS 变量,但它不起作用。

:root {
  --mobile-breakpoint: 642px;
}

@media (max-width: var(--mobile-breakpoint)) {

}

【问题讨论】:

  • 只是为了澄清人们通过 Google 发现这一点:您可以在媒体查询范围内使用 CSS 自定义属性,但不能在媒体查询声明中使用它们。

标签: css media-queries css-variables


【解决方案1】:

显然不可能使用这样的原生 CSS 变量。它是limitations 之一。

使用它的一个聪明方法是更改​​媒体查询中的变量,以影响您的所有风格。我推荐this article

:root {
  --gutter: 4px;
}

section {
  margin: var(--gutter);
}

@media (min-width: 600px) {
  :root {
    --gutter: 16px;
  }
}

【讨论】:

  • 我不明白“更改媒体查询中的变量”的含义,您可以举个例子吗?
  • 是的,刚刚做了,它在我链接的文章中。我知道这不是您所期望的,但 CSS 变量不能用于定义媒体查询
  • 这很重要。想象一下在@media 规则中使用自定义属性的值——然后还想更改该自定义属性的值——在同一个断点。这很奇怪......但它们是自定义属性 - 而不仅仅是变量。所以, - 似乎它不是以这种方式创建的原因 - 用一个例子比规范更好地解释。最好是组合。
  • 限制链接现在是 404
  • 感谢@ArthurShlain,已修复
【解决方案2】:

来自spec

var() 函数可以用来代替值的任何部分 元素上的任何属性。 var() 函数不能用作 属性名称、选择器或除属性值之外的任何其他内容。 (这样做通常会产生无效的语法,否则会产生一个 意义与变量无关。)

所以不,你不能在媒体查询中使用它。

这是有道理的。因为您可以设置 --mobile-breakpoint 例如到:root,即<html>元素,并从那里被继承到其他元素。但是媒体查询不是一个元素,它不是继承自<html>,所以它不能工作。

这不是 CSS 变量试图完成的任务。您可以改用 CSS 预处理器。

【讨论】:

  • 答案是正确的,因为规范目前不处理媒体查询中的 CSS 变量,但不正确的是,这不是 CSS 变量试图完成的任务。 减少重复和幻数正是创建 CSS 变量的原因 -- 参见 w3.org/TR/css-variables-1/#intro
  • 顺便说一句,这 NOT 是一个属性值吗?这是max-width 的财产价值!它应该完全有效!
  • @user9645 实际上,没有。它可能看起来max-width 属性,因为您编写了相同的文本,但它完成了完全不同的事情。 CSS 属性声明充当“setter”,它为元素设置值,而媒体查询中的max-width 是“getter”:它请求某物的当前宽度(然后将其与提供的值进行比较)。文本max-width: 1000px 作为媒体查询(以一些非有效伪代码的形式)类似于viewport.getWidth() <= 1000px,而作为属性声明它将是element.setMaxWidth(1000px)
【解决方案3】:

实现您想要的一种方法是使用 npm 包postcss-media-variables

如果你对使用 npm 包没问题,那么你可以在这里查看相同的文档:

例子

/* input */
:root {
  --min-width: 1000px;
  --smallscreen: 480px;
}
@media (min-width: var(--min-width)) {}
@media (max-width: calc(var(--min-width) - 1px)) {}

@custom-media --small-device (max-width: var(--smallscreen));
@media (--small-device) {}

【讨论】:

  • 谢谢,但我试图不使用任何预处理器。
  • 等。 al : 使用 postcss 你也可以使用 cssnext cssnext.io/features/#custom-media-queries
  • @sebilasse: custom-media-queries 没有解决无法使用 css 变量作为媒体查询断点的主要问题
  • postcss 不是预处理器
  • @user7637140 PostCSS - 使用 JavaScript 转换 CSS 的工具。那怎么不是预处理器?
【解决方案4】:

作为Oriol has answeredCSS Variables Level 1’s var() cannot currently be used in media queries。然而,最近的发展将解决这个问题。 一旦CSS Environment Variables Module Level 1 标准化并实施,我们就可以在所有现代浏览器的媒体查询中使用env() 变量。

CSS 工作组 (CSSWG) 将 env() 编入了一个新标准(目前处于草案阶段):CSS Environment Variables Module Level 1(有关更多信息,请参阅 this GitHub commentthis comment) .草案将媒体查询中的变量作为一个明确的用例:

因为环境变量不依赖于任何从特定元素中提取的值,所以它们可以用在没有明显可提取元素的地方,例如在@media 规则中,其中var()函数将无效。

如果您阅读了规范并有疑问,或者如果您想表达您对媒体查询用例的支持,您可以在issue #2627issue #3578any CSS GitHub issue labeled with “css-env-1” 中这样做。

GitHub issue #2627GitHub issue #3578 专门用于媒体查询中的自定义环境变量。


2017-11-09 的原始答案: 最近,CSS Working Group decided 表示 CSS 变量 Level 2 将支持使用 env() 的用户定义的环境变量,他们将尝试使它们在媒体查询中有效。集团在 2017 年 9 月 iPhone X 正式发布前不久解决了这个after Apple first proposed standard user-agent properties(另见WebKit: “Designing Websites for iPhone X” by Timothy Horton)。其他浏览器代表随后同意它们在许多设备上普遍有用,例如电视显示器和带有出血边缘的墨水打印。 (env() 以前称为 constant(),但现在已弃用。您可能仍然会看到引用旧名称的文章,例如 this article by Peter-Paul Koch。)几周后,Cameron McCormack of Mozilla realized 认为这些环境变量将可用于媒体查询,并且Tab Atkins, Jr. of Google then realized 用户定义的环境变量将作为可用于媒体查询的全局、不可覆盖的根变量特别有用。现在,Dean “Dino” Jackson of Apple will join Atkins 正在编辑第 2 级。

您可以在w3c/csswg-drafts GitHub issue #1693 订阅有关此事件的更新(有关特别相关的历史详细信息,请展开嵌入在CSSWG Meeting Bot’s resolutions 中的会议日志并搜索“MQ”,即“媒体查询”)。

【讨论】:

    【解决方案5】:

    您可以阅读其他答案,但仍然不可能这样做。

    有人提到自定义环境变量(类似于自定义css变量env()而不是var()),原理是正确的,虽然还是有2个大问题:

    • 浏览器支持较弱
    • 到目前为止还没有办法定义它们(但可能会在将来,因为目前这只是一个非官方的草案)

    【讨论】:

      【解决方案6】:

      可以做的是@media 查询您的:root 语句!

      :root {
           /* desktop vars */
      }
      @media screen and (max-width: 479px) {
          :root {
              /* mobile vars */
          }
      }
      

      至少可以在 Chrome、Firefox 和 Edge 中运行,至少是本文发布时的最新生产版本。

      一个限制:如果您需要将值作为变量访问——例如在其他地方的计算中使用——您将需要一个变量,并且需要在两个地方定义变量:媒体查询和变量声明。

      【讨论】:

        【解决方案7】:

        简答

        您可以使用 JavaScript 更改媒体查询的值并将其设置为 css 变量的值。

        // get value of css variable
        getComputedStyle(document.documentElement).getPropertyValue('--mobile-breakpoint'); // '642px'
        
        // search for media rule
        var mediaRule = document.styleSheets[i].cssRules[j];
        
        // update media rule
        mediaRule.media.mediaText = '..'
        


        长答案

        我编写了一个小脚本,您可以将其包含在您的页面中。它将每个值为1px 的媒体规则替换为css 变量--replace-media-1px 的值,将值为2px 的规则替换为--replace-media-2px 等等。这适用于媒体查询withmin-widthmax-widthheightmin-heightmax-height,即使它们使用and 连接也是如此。

        JavaScript:

        function* visitCssRule(cssRule) {
            // visit imported stylesheet
            if (cssRule.type == cssRule.IMPORT_RULE)
                yield* visitStyleSheet(cssRule.styleSheet);
        
            // yield media rule
            if (cssRule.type == cssRule.MEDIA_RULE)
                yield cssRule;
        }
        
        function* visitStyleSheet(styleSheet) {
            try {
                // visit every rule in the stylesheet
                var cssRules = styleSheet.cssRules;
                for (var i = 0, cssRule; cssRule = cssRules[i]; i++)
                    yield* visitCssRule(cssRule);
            } catch (ignored) {}
        }
        
        function* findAllMediaRules() {
            // visit all stylesheets
            var styleSheets = document.styleSheets;
            for (var i = 0, styleSheet; styleSheet = styleSheets[i]; i++)
                yield* visitStyleSheet(styleSheet);
        }
        
        // collect all media rules
        const mediaRules = Array.from(findAllMediaRules());
        
        // read replacement values
        var style = getComputedStyle(document.documentElement);
        var replacements = [];
        for (var k = 1, value; value = style.getPropertyValue('--replace-media-' + k + 'px'); k++)
            replacements.push(value);
        
        // update media rules
        for (var i = 0, mediaRule; mediaRule = mediaRules[i]; i++) {
            for (var k = 0; k < replacements.length; k++) {
                var regex = RegExp('\\((width|min-width|max-width|height|min-height|max-height): ' + (k+1) + 'px\\)', 'g');
                var replacement = '($1: ' + replacements[k] + ')';
                mediaRule.media.mediaText = mediaRule.media.mediaText.replace(regex, replacement);
            }
        }
        

        CSS:

        :root {
          --mobile-breakpoint: 642px;
        
          --replace-media-1px: var(--mobile-breakpoint);
          --replace-media-2px: ...;
        }
        
        @media (max-width: 1px) { /* replaced by 642px */
          ...
        }
        
        @media (max-width: 2px) {
          ...
        }
        

        【讨论】:

        • 喜欢你的解决方案和你的风格!
        • 也许可行,但它看起来太老套了!
        【解决方案8】:

        level 5 specification of media queries 定义了自定义媒体查询,几乎可以满足您的需求。它允许您定义断点,类似于处理 CSS 变量的方式,然后在不同的地方使用它们。

        规范示例:

        @custom-media --narrow-window (max-width: 30em);
        
        @media (--narrow-window) {
          /* narrow window styles */
        }
        @media (--narrow-window) and (script) {
          /* special styles for when script is allowed */
        }
        

        实际上仍然不支持此功能,因此我们必须等待才能使用此功能。

        【讨论】:

          【解决方案9】:

          您可以使用matchMedia 以编程方式构建媒体查询:

          const mobile_breakpoint = "642px";
          const media_query = window.matchMedia(`(max-width: ${mobile_breakpoint})`);
          function toggle_mobile (e) {
            if (e.matches) {
              document.body.classList.add("mobile");
            } else {
              document.body.classList.remove("mobile");
            }
          }
          // call the function immediately to set the initial value:
          toggle_mobile(media_query);
          // watch for changes to update the value:
          media_query.addEventListener("change", toggle_mobile);
          

          然后,当body 具有mobile 类时,应用所需的规则,而不是在您的 CSS 文件中使用媒体查询:

          .my-div {
            /* large screen rules */
          }
          
          .mobile .my-div {
            /* mobile screen rules */
          }
          

          【讨论】:

            猜你喜欢
            • 2013-05-30
            • 1970-01-01
            • 2021-12-08
            • 1970-01-01
            • 2023-03-09
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多