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


119

我试图结合使用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语句:

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

无论屏幕的宽度如何,它都会产生960px的布局。还要注意,如果我删除了$base_width: 1160px;它的第一行,则返回一个未定义变量的错误。有什么想法我想念的吗?


Answers:


96

这根本不可能。由于触发@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
          ...

这不是真正的DRY,而是您能做的最好的事情。

如果每次更改都相同,那么您还可以准备一个包含所有更改值的mixin,因此您无需重复该操作。此外,您可以尝试将mixin与特定更改结合在一起。喜欢:

@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

6
SASS仍不能与@media查询中的$ variables一起使用吗?
2014年

1
@HappyTorso总是这样,直到出现诸如在视口调整大小上运行的客户端Sass编译器(例如JavaScript)之类的东西。Sass变量在构建时被编译为静态值;它们在运行时不再存在。当查询中的媒体属性更改时,将在运行时评估媒体查询。
ericsoco '16

25
@ericsoco我不明白为什么这是一个原因。SASS可以轻松地(?)跟踪变量的所有用法,并在使用它们的地方插入媒体查询;$foo: 1rem; @media (min-width: 10rem) {$foo: 2rem} .class {font-size: $foo} .class2 {padding: $foo}会导致.class {font-size: 1rem} .class2 {padding: 1rem} @media (min-width: 10rem) (.class {font-size: 2rem} .class2 {padding: 2rem}}
powerbuoy 16/09/12

1
是的sass是一个预处理器,没有理由“这根本不可能” ...它可以做到,只是没有实现。
燕丽

54

与Philipp Zedler的答案类似,您可以使用mixin来完成。这样一来,您便可以将所有内容保存在一个文件中。

    @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);
    }

1
迟早您会遇到此问题,例如:sitepoint.com/cross-media-query-extend-sass
InsOp 2015年

这个比我的答案好!
菲利普·泽德勒

+1喜欢这个解决方案。将此与地图(sass-lang.com/documentation/functions/map)结合使用,您将拥有一些强大的功能-我将在此处提出一个单独的解决方案进行说明。编辑:完成。stackoverflow.com/a/56894640/385273

9

编辑:请不要使用此解决方案。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语句。


9

对于SASS,这是不可能的,但是对于CSS变量(或CSS自定义属性),这是可能的。唯一的缺点是对浏览器的支持-但是实际上有一个PostCSS插件-postcss-css-variables-可以“ 扩展 ” CSS变量的使用(它也支持较旧的浏览器)。

以下示例非常适合SASS(与postcss-css-variables一起使用时,您也支持较旧的浏览器)。

$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;
  }
}

8

使用@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/


我花了一点时间才看到它,但这与@ronen的答案是相同的技术,只是使用映射输入一次支持多个变量。我决不以任何方式低估它的价值,但是直到我建立这种联系之前,这很难理解
John Neuhaus

5

我有同样的问题。

$menu-width变量在移动设备视图上应为240px @media only screen and (max-width : 768px),在桌面视图上应为340px 。

所以我只创建了两个变量:

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

这是我如何使用它:

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

1

两个建议

1 编写“默认” CSS语句以用于小屏幕,而仅将媒体查询用于大屏幕。通常不需要max-width媒体查询。

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

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

.container {
  width: 960px;

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

2如果可以,请使用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-sizing属性设置为border-box。有很多方法可以解决问题。如果父级不是flex或grid容器,则可以使用.container { margin: auto }

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.