使用Sass管理z-index更好的解决方案
2014-06-21 00:00
337 查看
本文由大漠根据Hugo Giraudel的《A Better Solution for Managing z-index with Sass》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明原作者相关信息http://www.sitepoint.com/better-solution-managing-z-index-sass/。
——作者:Hugo Giraudel
——译者:大漠
最近我们看到有关于Sass管理z-index有好向篇文章:
Jackie Balzer在Smashing Magazine网站上发布的《Sassy z-index Management for Complex Layouts》
Doug Avery在Viget网站上发布的《Sass and z-indexes: a (slightly) better way》
Chris Coyier在CSS-Tricks网站上发布的《Handling z-index》
刚好前几天把Jackie Balzer在Smashing Magazine网站上发布的《Sassy z-index Management for Complex Layouts》一文翻译成中文了:《Sass管理复杂的z-index》。——@大漠
虽然Chris Coyier去年那篇文章最初帮助我解决了管理z-index,但并不怎么得心应手。从技术的角度出发,我在这里提出一个更简单、易用的方案。
因此通过这篇文章,我将系统的引导您,并且向您展示是如何创建管理z-index,以及如何让你在项目中更好的使用它。
为什么要管理z-index的值?
首先我们来回答这个问题:为什么我们要用Sass来管理z-index的值?我们没有看到无数文章如雨后春笋般的冒出来介绍使用Sass管理padding,对不对?那么为什么有关于z-index的会这么多呢?
那么,它必须要这样做,因为z-index很容易造成错误。此外,它接受无穷小到无穷大之间的任意一个值,在很多场合之下,他会搞砸你的事情。
因此,使用像9999999的值,让其在你的屏幕上随意出现。你可能不知道这是怎么一回事,但使用一个扩展工具是非常有趣的。在这种情况之下,使用CSS预处理器可以帮助你搞定这件事情。
概念是什么?
关于这个话题的所有文章介绍的概念几乎都是一样:创建一个可以带有关键词的函数,而且这个关键词可以通过Sass的map映射得到值。这个映射出来的值就是z-index需要输出的值。
Jackie Balzer使用了列表,Doug Avery使用列表和map的混合,Chris Coyier使用了map。事实上,Chris Coyier的解决方案与我的最终方案非常接近,只不过他的解决方案不太适合大系统环境下使用。
最终我们会这样使用:
什么要使用函数而不使用混合宏?
Doug Avery在他的文章介绍的方法是使用混合宏(mixin)。混合宏与函数最大区别在于使用方式:
虽然我知道这是个人喜好的问题,但我真的建议:如果只传一个CSS属性,尽量不要使用混合宏。这个功能就是一个很好的示例。
开始编写
因此,我们需要一个函数可能接受一个参数。随意称呼他,我把他称作$layer:
这个函数要做些什么呢?它会在map上寻找给定的参数,看它是否被映射到z-index值。如果是,慢返回值,否则返回一个错误信息。所以我们要创建一个map:
有两件事情:
我喜欢将mixins/functions要用的变量单独配置在一个文件中,比如_config.scss。你喜欢的话可以随意将他们移到z()函数里面。
你可以随意添加、删除和更新你需要的任意keys/values。
现在回到我们的函数中:
在这一点上,我们没有比map-get($z-layers,...)做得更好的方法。这个东西实际上也非常的酷,每次手工一遍又一遍的输入的确让人很烦。
如果该键值存在map中,则会返回映射到的值的索引值。如果该键值不存在,则会返回null。每当一个属性的值为null的时候,Sass的编译不会输出。
所以,如果调用一个未知的键值,Sass只是默默的不输出,这样做不太理想。让我们使用@warn指令发出警告信息,让开发者(也就是你)知道关键值不在map中:
如果你定义的map中有一个未知的关键词(例如SitePoint),Sass在命令终端编译的时候会输出:
是不是很酷。
使用方法
现在,功能已完成,我们应该让他发挥他的功效了。正如文章开头演示的那样,使用方法非常简单:
我的想法是,定义z-index值是需要始终使用这个功能。如果你只是有时候使用,有时候不使用,那么很容易搞死你。
另外,我觉得尽量让这个map保持较轻量级。层级你添加的越多,你的z-index管理也复杂。我建议成对的出现,通过关键词就可以映射出对应的值,这样更便于管理。
使用嵌套上下文加强使用功能
你不可能不知道z-index的值不是绝对的。他们都是相对于自己层叠的内容有关。这也意味着,你试图将内容A的元素在内容B的上面,但内容B却在内容A的上面,然后你就算是设置超过九千的值也将是无效的。
这段话理解起来蛮拗口的。我的理解是这样的:在你的页面中有两个区块A和B。B区块的z-index值高于A区块,现在你要将A区块内的元素层级要高于B区块。此时就算你将A区块内的元素的z-index定义的值超过九千也将是无效的。——@大漠
注:有关于层叠上下文和z-index值的有关知识,请务必阅读Philip Walton写的这篇文章。
现在,如果我们想使用系统认识的层叠的上下文,我们可以在map中嵌套map。举例来说明,如果我们的modal里面有新的层叠上下文,我们想按元素的顺序来设置,那么只需要更新map:
问题是,使用map-get()我们不能在嵌套的map中轻意的获取到我们需要的值。不过,值得庆幸的是,只需要创建一个这样的函数就能实现:
这样就可以了,是不是很简单?现在,我们就可以这样使用我们的modal模块了:
这样将产生这样的结果:
上述示例中使用map嵌套map的时候,并不能编译成功,已向作者询问解决方案。不过通过Sass方面的大神@wo_is神仙提供了一个更简单的解决方案:
有了这个函数功能之外,我们可以通过作者介绍的一样,使用map嵌套map实现。来看一个简单的示例:
这个编译出来的结果:
正是我需要的结果。
不过我会时刻关注作者的相关回答,同时会更新新的解决方案。如果大家有更好的解决方案,也可以通过评论与我们一起分享。
更新
今天收到原作的回信,其提供了另一种解决方案。
整个示例代码:
编译出来的CSS:
未来
美好的未来终将有一天会到来,我们只需要在CSS中使用变量。这样我们不需要这一切。相反,这会发生什么?
看到了?几乎是同样的东西,只不过var()替代了z()和--key替代了key。稍长一些,而且多了会引起混乱,因为这些都是单个变量,而不是通过map来映射。不过他能正常工作,而且保持它的原始性。
结论
我不知道你是怎么想的,但我认为,在Sass中管理z-index,这是一种很好的方法。它不仅好管理z-index,而且还可以使用map映射出需要的z-index值。我们从最后的一个示例就可以看出效果。
就是这样。在Sassmeister上放了一个演示示例。从现在开始,没有理由不将这个功能运用到你的项目当中。
译者手语:整个翻译依照原文线路进行,并在翻译过程略加了个人对技术的理解。如果翻译有不对之处,还烦请同行朋友指点。谢谢!
如需转载烦请注明出处:
英文出处:http://www.sitepoint.com/better-solution-managing-z-index-sass/
中文译文:/article/1214297.html
——作者:Hugo Giraudel
——译者:大漠
最近我们看到有关于Sass管理z-index有好向篇文章:
Jackie Balzer在Smashing Magazine网站上发布的《Sassy z-index Management for Complex Layouts》
Doug Avery在Viget网站上发布的《Sass and z-indexes: a (slightly) better way》
Chris Coyier在CSS-Tricks网站上发布的《Handling z-index》
刚好前几天把Jackie Balzer在Smashing Magazine网站上发布的《Sassy z-index Management for Complex Layouts》一文翻译成中文了:《Sass管理复杂的z-index》。——@大漠
虽然Chris Coyier去年那篇文章最初帮助我解决了管理z-index,但并不怎么得心应手。从技术的角度出发,我在这里提出一个更简单、易用的方案。
因此通过这篇文章,我将系统的引导您,并且向您展示是如何创建管理z-index,以及如何让你在项目中更好的使用它。
为什么要管理z-index的值?
首先我们来回答这个问题:为什么我们要用Sass来管理z-index的值?我们没有看到无数文章如雨后春笋般的冒出来介绍使用Sass管理padding,对不对?那么为什么有关于z-index的会这么多呢?
那么,它必须要这样做,因为z-index很容易造成错误。此外,它接受无穷小到无穷大之间的任意一个值,在很多场合之下,他会搞砸你的事情。
因此,使用像9999999的值,让其在你的屏幕上随意出现。你可能不知道这是怎么一回事,但使用一个扩展工具是非常有趣的。在这种情况之下,使用CSS预处理器可以帮助你搞定这件事情。
概念是什么?
关于这个话题的所有文章介绍的概念几乎都是一样:创建一个可以带有关键词的函数,而且这个关键词可以通过Sass的map映射得到值。这个映射出来的值就是z-index需要输出的值。
Jackie Balzer使用了列表,Doug Avery使用列表和map的混合,Chris Coyier使用了map。事实上,Chris Coyier的解决方案与我的最终方案非常接近,只不过他的解决方案不太适合大系统环境下使用。
最终我们会这样使用:
.element { z-index: z("modal"); }
什么要使用函数而不使用混合宏?
Doug Avery在他的文章介绍的方法是使用混合宏(mixin)。混合宏与函数最大区别在于使用方式:
.element { @include z("modal"); }
虽然我知道这是个人喜好的问题,但我真的建议:如果只传一个CSS属性,尽量不要使用混合宏。这个功能就是一个很好的示例。
开始编写
因此,我们需要一个函数可能接受一个参数。随意称呼他,我把他称作$layer:
@function z($layer) { // ... }
这个函数要做些什么呢?它会在map上寻找给定的参数,看它是否被映射到z-index值。如果是,慢返回值,否则返回一个错误信息。所以我们要创建一个map:
$z-layers: ( "goku": 9001, "shoryuken": 8000, "default": 1, "below": -1, "bottomless-pit": -9000 );
有两件事情:
我喜欢将mixins/functions要用的变量单独配置在一个文件中,比如_config.scss。你喜欢的话可以随意将他们移到z()函数里面。
你可以随意添加、删除和更新你需要的任意keys/values。
现在回到我们的函数中:
@function z($layer) { @return map-get($z-layers, $layer); }
在这一点上,我们没有比map-get($z-layers,...)做得更好的方法。这个东西实际上也非常的酷,每次手工一遍又一遍的输入的确让人很烦。
如果该键值存在map中,则会返回映射到的值的索引值。如果该键值不存在,则会返回null。每当一个属性的值为null的时候,Sass的编译不会输出。
所以,如果调用一个未知的键值,Sass只是默默的不输出,这样做不太理想。让我们使用@warn指令发出警告信息,让开发者(也就是你)知道关键值不在map中:
@function z($layer) { @if not map-has-key($z-layers, $layer) { @warn "No layer found for `#{$layer}` in $z-layers map. Property omitted."; } @return map-get($z-layers, $layer); }
如果你定义的map中有一个未知的关键词(例如SitePoint),Sass在命令终端编译的时候会输出:
WARNING: No layer found for `SitePoint` in $z-layers map. Property omitted.
是不是很酷。
使用方法
现在,功能已完成,我们应该让他发挥他的功效了。正如文章开头演示的那样,使用方法非常简单:
.modal { // ... z-index: z("modal"); } .modal-overlay { // ... z-index: z("modal") - 1; }
我的想法是,定义z-index值是需要始终使用这个功能。如果你只是有时候使用,有时候不使用,那么很容易搞死你。
另外,我觉得尽量让这个map保持较轻量级。层级你添加的越多,你的z-index管理也复杂。我建议成对的出现,通过关键词就可以映射出对应的值,这样更便于管理。
使用嵌套上下文加强使用功能
你不可能不知道z-index的值不是绝对的。他们都是相对于自己层叠的内容有关。这也意味着,你试图将内容A的元素在内容B的上面,但内容B却在内容A的上面,然后你就算是设置超过九千的值也将是无效的。
这段话理解起来蛮拗口的。我的理解是这样的:在你的页面中有两个区块A和B。B区块的z-index值高于A区块,现在你要将A区块内的元素层级要高于B区块。此时就算你将A区块内的元素的z-index定义的值超过九千也将是无效的。——@大漠
注:有关于层叠上下文和z-index值的有关知识,请务必阅读Philip Walton写的这篇文章。
现在,如果我们想使用系统认识的层叠的上下文,我们可以在map中嵌套map。举例来说明,如果我们的modal里面有新的层叠上下文,我们想按元素的顺序来设置,那么只需要更新map:
$z-layers: ( "goku": 9001, "shoryuken": 8000, "modal": ( "base": 500, "close": 100, "header": 50, "footer": 10 ), "default": 1, "below": -1, "bottomless-pit": -9000 );
问题是,使用map-get()我们不能在嵌套的map中轻意的获取到我们需要的值。不过,值得庆幸的是,只需要创建一个这样的函数就能实现:
@function map-deep-get($map, $keys...) { @each $key in $keys { $map: map-get($map, $key); } @return $map; }
这样就可以了,是不是很简单?现在,我们就可以这样使用我们的modal模块了:
.modal { position: absolute; z-index: z("modal", "base"); .close-button { z-index: z("modal", "close"); } header { z-index: z("modal", "header"); } footer { z-index: z("modal", "footer"); } }
这样将产生这样的结果:
.modal { position: absolute; z-index: 500; } /* This is `100` in the modal stacking context */ .modal .close-button { z-index: 100; } /* This is `50` in the modal stacking context */ .modal header { z-index: 50; } /* This is `10` in the modal stacking context */ .modal footer { z-index: 10; }
上述示例中使用map嵌套map的时候,并不能编译成功,已向作者询问解决方案。不过通过Sass方面的大神@wo_is神仙提供了一个更简单的解决方案:
@function z($layers...) { $keys: ''; @each $layer in $layers { $keys: $keys + '.' + $layer; } $keys: str-slice($keys, 2); $output: map-find($z-layers, $keys); @if $output == null { @warn 'No layer found for `#{inspect($layers)}` in $z-layers map. Property omitted.'; } @return $output; } // Before: map-get(map-get(map-get($map, a), b), c) // After: map-find($map, 'a.b.c') @function map-find($map, $keys) { @while str-index($keys, '.') { $index: str-index($keys, '.'); // Child elements $map: map-get($map, str-slice($keys, 0, $index - 1)); @if type-of($map) != map { @return null; } // Rest keys $keys: str-slice($keys, $index + 1); } @return map-get($map, $keys); }
有了这个函数功能之外,我们可以通过作者介绍的一样,使用map嵌套map实现。来看一个简单的示例:
$z-layers: (
'goku': 9001,
'shoryuken': 8000,
'modal': (
'base': 500,
'close': 100,
'header': 50,
'footer': 10
),
'default': 1,
'below': -1,
'bottomless-pit': -9000
);
@function z($layers...) { $keys: ''; @each $layer in $layers { $keys: $keys + '.' + $layer; } $keys: str-slice($keys, 2); $output: map-find($z-layers, $keys); @if $output == null { @warn 'No layer found for `#{inspect($layers)}` in $z-layers map. Property omitted.'; } @return $output; } // Before: map-get(map-get(map-get($map, a), b), c) // After: map-find($map, 'a.b.c') @function map-find($map, $keys) { @while str-index($keys, '.') { $index: str-index($keys, '.'); // Child elements $map: map-get($map, str-slice($keys, 0, $index - 1)); @if type-of($map) != map { @return null; } // Rest keys $keys: str-slice($keys, $index + 1); } @return map-get($map, $keys); }
.modal {
position: absolute;
z-index: z(modal, base);
.close-button {
z-index: z(modal, close);
}
header {
z-index: z(modal, header);
}
footer {
z-index: z(modal, footer);
}
}
.goku {
z-index: z(goku);
}
这个编译出来的结果:
.modal { position: absolute; z-index: 500; } .modal .close-button { z-index: 100; } .modal header { z-index: 50; } .modal footer { z-index: 10; } .goku { z-index: 9001; }
正是我需要的结果。
不过我会时刻关注作者的相关回答,同时会更新新的解决方案。如果大家有更好的解决方案,也可以通过评论与我们一起分享。
更新
今天收到原作的回信,其提供了另一种解决方案。
@function map-has-nested-keys($map, $keys...) { @each $key in $keys { @if not map-has-key($map, $key) { @return false; } $map: map-get($map, $key); } @return true; } @function map-deep-get($map, $keys...) { @each $key in $keys { $map: map-get($map, $key); } @return $map; } @function z($layers...) { @if not map-has-nested-keys($z-layers, $layers...) { @warn "No layer found for `#{inspect($layers...)}` in $z-layers map. Property omitted."; } @return map-deep-get($z-layers, $layers...); }
整个示例代码:
$z-layers: ( "goku": 9001, "shoryuken": 8000, "modal": ( "base": 500, "close": 100, "header": 50, "footer": 10 ), "default": 1, "below": -1, "bottomless-pit": -9000 );
@function map-has-nested-keys($map, $keys...) {
@each $key in $keys {
@if not map-has-key($map, $key) {
@return false;
}
$map: map-get($map, $key);
}
@return true;
}
@function map-deep-get($map, $keys...) {
@each $key in $keys {
$map: map-get($map, $key);
}
@return $map;
}
@function z($layers...) {
@if not map-has-nested-keys($z-layers, $layers...) {
@warn "No layer found for `#{inspect($layers...)}` in $z-layers map. Property omitted.";
}
@return map-deep-get($z-layers, $layers...);
}
.modal {
position: absolute;
z-index: z("modal", "base");
.close-button {
z-index: z("modal", "close");
}
header {
z-index: z("modal", "header");
}
footer {
z-index: z("modal", "footer");
}
}
.goku {
z-index: z("goku");
}
编译出来的CSS:
.modal { position: absolute; z-index: 500; } .modal .close-button { z-index: 100; } .modal header { z-index: 50; } .modal footer { z-index: 10; } .goku { z-index: 9001; }
未来
美好的未来终将有一天会到来,我们只需要在CSS中使用变量。这样我们不需要这一切。相反,这会发生什么?
:root { --z-goku: 9001; --z-shoryuken: 8000; --z-modal: 500; --z-default: 1; --z-below: -1; --z-bottomless-pit: -9000; } .modal { z-index: var(--z-modal); }
看到了?几乎是同样的东西,只不过var()替代了z()和--key替代了key。稍长一些,而且多了会引起混乱,因为这些都是单个变量,而不是通过map来映射。不过他能正常工作,而且保持它的原始性。
结论
我不知道你是怎么想的,但我认为,在Sass中管理z-index,这是一种很好的方法。它不仅好管理z-index,而且还可以使用map映射出需要的z-index值。我们从最后的一个示例就可以看出效果。
就是这样。在Sassmeister上放了一个演示示例。从现在开始,没有理由不将这个功能运用到你的项目当中。
译者手语:整个翻译依照原文线路进行,并在翻译过程略加了个人对技术的理解。如果翻译有不对之处,还烦请同行朋友指点。谢谢!
如需转载烦请注明出处:
英文出处:http://www.sitepoint.com/better-solution-managing-z-index-sass/
中文译文:/article/1214297.html
相关文章推荐
- jquery之管理包装元素集合(从包装集获取元素,get()方法与index()方法的使用)
- 【SharePoint 文档管理解决方案设计系列一】文档使用分析
- jquery之管理包装元素集合(从包装集获取元素,get()方法与index()方法的使用)
- Unity5使用所遇难点及解决方案(基于与unity4的比较)(三.管理状态)
- ABP+AdminLTE+Bootstrap Table权限管理系统第一节--使用ASP.NET Boilerplate模板创建解决方案
- 15个不使用应用性能管理APM解决方案的理由
- 在解决方案中所使用 NuGet 管理软件包依赖
- 安装 SQL SERVER 2008 必须使用 "角色管理工具" 错误 的 解决方案
- 在Delphi中创建线程,请一定使用BeginThread()代替CreateThread()创建线程!(更好的管理异常)
- 【Apache Tomcat 系列】Tomcat集群session管理解决方案(关于sticky session、session replication与使用memcached缓存session)
- 使用Sass管理颜色
- 使用gulp管理sass文件
- 在解决方案中所使用 NuGet 管理软件包依赖
- 安装 SQL SERVER 2008 必须使用 "角色管理工具" 错误 的 解决方案 (转)
- 关于npm和yarn安装node-sass失败并且依旧想使用NPM或者yarn的完美解决方案
- Tomcat集群session管理解决方案(关于sticky session、session replication与使用memcached缓存session)
- Sass管理复杂的z-index
- ABP+AdminLTE+Bootstrap Table权限管理系统第一节--使用ASP.NET Boilerplate模板创建解决方案
- 无责任Windows Azure SDK .NET开发入门篇三[使用Azure AD 管理用户信息--3.1 Index用户列表]
- PTF3 配置管理使用手册