Sass管理复杂的z-index

本文由大漠根据Jackie Balzer的《Sassy Z-Index Management For Complex Layouts》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明原作者相关信息http://www.smashingmagazine.com/2014/06/12/sassy-z-index-management-for-complex-layouts/

——作者:Jackie Balzer

——译者:大漠

z-index本身就是一个棘手的事情,在一个复杂的布局中管理z-index的顺序(层级)更是困难。不同的层叠顺序和内容,要跟踪他们的数字增加是很难的事情——而且他们来自CSS文件,忘了他吧!因为z-index可以造就一个UI元素可见或不可见,使您的网站的用户界面工作秩序是很微妙的。

因为z-index值跟上下文有关系,一旦你开始使用它,它可以很容易为其他元素先显示(如果元素需要)。在网站上查找z-index: 99999规则,它并少见,但使用臭名昭著的99999实属无耐之举。它经常被误用,认为让元素可以高于一切元素,但z-index并不总是那么简单。它也不是完全可扩展:你有什么东西是要放在最顶上的?

另一种策略是两位数递增z-index的值,让你有足够的空间给其他元素插入值,但并没有解决如何跟踪z-index值的问题,当你想在他们之间添加值时,它不能很好的扩展。

每个实例提出了一个问题:

  1. 为什么这个元素有这样的z-index值?所有其他元素上下文关系是什么?
  2. 有顺序的上下文中插入z-index合适?如果我增加一项,哪个会受影响?
  3. 如果添加一个元素的层叠顺序,其中z-index的值我必须增加?

使用Sass管理顺序

使用Sass的列表来控制上述所有因素是非常容易的。让我们以Behance主页做为一个例子:

Sass管理复杂的z-index

我们需要管理的顺序包括项目遮罩层、过滤器栏、位置搜索弹出窗、下拉菜单和导航。按这个顺序,从下到上。我们可以创建一个Sass的列表,如下:

$elements: project-covers, sorting-bar, modals, navigation;

在这个列表中,我们希望我们的元素的出现,从低到高。数组的顺序表示元素的z-index值。我们使用Sass的index()函数z-index的值分配给每个元素。

例如:

.project-cover {
   z-index: index($elements, project-covers);
}

这将输出:

.project-cover {
   z-index: 1;
}  

这是因为project-cover是列表中的第一个元素,他的索引值是1,z-index顺序中最低的元素。让我们用Sass给列表中其他元素指定z-index值:

.sorting-bar {
   z-index: index($elements, sorting-bar);
}
.modal {
   z-index: index($elements, modals);
}
.navigation {
   z-index: index($elements, navigation);
}  

现在编译出来的CSS看起来像这样:

.project-cover {
   z-index: 1;
}
.sorting-bar {
   z-index: 2;
}
.modal {
   z-index: 3;
}
.navigation {
   z-index: 4;
}

现在你可以将类名应用到相应的元素上。但是,如果我们想要给一个元素添加到现有的层叠顺序中呢?假设用户鼠标悬停在一个用户名上会弹出一个提示框(tooltip),他的位置在project-cover上面,但在其他元素的下面。

Sass管理复杂的z-index

在乏味的CSS中,我们需要重新更新sorting-barmodalnavigationz-index的值。使用Sass,我们只需要为新元素更新列表:

$elements: project-covers, user-tooltip, sorting-bar, modals, navigation;  

因为sorting-barmodalnavigationz-index的值在列表中已发生变化(以前他们的z-index的值是2,3,4,现在变成了3,4,5)。我们编译出来的CSS会自动调整他们的z-index值,用以新的位置。我们只需要在Sass中添加下面的代码:

.user-tooltip {
   z-index: index($elements, user-tooltip);
}  

这个时候,编译出来的CSS如下:

.user-tooltip {
   z-index: 2;
}
.sorting-bar {
   z-index: 3;
}
.modal {
   z-index: 4;
}
.navigation {
   z-index: 5;
}

通过层叠上下文顺序解决方案

假设我们的布局更复杂,有多个层叠的上下文和层叠顺序。(请记住,要让z-index起作用,需要确保position的值不是static,这就是新创建一个层叠的内容,只要将层叠顺序值指定所有元素的父元素上。)在这种情况下,一个列表可能不够使用。我们需要创建多个列表,每个列表会被认为是一个上下文。

