understanding css inherited currentColor - css

I was curious about currentColor and how it behaves when it is inherited and/or used in other properties.
Another aspect is omitting a color value in the border-property for example which should default to the text-color.
.outer {
color: #f90;
border: 5px solid;
box-shadow: 0 0 15px;
text-shadow: 2px 2px 3px;
}
<div class="outer">
Outer Div
</div>
Nothing fancy in the above Snippet.
The shadows and the border is the same Color as the Text.
Now lets inherit the color:
.outer {
color: #f90;
border: 5px solid;
box-shadow: 0 0 15px;
text-shadow: 2px 2px 3px;
}
.inner {
color: lime;
display: inline-block;
border: inherit;
box-shadow: inherit;
}
<div class="outer">
Outer Div
<div class="inner">
Inner Div no CurrentColor
</div>
</div>
Resutls:
In IE11 & Chrome 43 only the Text-Color is lime.
In Firefox 38 on the other hand the shadows are green too. (Note not the border)
When actively setting everything to currentColor the Browsers are showing the same result by displaying only the text in lime and everything else in orange. (As you can see in the final snippet at the bottom)
/**
* playing with currentColor
*/
body {background: darkgray;} /* friendly wink */
.outer {
width: 85%;
color: #f90;
border: 5px solid;
box-shadow: 0 0 15px;
text-shadow: 2px 2px 3px;
padding: 15px; margin: 15px;
}
.outer.currentColor {
border: 5px solid;
box-shadow: 0 0 15px currentColor;
text-shadow: 2px 2px 3px currentColor;
}
.inner {
color: lime;
display: inline-block;
border: inherit;
box-shadow: inherit;
}
.inner.resetting {
border-color: currentColor;
/* text-shadow-color: currentColor; /* does not exist */
/* box-shadow-color: currentColor; /* does not exist */
}
<div class="outer">
Outer Div
<div class="inner">
Inner Div no CurrentColor
</div>
</div>
<div class="outer currentColor">
Outer Div
<div class="inner">
Inner Div with CurrentColor
</div>
<div class="inner resetting">
Inner Div with CurrentColor
</div>
</div>
Questions:
Why is there a difference with the border in Firefox when omitting currentColor
Why does inherit not use the color value on the same element?
Is there a way to use the same properties and switching the color? (for border-color there is as you can see in the example by resetting it)
Here is also a dabblet link if you want to play around with it:
http://dabblet.com/gist/587ea745c7cda7a906ee

