I want to create buttons like these:
In modern browsers the effect is created using inset box-shadow and filters.
For IE8 - pseudo-elements are chosen.
For IE7 - I use special tags wrapped in conditional comments.
Demo: (http://jsfiddle.net/8M5Tt/68/)
/**
* Button w/o images
*/
html {
font-size: 62.5%;
}
body {
font: normal 1em/1em Arial, Tahoma, Verdana, sans-serif;
}
/* layout */
.btn {
display: inline-block;
height: 28px;
border-width: 1px;
border-style: solid;
width: 170px;
box-sizing: content-box;
overflow: hidden;
position: relative;
z-index: 1;
}
.btn {
margin: 15px;
}
.btn.btn_small {
width: 130px;
}
/* ie7 */
.lt-ie8 .btn .before,
.lt-ie8 .btn .after {
position: absolute;
right: -1px;
left: -1px;
display: block;
height: 3px;
}
.lt-ie8 .btn .before {
top: -1px;
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#80ffffff', endColorstr='#00ffffff',GradientType=0 );
}
.lt-ie8 .btn .after {
bottom: -1px;
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00ffffff', endColorstr='#80000000',GradientType=0 );
}
/* /ie7 */
/* ie8 */
.ie8 .btn:before,
.ie8 .btn:after {
content: ' ';
z-index: 1;
position: absolute;
right: -1px;
left: -1px;
display: block;
height: 3px;
}
.ie8 .btn:before {
top: -1px;
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#80ffffff', endColorstr='#00ffffff',GradientType=0 );
}
.ie8 .btn:after {
bottom: -1px;
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00ffffff', endColorstr='#80000000',GradientType=0 );
}
/* /ie8 */
/* typo */
.btn {
/* 28 / 14 = 2.57142857 */
font: bold 14px/2 Arial, Helvetica, Tahoma, sans-serif;
text-transform: uppercase;
}
.btn:active {
line-height: 2.4em;
}
/* color */
.btn {
background-color: #00cccc;
color: #fff;
border-color: #00a8a8;
border-radius: 3px;
cursor: pointer;
box-shadow:
1px 1px 4px rgba(255, 255, 255, 0.5) inset,
-1px -1px 4px rgba(000, 000, 000, 0.5) inset;
}
.btn:hover {
background-color: #00ebeb;
}
.btn:active {
box-shadow:
-1px -1px 4px rgba(255, 255, 255, 0.5) inset,
1px 1px 4px rgba(000, 000, 000, 0.5) inset;
}
/* green */
.btn_green {
background-color: #009900;
border-color: #009600;
}
.btn_green:hover {
background-color: #00c200;
}
/* red */
.btn_red {
background-color: #e00000;
border-color: #c13d00;
}
.btn_red:hover {
background-color: #f00000;
}
<!--
paulirish.com/2008/conditional-stylesheets-vs-css-hacks-answer-neither/
-->
<!--[if lt IE 7]>
<div class="no-js lt-ie9 lt-ie8 lt-ie7" lang="en">
<![endif]-->
<!--[if IE 7]>
<div class="no-js lt-ie9 lt-ie8 ie7" lang="en">
<![endif]-->
<!--[if IE 8]>
<div class="no-js lt-ie9 ie8" lang="en">
<![endif]-->
<!--[if gt IE 8]><!-->
<div class="no-js no-ie" lang="en">
<!--<![endif]-->
<button class="btn btn_green btn_small ">
Send
<!--[if IE 7]> <span class="before"> </span><span class="after"> </span> <![endif]-->
</button>
<button class="btn">
Buy
<!--[if IE 7]> <span class="before"> </span><span class="after"> </span> <![endif]-->
</button>
<button class="btn btn_green">
Activate
<!--[if IE 7]> <span class="before"> </span><span class="after"> </span> <![endif]-->
</button>
<button class="btn btn_red">
Delete
<!--[if IE 7]> <span class="before"> </span><span class="after"> </span> <![endif]-->
</button>
</div>
Main Question: Why don't filters work on pseudo elements in IE8?
Update:
I guess that filters do not work on css-generated content, despite the fact that it is not mentioned on this MSDN page.
I solved my problem in IE8 by applying filters to conditional elements like I do for IE7.
Final demo: (http://jsfiddle.net/matmuchrapna/8M5Tt/73/)
/**
* Button w/o images
*/
html {
font-size: 62.5%;
}
body {
font: normal 1em/1em Arial, Tahoma, Verdana, sans-serif;
}
/* layout */
.btn {
display: inline-block;
height: 28px;
border-width: 1px;
border-style: solid;
width: 170px;
box-sizing: content-box;
overflow: hidden;
position: relative;
z-index: 1;
}
.btn {
margin: 15px;
}
.btn.btn_small {
width: 130px;
}
/* ie78 */
.lt-ie9 .btn .before,
.lt-ie9 .btn .after {
position: absolute;
right: -1px;
left: -1px;
display: block;
height: 3px;
}
.lt-ie9 .btn .before {
top: -1px;
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#80ffffff', endColorstr='#00ffffff',GradientType=0 );
}
.lt-ie9 .btn .after {
bottom: -1px;
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#00ffffff', endColorstr='#80000000',GradientType=0 );
}
/* /ie78 */
/* typo */
.btn {
/* 28 / 14 = 2.57142857 */
font: bold 14px/2 Arial, Helvetica, Tahoma, sans-serif;
text-transform: uppercase;
}
.btn:active {
line-height: 2.4em;
}
/* color */
.btn {
background-color: #00cccc;
color: #fff;
border-color: #00a8a8;
border-radius: 3px;
cursor: pointer;
box-shadow:
1px 1px 4px rgba(255, 255, 255, 0.5) inset,
-1px -1px 4px rgba(000, 000, 000, 0.5) inset;
}
.btn:hover {
background-color: #00ebeb;
}
.btn:active {
box-shadow:
-1px -1px 4px rgba(255, 255, 255, 0.5) inset,
1px 1px 4px rgba(000, 000, 000, 0.5) inset;
}
/* green */
.btn_green {
background-color: #009900;
border-color: #009600;
}
.btn_green:hover {
background-color: #00c200;
}
/* red */
.btn_red {
background-color: #e00000;
border-color: #c13d00;
}
.btn_red:hover {
background-color: #f00000;
}
<!--
paulirish.com/2008/conditional-stylesheets-vs-css-hacks-answer-neither/
-->
<!--[if lt IE 7]>
<div class="no-js lt-ie9 lt-ie8 lt-ie7" lang="en">
<![endif]-->
<!--[if IE 7]>
<div class="no-js lt-ie9 lt-ie8 ie7" lang="en">
<![endif]-->
<!--[if IE 8]>
<div class="no-js lt-ie9 ie8" lang="en">
<![endif]-->
<!--[if gt IE 8]><!-->
<div class="no-js no-ie" lang="en">
<!--<![endif]-->
<button class="btn btn_green btn_small ">
Send
<!--[if lte IE 8]> <span class="before"> </span><span class="after"> </span> <![endif]-->
</button>
<button class="btn">
Buy
<!--[if lte IE 8]> <span class="before"> </span><span class="after"> </span> <![endif]-->
</button>
<button class="btn btn_green">
Activate
<!--[if lte IE 8]> <span class="before"> </span><span class="after"> </span> <![endif]-->
</button>
<button class="btn btn_red">
Delete
<!--[if lte IE 8]> <span class="before"> </span><span class="after"> </span> <![endif]-->
</button>
</div>
Update 2:
I solved my problem, but the main question is still unanswered:
“Why don't filters work on pseudo elements in IE8?”
Started a bounty.
Update 3: I created testcase only for filters(and also -ms-filter) on ie8:
But the filters still don't want to work on pseudo-elements.
Update 4: I think Scotts answer is closest to truth.
It is important to realize that pseudo-elements are considered descendants of their associated element. You may set a negative z-index for these pseudo-elements, but in order for them to actually appear below their parent element, you must create a new stacking context for the parent.
A CSS pseudo-element is used to style specified parts of an element. For example, it can be used to: Style the first letter, or line, of an element. Insert content before, or after, the content of an element.
A CSS pseudo-element is a keyword added to a selector that lets you style a specific part of the selected element(s). For example, ::first-line can be used to change the font of the first line of a paragraph.
The question is "Why don't filters work on pseudo elements in IE8?" The following is as close to a definitive answer as I can muster. It comes from the information on this page.
The gradient
filter is a "procedural surface" (along with alphaimageloader
). A procedural surface is defined so:
Procedural surfaces are colored surfaces that display between the content of an object and the object's background.
Read that carefully. It is essentially another "layer" you might say between the content of an object and that object's background. Do you see the answer to the question? What is created by :before
and :after
... Yes! Content. Specifically as MSDN notes:
The ::before and ::after pseudo-elements specify the location of content before and after an element in the document tree. The content attribute, in conjunction with these pseudo-elements, specifies what is inserted.
The generated content interacts with other boxes as if they were real elements inserted just inside their associated element.
Now, if it is content that is generated, then it is not an "object" containing content, but the content itself (which happens to have some behavior similar to an element object that might contain content).
Thus, there is no "object" containing "content" (since it is content) between which the filter
can place a procedural surface for content generated by a pseudo-element (i.e. "false element"). A gradient
must be applied to the object, and then the procedural surface is placed between it and the content.
The documentation on -ms-filter
-a synonym for filter
- states:
An object must have layout for the filter to render.
My first guess was that the :before
content doesn't have hasLayout
set to true. And while it's probably not set to true, it's probably not set to false either. For starters, when I followed the hasLayout docs to force the content to get hasLayout = true
(see jsfiddle) it didn't solve anything.
So I'd say it's neither true nor false. Instead, it's probably undefined. I noted in the same docs it says about the source of this property:
object.currentStyle.hasLayout
If we have a look at the W3 documentation on the content property it says:
Generated content does not alter the document tree. In particular, it is not fed back to the document language processor (e.g., for reparsing).
So, a possible conclusion would be that the generated content is not an object, as such it does not have a currentStyle
property, and thus also doesn't have hasLayout
set to true
. This would be the reason that filters don't work on the generated content, and thus answer the question.
At first sight I thought I had found a hint in the console of the above fiddle:
document.querySelectorAll('div')[0].currentStyle.hasLayout;
// true
document.querySelectorAll('div:before')[0].currentStyle.hasLayout
// Unable to get value of the property 'currentStyle':
// object is null or undefined
But as mentioned in the comments by @BoltClock: querySelectorAll cannot access pseudo-elements.
Another hint (though -again- nothing more than a hint) that filter
won't work on pseudo-elements can be found in this msdn introduction on filters, stating (emphasis mine):
Filters are applied to HTML controls through the filter property
Although I'm not sure what is meant by "HTML controls", I wouldn't expect content generated by the :before
pseudo-element to be considered a "HTML Control".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With