使用 key/value 遍历嵌套的 SCSS 列表

Loop through nested SCSS list using key/value

我有一个嵌套的 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

你的代码中有一些乱码......

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

  2. 错误:

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

...你有麻烦了。

你可以做什么:

  1. 重新整理您的地图。您可以更轻松地做到这一点:只存储值。
  2. 在你的 mixin 调用中直接输入你需要的值。无需循环!您只需要两个特殊值,您可以将其称为 targeted。
  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;
}


关于您问题的更新:
这是您更新后的要求的混合示例。

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

所以 font-sizing-settings 与边距甚至(几乎)所有其他 属性 设置一样有效,您希望 ot 适应断点。再一次使用 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;
  }
}



附加 HINT/IMPULSE:
可以压缩规则映射。在那种情况下,代码工作较少,但更专门用于单个标签和预定义的字体大小设置......而且可读性较差。 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;