So, a few things here:
The CSS Working Group agreed to change the meaning of currentColor between CSS Color level 3 and CSS Color level 4. In level 3, it is resolved at computed value time and the computed value is inherited; in level 4, the keyword currentColor is inherited as a computed value and it is resolved at used value time.
There were a number of reasons to make this change, though I can't find the minutes, and I've forgotten all the details. (I could find minutes at https://lists.w3.org/Archives/Public/www-style/2014Feb/0052.html discussing the change after the fact.) It makes things worse for transitions/animations, but better in a number of other cases. It slightly increases implementation complexity, but improves performance (at least in Gecko).
I think most implementations have not yet had a chance to update to the new rules in Level 4. Gecko certainly has not, though it's on my list of things to do (but not at the top).
Firefox has, for a long time (since well before currentColor existed) implemented a special internal value as the initial value of border-*-color and outline-color. (We also do the same for text-decoration-color, but haven't done so since 1998/1999.) This works like the level 4 currentColor does, so once we switch our implementation we can unify the two things, but we couldn't switch our implementation with the level 3 currentColor, since it would have been a significant performance and memory hit given that it was the initial value of the property. (Really, unifying our implementation means doing the same work that we've done for those properties for every other property that takes a color value.)
text-shadow and box-shadow, when the color is omitted, have explicitly specified the behavior for when the color is omitted as being equivalent to the way level 4 defines currentColor, even before currentColor worked that way: see the definition of box-shadow (the definition of text-shadow just points to box-shadow).

Why is there a difference with the border in Firefox when omitting currentColor
CSS's specifications for inheriting on text-shadow say it should inherit the .inner currentColor if it itself is set to inherit, but box-shadow is unspecified and looks like browsers are inconsistent on the implementation. Possible bug.
Why does inherit not use the color value on the same element?
It appears to inherit the computed value and not the inputted one. Example:
.outer {
color:red;
box-shadow: 2px 2px 2px; /* color omitted */
}
.inner {
box-shadow: inherit;
/* translates to:
box-shadow: 2px 2px 2px red; */
}
Like I said, it's faulty implementation.
Is there a way to use the same properties and switching the color? (for border-color there is as you can see in the example by resetting it)
How about explicitly duplicating instead of inheriting? This would give you the best result without resulting to SASS/LESS, imo.
.outer {
color: #f90;
}
.outer, .inner {
border: 5px solid;
box-shadow: 0 0 15px;
text-shadow: 2px 2px 3px;
}
.inner {
color: lime;
display: inline-block;
}
<div class="outer">
Outer Div
<div class="inner">
Inner Div no CurrentColor
</div>
</div>

Related

Why are half of my <hr>s being styled differently than the others?

I don't know why, but when I try and style my horizontal rules in css, every other hr looks different. See below:
https://i.imgur.com/ltZdncM
When I increase the border size to 2px, the gap in between the top and bottom borders is filled in, but then half the horizontal rules are thicker than the others.
MY CODE:
hr {
border: 1px solid #07234f;
width: 300px;
}
<body>
<hr>
<hr>
<hr>
<hr>
</body>
I expect all the horizontal rules to look similar. Any idea why they look different? How can I fix this issue?
You're placing a border on all sides of the hr. But Chrome, for example, already has a user-agent stylesheet that sets an inset border style on hr's. I was able to replicate your issue at various px units.
One way to fix this issue is the following:
kill whatever border the user agent stylesheet may be implementing behind your back: border: 0
Then set a border along a single edge (top or bottom) and set it to the px value you'd like. (I chose border-top: 2px.)
Set an explicit height on the hr equal to the pixel value you chose for border-top to prevent (in this case) Chrome's user agent stylesheet from displaying border-style: inset on your element.
hr {
border: 0;
border-top: 2px solid #07234f;
height: 2px;
width: 300px;
}
<body>
<hr>
<hr>
<hr>
<hr>
</body>
Another approach might be to explicitly set the individual border properties yourself so as to avoid confusing Chrome about which border style to apply (it appears that even with border: 1px solid #000000, Chrome still insists on applying the inset styling).
hr {
border-width: 2px 0 0 0;
border-style: solid;
border-color: #07234f;
width: 300px;
}
UPDATE
One way to implement a double line would be to set a top and bottom border with an explicit height:
hr {
border-width: 2px 0 2px 0;
height: 4px;
border-style: solid;
border-color: #07234f;
width: 300px;
margin: 16px auto;
}
You could also use border-style: double like this:
hr {
border-width: 4px 0 0 0;
border-style: double;
border-color: #07234f;
width: 300px;
margin: 16px auto;
}
Also, here's some inspiration for your hr styling needs: https://css-tricks.com/simple-styles-for-horizontal-rules/
It's a bit dated, but may give you some ideas.
UPDATE 2
This works fairly well, though I do still see some aberrations at various zoom levels. Does the following work for you at normal zoom? Is it only when you manually zoom the viewport that you see aberrations?
It's a conundrum.
body {
background-color: lightblue;
}
hr {
border: 0;
width: 300px;
margin: 16px auto;
height: 2px;
background-image: url("data:image/svg+xml,%3Csvg width='300' height='2' viewBox='0 0 376 2' fill='none' xmlns='http://www.w3.org/2000/svg'%3E %3Cline y1='0.5' x2='300' y2='0.5' stroke='black' stroke-opacity='0.1'/%3E %3Cline y1='1.5' x2='300' y2='1.5' stroke='white' stroke-opacity='0.3'/%3E %3C/svg%3E ");
}

Don't affect positioning of other elements on border-width changes

I'd like to change border-width of a circle on hover without affecting the positioning of other elements.
It will be more clear with this jsFiddle.
HTML
<span class="menu"><i class="cercle"></i>Foo</span>
<span class="menu"><i class="cercle"></i>Bar</span>
CSS
.menu{
margin-right: 10px;
cursor: pointer
}
.cercle{
border-radius: 16px;
margin-right: 5px;
vertical-align: middle;
width: 16px;
height:16px;
display:inline-block;
border: 5px solid #ff9c08
}
.menu:hover i{
border-width: 3px;
transition:border-width .1s
}
There are a couple of different ways you can go about achieving the effect you desire.
1. Using box-sizing: border-box:
Normally, neighbouring elements are affected by the changing an element's border-width property, because the elements are relatively positioned and the space each one occupies changes when the border-width changes. Using box-sizing: border-box ensures the width of the border is included in the dimensions of the element.
.cercle {
box-sizing: border-box;
}
2. Using box-shadow:
An alternative would be to use box-shadow property, instead, to imitate the visual appearance of a border but without its particular behaviour. The shadow of an element doesn't affect neighbouring elements when modified, so it's another good option to consider when trying to achieve the effect you desire.
.cercle {
box-shadow: inset 0 0 0 4px #ff9c08;
}
.menu:hover > .cercle {
box-shadow: inset 0 0 0 2px #ff9c08;
}
Check out more about the browser compatibility of box-sizing and box-shadow to see which suits you better. An updated version of your jsfiddle can be found here and a snippet just below.
Snippet:
.menu {
margin-right: 10px;
cursor: pointer;
}
.cercle {
width: 16px;
height: 16px;
display: inline-block;
margin-right: 5px;
vertical-align: middle;
border-radius: 16px;
}
#ex1 .cercle {
border: 4px solid #ff9c08;
box-sizing: border-box;
}
#ex1 .menu:hover i {
border-width: 2px;
transition: border-width .1s;
}
#ex2 .cercle {
box-shadow: inset 0 0 0 4px #ff9c08;
}
#ex2 .menu:hover .cercle {
box-shadow: inset 0 0 0 2px #ff9c08;
transition: box-shadow .1s;
}
<div id = "ex1">
<span class="menu"><i class="cercle"></i>Foo</span>
<span class="menu"><i class="cercle"></i>Bar</span>
</div>
<br>
<div id = "ex2">
<span class="menu"><i class="cercle"></i>Foo</span>
<span class="menu"><i class="cercle"></i>Bar</span>
</div>
This is not possible without having a border already on the element as adding a border would increase the width and height of the element. The technique I prefer is to have a transparent border on non-hover state to begin with and change the colour on hover.
.menu {
border: 3px solid rgba(0,0,0,0);
}
.menu:hover {
border-color: black;
}
This actually is possible, with box-sizing.
Setting .cercle { box-sizing: border-box; } means that the width and height of the .cercle elements includes the size of the border.
As such, the size of the .cercles will shrink with box-sizing: border-box, but that's an easy fix: just up the height and width from 16px to 21px (a change of 5px, since 5px was the size of the border).
Hopefully I explained how this works okay!
See this jsfiddle for functioning code:
https://jsfiddle.net/xhanrkzy/3/
I would assume you wanted to scale it down.
I used the transform property to do this:
.menu:hover i {
/* border-width: 3px; */
transform: scale(0.95);
transition: border-width .1s
}
In general "box-sizing: border-box" is a great simple solution. Note you can set it to apply to every element by default in your style-sheet. Here's a nice article about it: https://css-tricks.com/box-sizing/ .
Be aware that using border-box and changing the border-width means there is less space inside the circle etc. That is because the border "grows inwards" when using border-box. Therefore changing the border-width can affect the position of elements INSIDE the DOM-element whose border-width you are changing. Whether you consider those to be "other elements" (as per your question) is a matter of semantics.

