使用 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;
}
}
我没有收到任何错误,但是元素的样式不可用。
你的代码中有一些乱码......
mixin 使用了一个 @each
循环...这不是必需的但是恶意的因为你不想一次写所有 类 而是用它来仅将一组特殊属性包含在单个 class/selector 中(在您的示例中,您尝试仅建议 h1 {...}
。
错误:
- 在你的循环中,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 并结束...
...你有麻烦了。
你可以做什么:
- 重新整理您的地图。您可以更轻松地做到这一点:只存储值。
- 在你的 mixin 调用中直接输入你需要的值。无需循环!您只需要两个特殊值,您可以将其称为 targeted。
- 并且不要忘记建议适合您的新字体大小的行高 ;-)
代码可能如下所示:
// ### 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;
我有一个嵌套的 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;
}
}
我没有收到任何错误,但是元素的样式不可用。
你的代码中有一些乱码......
mixin 使用了一个
@each
循环...这不是必需的但是恶意的因为你不想一次写所有 类 而是用它来仅将一组特殊属性包含在单个 class/selector 中(在您的示例中,您尝试仅建议h1 {...}
。错误:
- 在你的循环中,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 并结束...
...你有麻烦了。
你可以做什么:
- 重新整理您的地图。您可以更轻松地做到这一点:只存储值。
- 在你的 mixin 调用中直接输入你需要的值。无需循环!您只需要两个特殊值,您可以将其称为 targeted。
- 并且不要忘记建议适合您的新字体大小的行高 ;-)
代码可能如下所示:
// ### 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;