【问题标题】:Loop through nested SCSS list using key/value使用键/值循环嵌套 SCSS 列表
【发布时间】:2021-07-03 02:15:09
【问题描述】:

我有一个嵌套的scss 列表,其中包含一些字体定义:

$font-cinzel: "Cinzel", serif;
$font-poppins: "Poppins", sans-serif;

$fonts: (
    "title": (
        "all": (
            font-family: $font-cinzel
        ),
        "sm": (
            font-size: 26px,
      line-height: 1.4
        ),
        "lg": (
            font-size: 80px,
      line-height: 1.6
        )
    ),
    "text": (
        "all": (
            font-family: $font-poppins
        ),
        "sm": (
            font-size: 16px,
      line-height: 1.2
        ),
        "lg": (
            font-size: 36px,
      line-height: 1.4
        )
    )
);

现在我想写一个mixin 和一个function 来在为每个视口传递字体名称时生成一个样式块。所以all 中定义的所有样式都应该在media query 之外呈现(所有视口的规则以避免冗余)。视口独有的所有其他样式都在视口块中定义,例如所有小样式都在sm 中,所有具有不同值的大样式都在lg 等等。我还有一个断点混合,我使用字体列表中的视口名称映射min-width

断点混合:

$breakpoints: (
    sm: 768px,
    md: 1024px,
    lg: 1280px,
    xl: 1400px
);

@function get-bp($bp) {
    @if $bp {
        $bp: map-get($breakpoints, $bp);
    } @else {
        @error "Parameter #{$vp} is unknown or empty.";
    }

    @return $bp;
}

这就是我尝试循环播放内容的方式:

@function get-value($definition, $vp) {
    @each $prop, $val in map-get($definition, $vp) {
        @return $val;
    }
}

@mixin font($name) {
    $definition: map-get($fonts, $name);

    @each $key, $value in $definition {
        @if $key == "all" {
            $prop: get-value($definition, $key);
        } @else {
            @media (min-width: get-bp($key)) {
                $prop: get-value($definition, $key);
            }
        }
    }
}

h1 {
  @include font('title');
}

p {
  @include font('text');
}

预期输出:

h1 {
  font-family: 'Cinzel', serif;

  @media (min-width: 768px) {
    font-size: 26px;
    line-height: 1.4;
  }

  @media (min-width: 1280px) {
    font-size: 80px;
    line-height: 1.6;
  }
}

p {
  font-family: 'Poppins', sans-serif;

  @media (min-width: 768px) {
    font-size: 16px;
    line-height: 1.2;
  }

  @media (min-width: 1280px) {
    font-size: 36px;
    line-height: 1.4;
  }
}

我没有收到任何错误,但样式不适用于元素。

这是代码笔: https://codepen.io/STWebtastic/pen/QWdOZPN