Inherit and add value to multi-value CSS property?

As we all know, some CSS properties can have multiple values simultaneously. A good example is CSS3's box-shadow.
However, sometimes it may be desirable for a class or ID to add to these values. For example, if I have an element with an inset box-shadow value, I may want to add an outer glow to the box with an .active class. Unfortunately, this overwrites the previous value.
Is it possible to inherit a value and simultaneously add to it? Below is a non-working example of what I am hoping can be accomplished. Notice how the end-result does not glow.
div {
background-color: #09F;
border-radius: 10px;
box-shadow: 3px 3px 10px #FFF inset, -3px -3px 10px #00F inset;
height: 100px;
width: 100px;
}
div.active {
box-shadow: inherit, 0 0 10px #FF0;
}
<div class="active"></div>

Add internal border on div within the padding

I have a div with a padding and I would like to add an "internal" border, considering padding. For example, consider to have this CSS:
div#border {
padding:10px;
border:1px solid;
background-color:#ccc;
}
My goal in this case is to create an internal solid border, far 10px from div border, but I only get an external border (jsFiddle). Adding an internal div does the trick but adds an extra HTML element (jsFiddle):
div#border {
padding:10px;
background-color:#ccc;
}
div#internal {
border:1px solid;
}
I've tried to add an outline as suggested here, but when I have two adiacent divs with outline, there's an overlap between (jsFiddle).
Is there a pure-CSS solution to add an "internal" border to a div, considering padding, without adding extra HTML elements and without overlapping on adiacent divs?
Solution #1 Use box-shadow with inset
We can take advantage of the fact that multiple values can be used for the box-shadow property.
The trick here is to set the first inner shadow with the background color of the div, and the second inner shadow - which is slightly larger - with the color of the border.
FIDDLE
div#border {
padding: 10px;
box-shadow: inset 0 0 0 9px #ccc, inset 0 0 0 10px black;
background-color: #ccc;
}
<div id="border">some content</div>
Solution #2 Use outline with the outline-offset property.
outline:1px solid;
outline-offset: -10px;
FIDDLE
div#border {
padding: 10px;
outline: 1px solid;
outline-offset: -10px;
background-color: #ccc;
}
<div id="border">some content</div>

