在 CSS3媒体查询中使用 Sass 变量

我试图将 Sass 变量的使用与@media 查询结合起来,如下所示:

$base_width:1160px;


@media screen and (max-width: 1170px) {$base_width: 960px;}
@media screen and (min-width: 1171px) {$base_width: 1160px;}

然后在样式表宽度百分比测量中的不同点定义 $base_width,以生成流体布局。

当我这样做时,变量似乎被正确识别,但媒体查询的条件却不是。例如,上面的代码生成一个1160px 的布局,而不管屏幕宽度如何。如果我像这样翻转@媒体声明:

@media screen and (min-width: 1171px) {$base_width: 1160px;}
@media screen and (max-width: 1170px) {$base_width: 960px;}

它生成一个960px 的布局,同样与屏幕宽度无关。还要注意,如果我删除 $base_width: 1160px;的第一行,它会返回一个未定义变量的错误。知道我错过了什么吗?

126617 次浏览

这是不可能的,因为触发器 @media screen and (max-width: 1170px)发生在客户端。

只有当 SASS 抓取包含 $base_width变量的样式表中的所有规则和属性并相应地复制/更改它们时,才有可能实现预期的结果。

因为它不会自动工作,你可以像这样用手做:

@media screen and (max-width: 1170px)
$base_width: 960px // you need to indent it to (re)set it just within this media-query
// now you copy all the css rules/properties that contain or are relative to $base_width e.g.
#wrapper
width: $base_width
...


@media screen and (min-width: 1171px)
$base_width: 1160px
#wrapper
width: $base_width
...

这不是真正的干燥,但最好的你可以做到这一点。

如果每次的更改都是相同的,那么您还可以准备一个混合文件,其中包含所有更改的值,因此您不需要重复它。此外,您可以尝试将 mix 与特定的更改组合在一起。比如:

@media screen and (min-width: 1171px)
+base_width_changes(1160px)
#width-1171-specific-element // additional specific changes, that aren't in the mixin
display: block

Mixin 就会变成这样

=base_width_changes($base_width)
#wrapper
width: $base_width

编辑: 请不要使用这个解决方案,Ronen 的答案要好得多。

作为 DRY 解决方案,您可以在媒体查询中使用 @import语句,例如。

@media screen and (max-width: 1170px) {
$base_width: 960px;
@import "responsive_elements";
}
@media screen and (min-width: 1171px) {
$base_width: 1160px;
@import "responsive_elements";
}

使用媒体查询中定义的变量定义文件中包含的所有响应元素。所以,您需要重复的就是 import 语句。

类似于 Philipp Zedler 的回答,你可以用混音来做。如果需要的话,可以将所有内容放在一个文件中。

    @mixin styling($base-width) {
// your SCSS here, e.g.
#Contents {
width: $base-width;
}
}


@media screen and (max-width: 1170px) {
@include styling($base-width: 960px);
}
@media screen and (min-width: 1171px) {
@include styling($base-width: 1160px);
}

我也有同样的问题。

$menu-width变量在 手机视图中应该是240px,在 桌面视图中应该是340px。

所以我简单地创建了两个变量:

$menu-width: 340px;
$menu-mobile-width: 240px;

我是这样使用它的:

.menu {
width: $menu-width;
@media only screen and (max-width : 768px) {
width: $menu-mobile-width;
}
}

这对于 SASS 是不可能的,但是对于 CSS 变量(或者 CSS 自定义属性)却是可能的。唯一的缺点是浏览器支持-但实际上有一个 PostCSS 插件 -Postcss-css- 变量-它“扁平化”了 CSS 变量的使用(这也给了你对旧浏览器的支持)。

下面的例子非常适用于 SASS (而且对于 postcss-css 变量,您也可以获得对旧浏览器的支持)。

$mq-laptop: 1440px;
$mq-desktop: 1680px;


:root {
--font-size-regular: 14px;
--gutter: 1rem;
}