Sass管理复杂的z-index

$elements: project-covers, user-tooltip, sorting-bar, modals, navigation;
$modal-elements: fields, form-controls, errors, autocomplete-dropdown;

.modal {
   z-index: index($elements, modals);

   .field {
      z-index: index($modal-elements, fields);
   }
   .form-controls {
      z-index: index($modal-elements, form-controls);
   }
   .error {
      z-index: index($modal-elements, errors);
   }
   .autocomplete-dropdown {
      z-index: index($modal-elements, autocomplete-dropdown);
   }

} /* .modal */

编译出来的CSS:

.modal {
   z-index: 4;
}
.modal .field {
   z-index: 1;
}
.modal .form-controls {
   z-index: 2;
}
.modal .error {
   z-index: 3;
}
.modal .autocomplete-dropdown {
   z-index: 4;
}  

跨网站解决方案

这种技术最主要的要求就是坚持维护。任何硬性的z-index值都可能危及到那些列表的完整性。正因为如此,你会发现,你可能在一个网站会有多个页面要定义z-index的值。最简单的方案就是创建一个局部的文件,包括整个网站的列表,然后就可以在需要的地方使用。(你可能有了这样的局部文件,比如用来存储网站颜色,字体等变量——这是类似的一个做法)。

_ZINDEX.SCSS

$elements: project-covers, user-tooltip, sorting-bar, modals, navigation;
$modal-elements: fields, form-controls, errors, autocomplete-dropdown;   

MYPAGE.SCSS

@import '_zindex.scss'

.modal {
   z-index: index($elements, modals);
}   

每个页面修改或合并全局的列表也是可能的。你导入你的那部分,然后使用Sass的列表函数(或者更高级的功能)修改你需要的部分。例如:

import '_zindex.scss'

$modal-elements: append($modal-elements, close-button);
$elements: insert-nth($elements, sidebar-filters, 3);

.modal .close-button {
   z-index: index($modal-elements, close-button);
}
.sidebar-filter {
   z-index: index($elements, sidebar-filter);
}   

这个Sass会在modal-elements列表最后面插入一个close-buttons和在elements列表第三个顺序中插入sidear-filters,而且不会影响其他页面使用的_z-index.scss

错误的报告

经常检查代码中的错误,以避免造成错误。例如你想给不在你列表中的项设置z-index值,你可能会发现一个意想不到的输出:

.objects {
   z-index: index($elements, thing-not-in-my-list);
}
.objects {
   z-index: false;
}

因为false不是z-index的有效值,我们不希望他出现在我们编译出来的代码中。我们可以自定义一个函数,使用Sass的@warn,在一开始就告诉我们东西是否出了问题。

@function z($list, $element) {

   $z-index: index($list, $element);

   @if $z-index {
      @return $z-index;
   }

   @warn 'There is no item "#{$element}" in this list; choose one of: #{$list}';
   @return null;
}   

这个函数接受 index()相同的参数,但在返回值之前他会检查我们要求的东西是否存在列表中。如果该值存在,他就会返回index()的索引值,就像刚才一样。如果该值不存在,他会发现两件事:

  1. 会输出警告信息,告诉你选项不在列表中,并且会将列表打印出来,以供你做出选择
  2. 将会返回null值,告诉Sass不会打印出相应的规则

而不是以下无效的CSS:

.objects {
   z-index: false;
}   

z-index的值一直不会打印出来。如果他在你的规则中是唯一的一个规则,那么Sass甚至会做出不打印的选择,从而最大限度的减少不必要的输出。

结论

跟踪上下文的层叠顺序,使用CSS是非常难的,但使用预处理程序使它变得更容易。有许多方法可以处理它,但我们看到这里的做法是最简单的,需要最少的维护。而且由于Sass的列表和函数如此强大,你必须扩大这项技术,因为你需要更好的掌握他们。

相关资源

译者手语:整个翻译依照原文线路进行,并在翻译过程略加了个人对技术的理解。如果翻译有不对之处,还烦请同行朋友指点。谢谢!

出处:

英文出处:http://www.smashingmagazine.com/2014/06/12/sassy-z-index-management-for-complex-layouts/

中文译文:http://www.w3cplus.com/preprocessor/sassy-z-index-management-for-complex-layouts.html