Is there a 'box-shadow-color' property?

I have the following CSS:
box-shadow: inset 0px 0px 2px #a00;
Now I am trying to extract that color to make the page colors 'skinnable'. Is there any way of doing this? Simply removing the color, and then using the same key again later overwrites the original rule.
There doesn't seem to be a box-shadow-color, at least Google turns nothing up.
Actually… there is! Sort of. box-shadow defaults to color, just like border does.
According to http://dev.w3.org/.../#the-box-shadow
The color is the color of the shadow. If the color is absent, the used
color is taken from the ‘color’ property.
In practice, you have to change the color property and leave box-shadow without a color:
box-shadow: 1px 2px 3px;
color: #a00;
Support
Safari 6+
Chrome 20+ (at least)
Firefox 13+ (at least)
IE9+ (IE8 doesn't support box-shadow at all)
Demo
div {
box-shadow: 0 0 50px;
transition: 0.3s color;
}
.green {
color: green;
}
.red {
color: red;
}
div:hover {
color: yellow;
}
/*demo style*/
body {
text-align: center;
}
div {
display: inline-block;
background: white;
height: 100px;
width: 100px;
margin: 30px;
border-radius: 50%;
}
<div class="green"></div>
<div class="red"></div>
The bug mentioned in the comment below has since been fixed :)
No:
http://www.w3.org/TR/css3-background/#the-box-shadow
You can verify this in Chrome and Firefox by checking the list of computed styles. Other properties that have shorthand methods (like border-radius) have their variations defined in the spec.
As with most missing "long-hand" CSS properties, CSS variables can solve this problem:
#el {
--box-shadow-color: palegoldenrod;
box-shadow: 1px 2px 3px var(--box-shadow-color);
}
#el:hover {
--box-shadow-color: goldenrod;
}
You can do this with CSS Variable
.box-shadow {
--box-shadow-color: #000; /* Declaring the variable */
width: 30px;
height: 30px;
box-shadow: 1px 1px 25px var(--box-shadow-color); /* Calling the variable */
}
.box-shadow:hover {
--box-shadow-color: #ff0000; /* Changing the value of the variable */
}
You could use a CSS pre-processor to do your skinning. With Sass you can do something similar to this:
_theme1.scss:
$theme-primary-color: #a00;
$theme-secondary-color: #d00;
// etc.
_theme2.scss:
$theme-primary-color: #666;
$theme-secondary-color: #ccc;
// etc.
styles.scss:
// import whichever theme you want to use
#import 'theme2';
-webkit-box-shadow: inset 0px 0px 2px $theme-primary-color;
-moz-box-shadow: inset 0px 0px 2px $theme-primary-color;
If it's not site wide theming but class based theming you need, then you can do this: http://codepen.io/jjenzz/pen/EaAzo
A quick and copy/paste you can use for Chrome and Firefox would be: (change the stuff after the # to change the color)
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
-khtml-border-radius: 10px;
-border-radius: 10px;
-moz-box-shadow: 0 0 15px 5px #666;
-webkit-box-shadow: 0 0 15px 05px #666;
Matt Roberts' answer is correct for webkit browsers (safari, chrome, etc), but I thought someone out there might want a quick answer rather than be told to learn to program to make some shadows.

Resources