// The fact that we have to use a `max-width` media query here, so as to not
// overlap with the next media query, is a quirk of postcss-css-variables
@media (min-width: $mq-laptop) and (max-width: $mq-desktop - 1px) {
:root {
--font-size-regular: 16px;
--gutter: 1.5rem;
}
}


@media (min-width: $mq-desktop) {
:root {
--font-size-regular: 18px;
--gutter: 1.75rem;
}
}


.my-element {
font-size: var(--font-size-regular);
padding: 0 calc(var(--gutter) / 2);
}

这将导致以下 CSS。重复的媒体查询会增加文件大小,但是我发现,一旦 Web 服务器应用了 gzip(它通常会自动这样做) ,这种增加通常是可以忽略不计的。

.my-element {
font-size: 14px;
padding: 0 calc(1rem / 2);
}
@media (min-width: 1680px) {
.my-element {
padding: 0 calc(1.75rem / 2);
}
}
@media (min-width: 1440px) and (max-width: 1679px) {
.my-element {
padding: 0 calc(1.5rem / 2);
}
}
@media (min-width: 1680px) {
.my-element {
font-size: 18px;
}
}
@media (min-width: 1440px) and (max-width: 1679px) {
.my-element {
font-size: 16px;
}
}

有了@ronen 的 答得好和地图,就有了真正的电力:

    @mixin styling($map) {
.myDiv {
background: map-get($map, 'foo');
font-size: map-get($map, 'bar');
}
}


@media (min-height: 500px) {
@include styling((
foo: green,
bar: 50px
));
}


@media (min-height: 1000px) {
@include styling((
foo: red,
bar: 100px
));
}

现在可以有更多针对 .myDiv的 DRY 媒体查询,它们具有一系列不同的值。


地图文档: https://sass-lang.com/documentation/functions/map

示例映射使用: https://www.sitepoint.com/using-sass-maps/

两条建议

1 编写针对小屏幕的“默认”CSS 语句,并且只针对大屏幕使用媒体查询。通常不需要 max-width媒体查询。

示例(假设元素具有类“ Container”)

@mixin min-width($width) {
@media screen and (max-width: $width) {
@content;
}
}


.container {
width: 960px;


@include min-width(1170px) {
width: 1160px;
}
}

使用 CSS 变量来解决问题,如果 你可以的

@mixin min-width($width) {
@media screen and (max-width: $width) {
@content;
}
}


:root {
--container-width: 960px;
@include min-width(1170px) {
--container-width: 1160px;
}
}


.container {
width: var(--container-width);
}

注:

因为当窗口的宽度为1170px 时,它的宽度为1160px,所以最好使用100% 的宽度和1160px 的最大宽度,并且父元素可能有5px 的水平填充,只要将 box-size 属性设置为 orders-box。有很多方法可以解决这个问题。如果父容器不是 Flex 或网格容器,则可以使用 .container { margin: auto }

使用% 占位符也可以做到这一点。

% 占位符可以包装在媒体查询中。因此,您可以设置多个变量,以便在不同的屏幕大小下使用,然后占位符将自动进行相应的预处理。我在这里还使用了一些 Mixin 来缩短媒体查询声明。

在您的 _ vars.scss 文件中:

    $width-1: 960px;
$width-2: 1160px;

在您的 _ placeholders.scss 文件中:

    %variable-site-width                    {
@media screen and (max-width: 1170px)       { width: $width-1; }
@media screen and (min-width: 1171px)       { width: $width-2; }
}

在 page.scss 文件中:

    .wrapper.     { @extend %variable-site-width; background: red; etc... }

这将汇编成类似于:

    @media screen and (max-width: 1170px) {
.wrapper { width: 960px; }
}
@media screen and (min-width: 1171px) {
.wrapper { width: 1160px; }
}

瞧!

我广泛使用这种技术来处理诸如可变字体大小和其他大量事情。