【问题讨论】:

    标签: css sass each scss-mixins


    【解决方案1】:

    您的代码中有一些杂乱无章...

    1. mixin 使用了一个@each 循环......这不是必需的,但它是恶意的,因为您不想一次编写所有类,而是使用它来仅将一组特殊的属性包含到单个类/选择器中(在您的示例中,您尝试仅向h1 {...} 提供建议。

    2. 错误:

    • 在您的循环中,mixin 调用 map-get($fonts, $name)' which in your example is inner map title` 中的每个元素。
    • 现在,对于这张地图 (= fontFamily, sm, lg) 的每个元素,它都应该做一些事情...
    • 在您的情况下,您假设所有元素都是映射以从中获取值。
    • 所以循环采用第一个元素fontFamily
    • 您尝试获取内部元素的值 fontFamily ...
    • SASS 首先检查函数map-get 并意识到fontFamily 你命名为映射的函数不是映射...
    • 此时 SASS 并结束...

    ...你有麻烦了。

    你可以做什么:

    1. 重新组织您的地图。您可以更轻松地做到这一点:只存储值。
    2. 在您的 mixin 调用中直接输入您需要的值。无需循环!您只需要两个可以称为目标的特殊值。
    3. 不要忘记建议适合您的新字体大小的行高 ;-)

    代码可能如下所示:

    // ### SASS
    
    $fonts: (
        title: (
            fontFamily: 'Arial',
            sm: 12px,
            lg: 24px,
        ),
        text: (
            fontFamily: 'Courier New',
            sm: 10px,
            lg: 20px,
        ),
    ) !default;
    
    @mixin font( $item, $size  ) {
        font-family: map-get(map-get($fonts, $item), fontFamily );
        font-size: map-get(map-get($fonts, $item), $size );
        line-height: 1.2em;
    }
    
    h1 {
        @include font( title, sm);
    }
    
    
    
    // ### Compiles to CSS
    
    h1 {
      font-family: "Arial";
      font-size: 12px;
      line-height: 1.2em;
    }
    
    
    

    【讨论】:

    • 感谢您的回答。看起来不错,但它并不能真正解决我的问题。也许我没有解释到最后,因为我试图让 sn-p 最容易理解,但我的总体想法是为每个视口的元素加载字体样式。有没有办法进入 stackoverflow 中的私人聊天频道,以便我可以向您展示整个 sass 文件?干杯。
    • 感谢您的反馈。那么'sm'和'lg'是断点吗?您可以调整 mixin 来实现这一点。 mixin应该用于单个元素吗?您可以使用 mixin 编写包括 @media 变体在内的整个规则,并建议示例中显示的值……但确实令人困惑……聊天:实际上我很忙,不确定今天是否有时间。但是,如果您用想要的逻辑更新您的问题...我会稍后再尝试(不太确定时间)...或者其他人在这里我肯定会有所帮助...这是编码人员的强大力量:-)
    • 我会在这里解释一下:所以在我的设计中,我有特定元素的字体样式,例如多个视口的标题。我尝试将此样式存储在嵌套列表中。 all 应该在媒体查询之外呈现,以便所有视口都有所有样式。字体大小、行高等变体应存储在视口名称中,例如sm 的所有样式都在sm 中,lg 的样式在lg 等中。然后我遍历这个嵌套列表并尝试直接在一个选择器中为每个定义构建一个样式块:codepen.io/STWebtastic/pen/QWdOZPN
    • PS:我已经更新了下面的问题。谢谢
    【解决方案2】:

    至于您在问题中的更新:
    这是您更新要求的混合示例。

    该示例以更通用的方式完成,可多次使用且具有良好的可读性。

    所以 font-sizing-settings 和边距一样有效,甚至(几乎)你想适应断点的所有其他属性设置。再一次使用 map-element selector 它适用于简单元素(标签)、类、id 和更复杂的选择器。

    除了$rules 映射之外,它还基于断点映射。这确保它适用于建议给项目的所有断点。但是断点的规则只有在规则映射中注明时才会添加到元素中......所以你可以说:这是一把万能的瑞士刀。

    示例:

    //###### SASS
    // this example assumes:
    // breakpoints allways min-width ...
    $breakpoints: (
        sm: 768px,
        md: 1024px,
        lg: 1280px,
        xl: 1400px
    );
    
    $rules: (
    
        title: (
    
            selector: 'h1',
    
            all: (
                font-family: 'Arial',
                font-size: 26px,
                line-height: 1.4,
            ),
    
            sm: (
                font-size: 26px,
                line-height: 1.4,
            ),
            lg: (
                font-size: 80px,
                line-height: 1.6,
            ),
            xl: (
                font-size: 100px,
            ),
        ),
    
        text: (
    
            selector: 'p',
    
            all: (
                font-family: 'Courier New',
                font-size: 26px,
                line-height: 1.4,
            ),
    
            sm: (
                font-size: 16px,
                line-height: 1.2,
            ),
            lg: (
                font-size: 36px,
                line-height: 1.4,
            )
        ),
    
    ) !default;
    
    
    
    @mixin fontSizing($rule-map, $breakpoints: $breakpoints){
    
    
        @each $element, $settings-map in $rule-map {
    
            $selector: map-get($settings-map, selector);
    
            // write generel rules
            #{$selector} {      
                @each $property, $value in map-get($settings-map, all){
                    #{$property}: $value;
                }
            }
    
            // rules for every breakpoint
            @each $breakpoint, $breakpoint-setting in $breakpoints {
    
                // only if breakpoint values set for element
                @if map-has-key( $settings-map, $breakpoint ){
    
                    // write breakpoints rule
                    @media ( min-width: #{$breakpoint-setting} ){
                        #{$selector} {
                            @each $property, $value in map-get($settings-map, $breakpoint){
                                #{$property}: $value;
                            }
                        }
                    }
    
                }//if
    
            }//each
    
        }//each
    
    }//mixin
    
    
    //##### CALL MIXIN
    @include fontSizing($rules);
    
    
    //##### COMPILES TO...
    
    h1 {
      font-family: "Arial";
      font-size: 26px;
      line-height: 1.4;
    }
    
    @media (min-width: 768px) {
      h1 {
        font-size: 26px;
        line-height: 1.4;
      }
    }
    @media (min-width: 1280px) {
      h1 {
        font-size: 80px;
        line-height: 1.6;
      }
    }
    @media (min-width: 1400px) {
      h1 {
        font-size: 100px;
      }
    }
    p {
      font-family: "Courier New";
      font-size: 26px;
      line-height: 1.4;
    }
    
    @media (min-width: 768px) {
      p {
        font-size: 16px;
        line-height: 1.2;
      }
    }
    @media (min-width: 1280px) {
      p {
        font-size: 36px;
        line-height: 1.4;
      }
    }
    
    
    

    附加提示/冲动:
    可以压缩规则映射。在这种情况下,代码工作较少,但更专门针对单个标签和预定义的字体大小设置......而且可读性较差。 mixin 的一般构造是相同的,但是当您使用预定义的属性和嵌套列表而不是嵌套映射时,代码编写会发生一些变化。随意调整代码。以下是可能压缩到规则映射的示例:

    $rule: (
        h1: (
            fontFamily: 'Arial',
            all: (10px, 1.2),
            sm: (12px, 1.4),
            lg: (24px, 1.6),
        ),
        p: (
            fontFamily: 'Courier New',
            all: (8px, 1.2),
            sm: (10px, 1.4),
            lg: (20px, 1.6),
            xl: (24px, 1.8),
        ),
    ) !default;
    

    【讨论】:

    猜你喜欢
    • 2018-01-06
    • 1970-01-01
    • 2019-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-27
    相关资源
    最近更新 更多