8

I'm trying to use CSS currentColor as a border-color to generate CSS triangles using :after content. This works great in all browsers I've tried, except one: Safari seems to be caching the currentColor from the first triangle it generates, and then using that everywhere.

Here's what I'm seeing -- expected behavior from Chrome (and Firefox, and IE9+):

Chrome screenshot

Incorrect behavior from Safari 8.0.4 on Yosemite 10.10.2 (same on iOS 8.2) -- notice all three triangles are red, not the currentColor of their elements:

Safari screenshot

Here's a fiddle with the full code demonstrating the problem. The relevant CSS:

span {
    display: inline-block;
    border-bottom: 2px solid currentColor;
}

span::after {
    /* Generate a triangle (based on Foundation's css-triangle mixin) */
    content:"";
    display: inline-block;
    width: 0;
    height: 0;
    border: inset 0.4em;
    /* Safari seems to cache this currentColor... */
    border-color: currentColor transparent transparent transparent;
    border-top-style: solid;
}

.red { color: #c00; }
.blue { color: #009; }

The HTML is simple:

<div>
    <span class="red">Red</span>
    <span>Default</span>
    <span class="blue">Blue</span>
</div>

Is this a bug in Safari? A matter of interpretation on the CSS spec?

More importantly, any suggestions for working around this? I'd hate to have to explicitly declare the color in separate :after rules for each element. (Using currentColor really simplifies maintenance as our other CSS changes.)

medmunds
  • 5,950
  • 3
  • 28
  • 51
  • This is probably similar to [this question](http://stackoverflow.com/questions/23936150/issues-with-css-currentcolor-keyword-in-ios-and-safari), which is using currentColor with other CSS selectors. But the only responses there so far claim this is expected behavior (which seems in conflict with all other browser implementations), or suggest avoiding currentColor altogether (which I don't think can work for my case). – medmunds Apr 01 '15 at 20:39

2 Answers2

6

So, this turns out to be an actual Safari bug (which might be fixed soon).

I was able to work around it using this suggestion that border-color defaults to currentColor. Replace this:

    border-color: currentColor transparent transparent transparent;

with expanded properties that avoid mentioning currentColor:

    /* border-top-color: currentColor; is the default behavior */
    border-right-color: transparent;
    border-bottom-color: transparent;
    border-left-color: transparent;

and the problem goes away in Safari (and it still works in the other browsers).

Community
  • 1
  • 1
medmunds
  • 5,950
  • 3
  • 28
  • 51
  • 1
    Although the WebKit bug was resolved on 2015-03-29, the fix still doesn't seem to have landed in Safari 8.0.7. – medmunds Aug 21 '15 at 01:37
  • This seems to be fixed as of Safari 9.0.2 (maybe earlier), so the workarounds should no longer be necessary. – medmunds Dec 17 '15 at 01:27
  • This still appears to be an issue on iOS Safari (or at least, a very similar bug). – Tim Malone Aug 03 '16 at 07:07
  • @TimMalone in Safari on iOS 9.3.3, the [demonstration fiddle](https://jsfiddle.net/medmunds/kkbnm6cm/) from the question seems to work fine. Are you maybe using an earlier iOS version? [navigator.userAgent: ... AppleWebKit/601.1.46 ...] – medmunds Aug 03 '16 at 17:37
1

Even I faced a similar issue, so i have to go with a small js trick.

With this trick we can use the currentColor attribute to be set correctly in the desired elements. but it can be achieved only for normal elements. so i moved the pseudo elements into normal elements.

You have to force safari to redraw elements to achieve this. To achieve redrawing elements simply hide and show it.

var nodeStack =[element];
while (node = nodeStack.pop()) {
    if (node.nodeType == 1) {
        node.style.display="none";
        node.style.display="";
        var i = node.childNodes.length;
        while (i--) {
            nodeStack.push(node.childNodes[i]);
        }
    }
}

Check this simple codepen (Your code with little modification)

and also read this for brief info

Pseudo elements cannot be achieved through this trick. You have to move that into a span or some other element.

Community
  • 1
  • 1
Prasanna Rkv
  • 419
  • 4
  • 12