CSS 本机变量在媒体查询中不起作用
CSS native variables not working in media queries
我正在尝试在媒体查询中使用 CSS 变量,但它不起作用。
:root {
--mobile-breakpoint: 642px;
}
@media (max-width: var(--mobile-breakpoint)) {
}
显然无法像那样使用本机 CSS 变量。这是 limitations.
之一
一个巧妙的使用方法是更改媒体查询中的变量,以影响您的所有样式。我推荐this article.
:root {
--gutter: 4px;
}
section {
margin: var(--gutter);
}
@media (min-width: 600px) {
:root {
--gutter: 16px;
}
}
来自spec,
The var()
function can be used in place of any part of a value in
any property on an element. The var()
function can not be used as
property names, selectors, or anything else besides property values.
(Doing so usually produces invalid syntax, or else a value whose
meaning has no connection to the variable.)
所以不,你不能在媒体查询中使用它。
这是有道理的。因为您可以设置 --mobile-breakpoint
例如到 :root
,即 <html>
元素,并从那里继承到其他元素。但是媒体查询不是元素,它不继承自<html>
,所以它不能工作。
这不是 CSS 变量试图完成的。您可以改用 CSS 预处理器。
一种实现您想要的方法是使用 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) {}
随着 , CSS Variables Level 1’s var()
cannot currently be used in media queries. However, there have been recent developments that will address this problem. Once CSS Environment Variables Module Level 1 的标准化和实施,我们将能够在所有现代浏览器的媒体查询中使用 env()
变量。
CSS 工作组 (CSSWG) 将 env()
编入新标准(目前处于草案阶段):CSS Environment Variables Module Level 1 (see this GitHub comment and this comment获取更多信息)。草案将媒体查询中的变量作为显式用例调用:
Because environment variables don’t depend on the value of anything drawn from a particular element, they can be used in places where there is no obvious element to draw from, such as in @media
rules, where the var()
function would not be valid.
如果您阅读规范后有疑虑,或者如果您想表达对媒体查询用例的支持,可以在 issue #2627, in issue #3578, or in any CSS GitHub issue labeled with “css-env-1”.
中进行
GitHub issue #2627 and GitHub issue #3578 专门用于媒体查询中的自定义环境变量。
2017-11-09 的原始答案:
最近,CSS Working Group decided that CSS Variables Level 2 will support user-defined environment variables using env()
, and they will try to make them be valid in media queries. The Group resolved this after Apple first proposed standard user-agent properties, shortly before the official announcement of iPhone X in September 2017 (see also WebKit: “Designing Websites for iPhone X” by Timothy Horton). Other browser representatives then agreed they would be generally useful across many devices, such as television displays and ink printing with bleed edges. (env()
used to be called constant()
, but that has now been deprecated. You might still see articles that refer to the old name, such as this article by Peter-Paul Koch.) After some weeks passed, Cameron McCormack of Mozilla realized that these environment variables would be usable in media queries, and Tab Atkins, Jr. of Google then realized that user-defined environment variables would be especially useful as global, non-overridable root variables usable in media queries. Now, Dean “Dino” Jackson of Apple will join Atkins 在编辑 Level 2。
您可以在 w3c/csswg-drafts
GitHub issue #1693 (for especially relevant historical details, expand the meeting logs embedded in the CSSWG Meeting Bot’s resolutions 中订阅有关此事的更新并搜索“MQ”,它代表“媒体查询”)。
正如您可以阅读其他答案一样,仍然不可能这样做。
有人提到了自定义环境变量(类似于自定义css变量env()
而不是var()
),原理不错,虽然还有 2 个主要问题:
- 浏览器支持较弱
- 到目前为止还没有办法定义它们(但可能会在未来,因为到目前为止这只是一个非官方草案)
你可以做的是@media查询你的:root
声明!
:root {
/* desktop vars */
}
@media screen and (max-width: 479px) {
:root {
/* mobile vars */
}
}
完全适用于 Chrome,Firefox 和 Edge 至少是截至本文发布时的最新生产版本。
一个限制:如果您需要将值作为变量访问——例如在其他地方的计算中使用——您将需要一个变量,并且需要在两个地方定义变量:媒体查询和变量宣言.
简答
您可以使用 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
等等。这适用于媒体查询 with
、min-width
、max-width
、height
、min-height
和 max-height
,即使它们是使用 [=23 连接的=].
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 = '(: ' + 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) {
...
}
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 */
}
实际上仍然不支持此功能,因此我们必须等待才能使用此功能。
您可以使用 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
class:
时应用所需的规则,而不是在 CSS 文件中使用媒体查询
.my-div {
/* large screen rules */
}
.mobile .my-div {
/* mobile screen rules */
}
我正在尝试在媒体查询中使用 CSS 变量,但它不起作用。
:root {
--mobile-breakpoint: 642px;
}
@media (max-width: var(--mobile-breakpoint)) {
}
显然无法像那样使用本机 CSS 变量。这是 limitations.
之一一个巧妙的使用方法是更改媒体查询中的变量,以影响您的所有样式。我推荐this article.
:root {
--gutter: 4px;
}
section {
margin: var(--gutter);
}
@media (min-width: 600px) {
:root {
--gutter: 16px;
}
}
来自spec,
The
var()
function can be used in place of any part of a value in any property on an element. Thevar()
function can not be used as property names, selectors, or anything else besides property values. (Doing so usually produces invalid syntax, or else a value whose meaning has no connection to the variable.)
所以不,你不能在媒体查询中使用它。
这是有道理的。因为您可以设置 --mobile-breakpoint
例如到 :root
,即 <html>
元素,并从那里继承到其他元素。但是媒体查询不是元素,它不继承自<html>
,所以它不能工作。
这不是 CSS 变量试图完成的。您可以改用 CSS 预处理器。
一种实现您想要的方法是使用 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) {}
随着 var()
cannot currently be used in media queries. However, there have been recent developments that will address this problem. Once CSS Environment Variables Module Level 1 的标准化和实施,我们将能够在所有现代浏览器的媒体查询中使用 env()
变量。
CSS 工作组 (CSSWG) 将 env()
编入新标准(目前处于草案阶段):CSS Environment Variables Module Level 1 (see this GitHub comment and this comment获取更多信息)。草案将媒体查询中的变量作为显式用例调用:
Because environment variables don’t depend on the value of anything drawn from a particular element, they can be used in places where there is no obvious element to draw from, such as in
@media
rules, where thevar()
function would not be valid.
如果您阅读规范后有疑虑,或者如果您想表达对媒体查询用例的支持,可以在 issue #2627, in issue #3578, or in any CSS GitHub issue labeled with “css-env-1”.
中进行GitHub issue #2627 and GitHub issue #3578 专门用于媒体查询中的自定义环境变量。
2017-11-09 的原始答案:
最近,CSS Working Group decided that CSS Variables Level 2 will support user-defined environment variables using env()
, and they will try to make them be valid in media queries. The Group resolved this after Apple first proposed standard user-agent properties, shortly before the official announcement of iPhone X in September 2017 (see also WebKit: “Designing Websites for iPhone X” by Timothy Horton). Other browser representatives then agreed they would be generally useful across many devices, such as television displays and ink printing with bleed edges. (env()
used to be called constant()
, but that has now been deprecated. You might still see articles that refer to the old name, such as this article by Peter-Paul Koch.) After some weeks passed, Cameron McCormack of Mozilla realized that these environment variables would be usable in media queries, and Tab Atkins, Jr. of Google then realized that user-defined environment variables would be especially useful as global, non-overridable root variables usable in media queries. Now, Dean “Dino” Jackson of Apple will join Atkins 在编辑 Level 2。
您可以在 w3c/csswg-drafts
GitHub issue #1693 (for especially relevant historical details, expand the meeting logs embedded in the CSSWG Meeting Bot’s resolutions 中订阅有关此事的更新并搜索“MQ”,它代表“媒体查询”)。
正如您可以阅读其他答案一样,仍然不可能这样做。
有人提到了自定义环境变量(类似于自定义css变量env()
而不是var()
),原理不错,虽然还有 2 个主要问题:
- 浏览器支持较弱
- 到目前为止还没有办法定义它们(但可能会在未来,因为到目前为止这只是一个非官方草案)
你可以做的是@media查询你的:root
声明!
:root {
/* desktop vars */
}
@media screen and (max-width: 479px) {
:root {
/* mobile vars */
}
}
完全适用于 Chrome,Firefox 和 Edge 至少是截至本文发布时的最新生产版本。
一个限制:如果您需要将值作为变量访问——例如在其他地方的计算中使用——您将需要一个变量,并且需要在两个地方定义变量:媒体查询和变量宣言.
简答
您可以使用 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
等等。这适用于媒体查询 with
、min-width
、max-width
、height
、min-height
和 max-height
,即使它们是使用 [=23 连接的=].
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 = '(: ' + 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) {
...
}
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 */
}
实际上仍然不支持此功能,因此我们必须等待才能使用此功能。
您可以使用 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
class:
.my-div {
/* large screen rules */
}
.mobile .my-div {
/* mobile screen rules */
}