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

Posted

技术标签:

【中文标题】在 CSS3 媒体查询中使用 Sass 变量【英文标题】:Using Sass Variables with CSS3 Media Queries 【发布时间】:2012-02-25 16:33:22 【问题描述】:

我正在尝试将 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;

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

【问题讨论】:

重复的***.com/questions/40739695/… 【参考方案1】:

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

【讨论】:

在@media 查询中,SASS 仍然无法使用 $variables 吗? @HappyTorso 一直都是这种情况,直到出现在视口调整大小时运行的客户端 Sass 编译器(例如在 javascript 中)。 Sass 变量在构建时被编译成静态值;它们在运行时不再存在。当查询中的媒体属性发生变化时,媒体查询会在运行时进行评估。 @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 是的,sass 是一个预处理器,没有理由说“这根本不可能”......它可以做到,只是没有实现。【参考方案2】:

与 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);
    

【讨论】:

迟早你会遇到这个问题,虽然:sitepoint.com/cross-media-query-extend-sass 这个比我的回答好! +1 喜欢这个解决方案。将其与地图 (sass-lang.com/documentation/functions/map) 结合使用,您就拥有了一些力量——我将在这里制作一个单独的解决方案来解释。编辑:完成。 ***.com/a/56894640/385273【参考方案3】:

这对于 SASS 是不可能的,但对于 CSS 变量(或 CSS custom properties)是可能的。唯一的缺点是浏览器支持——但实际上有一个 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。重复的媒体查询会增加文件大小,但我发现一旦网络服务器应用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;
  

【讨论】:

【参考方案4】:

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

【讨论】:

【参考方案5】:

有了@ronen 的great answer 和一张地图,就有了一些真正的力量:

    @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 的答案相同,只是使用地图输入来一次支持多个变量。我不会以任何方式贬低它的价值,但在我建立这种联系之前很难理解【参考方案6】:

我遇到了同样的问题。

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

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

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

这是我使用它的方式:

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

【讨论】:

【参考方案7】:

两条建议

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变量解决问题,如果you can。

@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

【讨论】:

标准 CSS 变量是最干净的路径。【参考方案8】:

这也可以通过 %placeholders 实现。

%placeholders 可以包含在媒体查询中。因此,您可以设置多个变量以在不同的屏幕尺寸下使用,然后占位符会自动相应地进行预处理。我也在使用一些 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; 
     

瞧!

我将这种技术广泛用于可变字体大小和大量其他事情。

【讨论】:

以上是关于在 CSS3 媒体查询中使用 Sass 变量的主要内容,如果未能解决你的问题,请参考以下文章

使用 css 变量(没有 SASS/LESS)设置媒体查询的最小/最大宽度?

scss Bootstrap Sass媒体查询变量

scss Bootstrap Sass媒体查询变量

scss Bootstrap Sass媒体查询变量

如何使用媒体查询或运算符使 SASS 嵌套嵌套媒体查询工作

CSS3媒体查询总结