Search code examples
cssfirefoxsvgz-indexsvg-filters

SVG filter in Firefox breaks z-index


I am creating tabbed menu with SVG images as background. I need the the tabs to overlap each other in reverse order - first over second, second over third. And I need svg shadow, to work in Firefox.

Howerer, when I apply the shadow, the z-index of .after element gets broken which breaks the overlap. Is there any way to change stacking order/fix this? Here is sample source:

div{
    background-color: grey;
    padding-top:20px;
    padding-bottom: 20px;
}
ul.tabs-nav{
	margin: 0px;
	padding: 0px;
	list-style-type: none;
	margin-left: 10px;
	height: 40px;
	overflow: hidden;
}
ul.tabs-nav li{
	margin: 0px -38px 0px 0px;
	padding: 0px;
	display: block;
	float: left;
	text-decoration: none;
	filter: url("#drop-shadow");
}
ul.tabs-nav li a{
	background-color: #5d6c7a;
	text-decoration: none;
	height:40px;
	line-height: 40px;
	float:left;
	color: white;
	font-size: 14px;
	vertical-align: baseline;
	padding-left: 10px;
	padding-right: 10px;
}

ul.tabs-nav span.before{
	background-image: url("https://dl.dropboxusercontent.com/u/10056766/fiddle/tab_grey.svg");
    background-position: left top;
	display: block;
	float: left;
	height: 40px;
	width: 40px;
	position: relative;		
}

ul.tabs-nav span.after{
	background-image: url("https://dl.dropboxusercontent.com/u/10056766/fiddle/tab_grey.svg");
    background-position: right top;
	display: block;
	float: left;
	height: 40px;
	width: 40px;
	position: relative;
	z-index:1;
}

ul.tabs-nav li:first-child span.before{
	background-image: url("https://dl.dropboxusercontent.com/u/10056766/fiddle/tab_white.svg");
    background-position: left top;
	display: block;
	float: left;
	height: 40px;
	width: 40px;
	position: relative;		
}

ul.tabs-nav li:first-child span.after{
	background-image: url("https://dl.dropboxusercontent.com/u/10056766/fiddle/tab_white.svg");
    background-position: right top;
	display: block;
	float: left;
	height: 40px;
	width: 40px;
	position: relative;
	z-index:1;
}

ul.tabs-nav li:first-child a{
    background-color: white;
    color: black;
}
<div>
<ul class="tabs-nav" style="padding: 0;">

	<li style="z-index: 10;" class="tab
	tabs-active
	"><span class="before"></span><a href="/foo.jsp" class="">User</a><span class="after"></span></li>
	<li style="z-index: 8;" class="tab
	"><span class="before"></span><a href="/foo.jsp" class="">Developer</a><span class="after"></span></li>
	<li class="tab
	"><span class="before"></span><a href="/foo.jsp" class="">Users</a><span class="after"></span></li>
	<li class="tab
	"><span class="before"></span><a href="/foo.jsp" class="">Roles</a><span class="after"></span></li>
	<li class="tab
	"><span class="before"></span><a href="/foo.jsp" class="">Attributes</a><span class="after"></span></li>
	<li class="tab
	"><span class="before"></span><a href="/foo.jsp" class="">Screens</a><span class="after"></span></li>
	<li class="tab
	"><span class="before"></span><a href="/foo.jsp" class="">Locales</a><span class="after"></span></li>
	<li class="tab
	"><span class="before"></span><a href="/foo.jsp" class="">Providers</a><span class="after"></span></li>
	</ul>
    
</div>

<svg height="0" xmlns="http://www.w3.org/2000/svg">

<filter id="drop-shadow">

<feGaussianBlur in="SourceAlpha" stdDeviation="2.2"/>

<feOffset dx="12" dy="2" result="offsetblur"/>

<feFlood flood-color="rgba(0,0,0,0.2)"/>

<feComposite in2="offsetblur" operator="in"/>

<feMerge>

<feMergeNode/>

<feMergeNode in="SourceGraphic"/>

</feMerge>

</filter>

</svg>

http://jsfiddle.net/mark_bacon/5vnefef5/3/

Turn off filter of li element and you will see how it should look.


Solution

  • The filter property creates a CSS stacking context. That means that the z-index property on any child elements will only control how the child content is stacked amongst each other, not how they are stacked relative to other elements on the page.

    You're applying filter to your li elements, but you're applying the z-index to the child spans. This will raise up those spans above the other content in the li, but all the content within the list element will be flattened into one layer before being stacked with the rest of the page. And since you don't set a z-index value on the li itself, the default stacking order applies. In other words, elements later on in the document get drawn over top.

    You've got a lot of things going on in this example, but I'm pretty sure you could get the effect you want just by setting z-index:1 on the li:first-child itself.