currentBackgroundColor
(or currentBackground
) would be a variable similar to currentColor
, the difference being that currentBackground
is based on the background color rather than the (text) color of the element.
When used with CSS color functions, currentBackground
enables dynamic styling based on the block of color which is predominant in the element.
Currently, a popular pattern is to use the currentColor variable for an outline or border on a link or button. Sometimes, this is then swapped on hover. The effect is limited using currentColor
. Another note is that the color options for foregrounds are often more limited with accessibility being a primary concern. currentBackground enables more subtle dynamic borders without sacrificing accessibility.
https://codepen.io/una/pen/BajmGwZ
An example with filter cards:
currentBackground
also affords us more flexibility with hover/focus effects, and even allows us to set currentColor
in a dynamic way. This is also a continuation of the last example where we use currentColor for the borders in the example on the left, while the right example has two different values, despite setting color using currentBackground.
https://codepen.io/una/pen/xxZPQYv
With the neumorphism web trend, we’re seeing a lot more subtle shadows and “gummy” buttons. Using currentBackground
to set the shadow color can help create this effect dynamically:
https://codepen.io/una/pen/mdVqQGR
This would also help with neon effects, translucent effects, and more simply: more subtle shadows.
This was originally brought up in #364 a few years ago, but with CSS color functions there is so much more opportunity to have a background color variable!
Note that the currentBackgroundColor is usually transparent
. So would this really be as useful as you are expecting?
@fantasai I believe this would only really be used when a background color is specified either on the component itself or on a parent, and in that case, I'd find it really useful.
I see dynamic backgrounds frequently in components like cards that have some shared structure, but unique characteristics (i.e. on a media website with a carousel of different types of article preview cards, each with a slightly different background color and matching border to hint at this type).
A note RE: the parent value, since background-color is not inherited, if the card background is lightblue, and one wanted to use currentBackground
on a child element, they would have to set its background to inherit
. Not ideal but workable. It would be nice if there was a way to grab the first inherited background in this case. closestBackgroundColor
maybe?
Other than backgrounds being likely defined in an ancestor and possibly not being just a plain color, what about cycles?
color: currentBackgroundColor;
background-color: currentColor;
@Loirooriol Thought about this earlier this week; I would say that should translate to color: inherit
besides no-op; similarly background-color:
currentBackgroundColorshould be equivalent to
background-color: inheritsimilar to how
color: currentColor` behaves.
If we introduce a current-background-color
(let's not repeat the mistake of currentColor
), it needs to be decided whether this new keyword should be preserved in computed value like currentcolor
, or get replaced by a fixed value like other named colors.
If it's made a computed-value time keyword like currentcolor
, and it's used in color
, I suspect that it would very likely cause pretty confusing result to authors, as all the descendants of an element would likely have a text color derived from transparent
background, because they all read from background color of the current element if color
inherits the current-background-color
keyword rather than the color itself. Depending on how we define style of text, this could potentially be meaningless at all.
Additionally, we currently have currentcolor
be a computed-value time keyword, but when specified on color
property, it becomes a specified-value time keyword, i.e. it's replaced by the color
value of its parent. Adding current-background-color
makes it more complicated.
If we preserve current-background-color
as computed-value time keyword for color
, we inherently preserve currentcolor
as keyword on color
, and at the worst case we may need to climb the DOM tree all the way up to the root just for resolving a color for rendering. This, along with the issue above indicates that we may want current-background-color
to at least be a specified-value time keyword for color
property.
On the other hand, if it's made a specified-value time keyword like other named colors, and it gets replaced by the color specified by background-color
on the element when producing computed value, it might also cause confusion as it would behave differently from currentcolor
on transition, e.g. if you are transitioning border-color
from red
to currentcolor
, while also transitioning color
from green
to blue
, then the used value of border-color
would be a mixed of the three colors, which is only possible when it's a computed-value time keyword.
It feels like that having current-background-color
being a computed-value time keyword, but get resolved in color
and background-color
properties would likely be the most sensible approach forward. This would make background-color
a dependency for color
property in computation, but that's probably not the end of the world.
I have to admit that I started this comment with being strongly against this idea as I felt it would be adding unreasonable amount of complexity to implementations. But having all the above written, I now think it's probably manageable. I would still be against from implementer's point of view, as it still feels like some complexity more than its worth, but less strongly.
For the use cases themselves, though, I tend to think it's more reasonable to rely on CSS variables rather than introducing more builtin variables based on property values.
If the reason for its having to be a builtin variable is because CSS variables don't interpolate, I would bet more on CSS Properties and Values API than adding ad hoc builtin variables like this.
Referenced here: https://gist.github.com/jamiebuilds/b403c07806f20815cb5ac32a674bf1b3
@una do you find the suggestion from @upsuper to interpolate using Properties and Values API convincing, or not? If not (which I suspect) should we bring this to a CSSWG telcon for further discussion? If so, please tag Agenda+
I would like to discuss this with the group, as I do think there is a strong value add for this property, especially with color-5 functions.
Strong support for the feature itself, but not for the keyword syntax.
I would much prefer a functional notation e.g. current()
, with current(color)
aliased to currentColor
and current(background-color)
resolving to what is proposed here. This would allow us to gradually extend it into other properties for which this kind of thing can be safely implemented, without introducing new keywords and new syntax that people have to learn. As a bonus, it would also allow us to add other arguments in the future, if we so decide.
Other than backgrounds being likely defined in an ancestor and possibly not being just a plain color, what about cycles?
color: currentBackgroundColor; background-color: currentColor;
Same as color: currentColor
. I believe when the potential for cycles is as limited as this, they can be detected and resolved (see var()
cycles), but looking forward to an implementor response.
A note RE: the parent value, since background-color is not inherited, if the card background is lightblue, and one wanted to use
currentBackground
on a child element, they would have to set its background toinherit
. Not ideal but workable. It would be nice if there was a way to grab the first inherited background in this case.closestBackgroundColor
maybe?
Maybe time to revive https://github.com/w3c/csswg-drafts/issues/2864 ?
I really like this idea; I assumed it was blocked not happening before
On Wed, Nov 11, 2020 at 5:07 AM Lea Verou notifications@github.com wrote:
Other than backgrounds being likely defined in an ancestor and possibly
not being just a plain color, what about cycles?color: currentBackgroundColor;background-color: currentColor;
Same as color: currentColor.
A note RE: the parent value, since background-color is not inherited, if
the card background is lightblue, and one wanted to use currentBackground
on a child element, they would have to set its background to inherit. Not
ideal but workable. It would be nice if there was a way to grab the first
inherited background in this case. closestBackgroundColor maybe?Maybe time to revive #2864
https://github.com/w3c/csswg-drafts/issues/2864 ?—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/w3c/csswg-drafts/issues/5292#issuecomment-725413163,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AAJKUOEUIVNCMRNLNQV7DQDSPKEBZANCNFSM4OR6UZAA
.>
Kevin Lozandier
[email protected] lozandier@gmail.com
Same as
color: currentColor
. I believe when the potential for cycles is as limited as this, they can be detected and resolved (seevar()
cycles)
The first question would be how cycle should be handled. In var()
's case, all properties involved become invalid on computed-value-time. I think the thing is more complicated in color's case.
I'd like to remind that currentcolor
is a computed-value-time keyword, and only gets resolved at used time. If we have multiple colors (as @LeaVerou's proposed syntax indicates), we may want them to behave in the same way. Then we would have to resolve the cycle at used value time, and we create a new concept of invalid value at used value time, and compositor may need to resolve such cycle at 60fps.
The reason that it has to happen at used value time is because we want currentcolor
to be inherited as a keyword, and so probably others as well. Consider we have
color: current(caret-color);
caret-color: current(text-emphasis-color);
text-emphasis-color: current(color);
It may be invalid for the current element, but as soon as its descendant specifies one of them, the cycle should be broken, and they should all use that color. Since they have to be inherited as is, we can't resolve the cycle like var()
s.
At the end, I don't understand what value this proposal really adds on top of the ability to customize interpolation of variables especially given its additional complexity. Could anyone explain?
There are some other potential footguns, while possibly minor, should be taken into account as well for the new extended current()
proposal, such as
current(border-color)
?outline-color
a shorthand just like border?At the end, I don't understand what value this proposal really adds on top of the ability to customize interpolation of variables especially given its additional complexity. Could anyone explain?
The way I see it, decoupling. Variables are essentially a "contract" between two parts of CSS code. A library that uses variables needs the host CSS to know about it and its variable names to be useful. And if the library is swapped with another library, these properties would likely need to change as well. Whereas with something like this, one can write code that augments existing websites without their code needing any adjustment and without the indirection of reflecting real properties with custom properties.
There are some other potential footguns, while possibly minor, should be taken into account as well for the new extended
current()
proposal, such as
- would it over shorthand works, e.g.
current(border-color)
?- what happens if we convert a longhand color property to a shorthand, e.g. maybe making
outline-color
a shorthand just like border?
Please note that my proposal is entirely about syntax. It is not for a more powerful feature than what @una proposes, just for one that has the future potential to become more powerful. I wasn't suggesting we add all color properties to it, just to go with a syntax that allows us to do so at some point in the future, if we so decide and use cases come up. We don't need to resolve all issues that come with that now which would delay and potentially stall it, but only when and if we decide to extend the syntax.
But to answer your shorthand question (good point about future shorthands! Do note that color
and background-color
are theoretically not exempt from that either), if the serialized value makes the declaration invalid, then the declaration can be invalid at computed value time, just like var()
.
The point about cycles is the same regardless of whether we go with keywords or a functional notation.
I wasn't suggesting we add all color properties to it, just to go with a syntax that allows us to do so at some point in the future, if we so decide and use cases come up. We don't need to resolve all issues that come with that now which would delay and potentially stall it, but only when and if we decide to extend the syntax.
If there's no possibly viable path to resolve the issues, its potential could just be an illusion, and it's going to become a tech debt in the spec people may regularly question about.
the declaration can be invalid at computed value time, just like var().
One of the main point I argued above is that for currentcolor-like keywords you can't resolve them at computed value time because of inheritance and interpolation.
I would much prefer a functional notation e.g.
current()
, withcurrent(color)
aliased tocurrentColor
andcurrent(background-color)
resolving to what is proposed here. This would allow us to gradually extend it into other properties for which this kind of thing can be safely implemented, without introducing new keywords and new syntax that people have to learn. As a bonus, it would also allow us to add other arguments in the future, if we so decide.
I love the extensibility behind this functional syntax for current()
in @LeaVerou's proposal above. My only concern here would be that this might significantly increase overhead for implementors. For example, current(background)
could be valid in many cases instead of current(background-color)
, yet not always (i.e. if there are images and multiple backgrounds). That leaves it to the author to require more value management and overhead.
currentBackgroundColor
limits the value options and is explicit to what you're getting. Would the property list be limited to a specific set of options, such as those that only accept single-value properties like current(border-top-color)
?
This also reminds me of text-decoration-thickness: from-font;
, as it would be able to be written text-decoration-thickness: current(font-weight)
. There are likely many usecases for this beyond color, so I do like this exploration, I'm just worried about complexity and management cost vs. benefit.
I think lots of complexity comes from the fact that currentcolor is complicated to handle as it's a computed-value-time keyword for inheritance and interpolation. If we can avoid messing up with that, things may be a lot simpler.
I'm thinking about maybe we can just accept property name as variable in var()
function, and have it resolved in a similar way as variables, e.g. after resolving CSS-wide keywords in specified values but before computation. That should address the use cases and keep the decoupling characteristic, but more extendable and possibly less complicated as we would be able to actually resolve things during computation rather than having to handle them post that. There are some trickiness we may need to think about carefully, though, like how inherited values are handled, as well as shorthands.
With that, currentcolor
and var(color)
would differ in the following ways:
color: var(color)
would be invalid at computed-value-time because of cycle,var(color)
would not follow animation on color
property as it's resolved on computed time,var(color)
would use the actual color from its parent rather than the fact that it follows color
property of the current element.But I don't think they matter for your usecase. WDYT?
Basically, I think the decoupling thing indicates that we may want a well-known thing behaves like variables... and seemingly you don't need the full power of currentcolor.
@upsuper what I'm hoping to accomplish with currentBackgroundColor
is precisely that runtime parent-dependent variable that doesn't need to be separately set and updated, as one would need to do with custom properties. Therefore, I don't think var(color)
really covers it.
@una please elaborate, possibly with some "real" code assuming it exists. I don't think any of the examples you listed in the op needs that, nor does the outline focus ring thing in the gist.
var(color)
would not follow animation oncolor
property as it's resolved on computed time
@upsuper Not sure if I get it, you make it sound as if animations are done after finding the computed value, but actually animations are part of the cascade, and affect the computed value. I think var(color)
should basically work as var(--color)
with
@property --color {
syntax: "<color>";
inherits: true;
initial-value: CanvasText;
}
and in Chromium var(--color)
follows animation on --color
just fine: https://software.hixie.ch/utilities/js/live-dom-viewer/saved/8680
@Loirooriol Hmmm, okay I may be wrong about how animation works... In that case yeah it would work.
Maybe it would not work in the same way for transition I guess, as transition is interpolating between computed values.
Assuming it works the same as custom properties in transitions and animations, @upsuper's proposal does cover my use cases. Do note that a (registered) custom property propagates correctly for both transitions and animations. See demo: https://codepen.io/leaverou/pen/WNxYBLe
I love the extensibility behind this functional syntax for
current()
in @LeaVerou's proposal above. My only concern here would be that this might significantly increase overhead for implementors. For example,current(background)
could be valid in many cases instead ofcurrent(background-color)
, yet not always (i.e. if there are images and multiple backgrounds). That leaves it to the author to require more value management and overhead.
@una As I explained above, there is literally no additional implementation complexity with my syntax. The additional complexity that comes with adding more properties can be resolved when more properties are added, with the constraints of that time. Especially about shorthands, perhaps we should simply never add them (though as @upsuper pointed out, what happens with longhands that later become shorthands? In theory, even background-color
could become a shorthand at some point in the future).
If there's no possibly viable path to resolve the issues, its potential could just be an illusion, and it's going to become a tech debt in the spec people may regularly question about.
I'd be wary of making such statements about there being "no possibly viable path". Do you want me to list cases where we thought that certain features were impossible or difficult to implement, and then other changes made them feasible later?
@upsuper
Consider the following HTML on a media site, where each card highlights a specific type of news post:
<div class="card highlight">
<button>click me</button>
</div>
<div class="card politics">
<button>click me</button>
</div>
<div class="card fashion">
<button>click me</button>
</div>
.card,
.button {
border: color-mix(currentBackgroundColor, #ccc, 50%)
}
.highlight {
background-color: yellow;
}
.fashion {
background-color: blue;
}
.politics {
background-color: green;
}
All cards should read from their background colors, but all background colors are unique. This is not an uncommon pattern in components. Additionally, if there was any transition state on hover/focus color change, the currentBackgroundColor
would automatically compute instead of writing out a new custom property value.
RE: button
, it would pull from the closest parent with a background color unless a new background color is set on it.
The CSS Working Group just discussed [css-color-5] Add `currentBackgroundColor` Variable
.
The full IRC log of that discussion
<dael> Topic: [css-color-5] Add currentBackgroundColor
Variable
<dael> github: https://github.com/w3c/csswg-drafts/issues/5292
<dael> una: The idea behind currentBG came from work in color 5 with color mix. Use case I see commonly is unity within and element where you want a border or a shadow to be related to the primary color of an element which is usually the bg
<dael> una: Right now need a separate variable. currentBG would be useful here to use the BG color.
<dael> una: A bit of discussion on issue. Way I see it is b/c transparent is default value you look for closest parent with a color and use that
<Rossen_> q?
<leaverou> q+
<dael> una: leaverou had a great comment about a current function to take any inherited keyword. That would work for things like font weight for text decor.
<dael> una: Would love questions, comments, thoughts
<Rossen_> ack leaverou
<dael> leaverou: The clarify my prop is not for current function to take any property as an arg. I said this is useful but since in future we want similar perhaps syntax should allow for us to add more keywords in future
<dael> leaverou: I suggested starting with color and bg color. It's no more complext hen keywords but it's more extensible for the future. If it's a funtion that's like any property or longhand that's harder to impl. I wouldn't want to stall this very useful feature by making it complex
<Rossen_> q?
<TabAtkins> q+
<dael> una: Agree. Starting with subset of arg for current is a great route
<emilio> q+
<Rossen_> ack TabAtkins
<dael> TabAtkins: I have a slight objection to trying to generalize to a current function b/c behaviors won't be same. Discussion in thread about if currentBGColor would comput to self or would compute at computed value time and inherit as that color.
<dael> TabAtkins: Suspect for BG color b/c transparent we wouldn't want hte behavior of currentColor. Tying together in one syntax implies similar behavior. Since our two examples are divergent I'm not convinced we'd have coherence in our 3rd or 4th
<dael> leaverou: Keyword that looks like currentColor also suggests might be same?
<dael> TabAtkins: Yes, but we can't avoid that much similarity. A brand new current has a more implicit guar of similar I think
<Rossen_> q?
<dael> emilio: I want to say xidorn concerns about impl complexity vs benefit. hesitant about mode dependencies b/c get complex. Not sure the use case warrants another one
<Rossen_> ack emilio
<Rossen_> q?
<dael> una: I think it's a common pattern to have a base color for a component, cards, sidebar, whatever where you have a color theme and additional color values for items in that component based on the theme. I've mostly seen that primry color be the background. That's the inspiration on existing common UI patterns
<dael> Rossen_: Going back to meta point of do we want to pursue...handling semantics later...is this something we want to pursue as part of color 5?
<dael> Rossen_: Use cases and usefulness. Do we have enough merit we can say it sounds like good to put in?
<emilio> q+
<emilio> dbaron: huh, wfm on nightly
<chris> q+
<leaverou> +1 would want to pursue
<brandon> +1 this would be very useful
<dael> fantasai: Question is if the use case is strong enough it outweighs dealing with impl complexity. You have to look through transparent things. If you have image BG the base color is not nec the color b/c might have semi-transparent on top so it might not rep the color you want. Also issues with how and when this computes
<emilio> q- was going to mention mostly what fantasai is saying
<emilio> q-
<leaverou> q+
<dael> fantasai: otoh we have the use case. I believe una it exists. You can work around with a variable but it's more work for author to establish a convention and stick to it. I haven't read deeply into impl complexity. I think that's what it boils down to. Does it balance out.
<dael> chris: My point was about you can...first if you look at examples in color 5 for contrast they implicitly use bg as the first color for contrast. Simplifies things. otoh you've got partial transparency and you could have an image color bg color isn't used.
<Rossen_> ack chris
<dael> chris: At the moment we're sticking a color in there and it's author convention that it's the bg. An improvement is good even if not bullet proof
<Rossen_> ack leaverou
<dael> leaverou: I wanted to say fantasai raises valid concerns. Would it be possible to have a syntax for compositied bg color. Start from current and go up until you meet opaque and composit. Use cases from una in need of that, as is the contrast case
<dael> fantasai: What about an image? Have to narrow to a point
<smfr> q+
<gregwhitworth> do we mean true composition because that comes far after style
<gregwhitworth> so that would need a round trip to compute
<dael> leaverou: Images makes it more complex and we don't want to deal. But there's an algo for a single color which you can plug into color functions.
<una> q+
<chris> maybe we need a NaC (Not a Color) value
<gregwhitworth> +1 to smfr
<dael> smfr: Running algo leaverou desc is expensive. You'd have to re-eval every frame with animations. I don't think practical.
<dael> Rossen_: Given convo this generated and the thread on GH we can go back to GH and continue there and don't resolve pursue or not now. I see decent support in IRC and decent amount of concern.
<gregwhitworth> we investigated this for a dynamic accessible focus rect and decided to not pursue it although I think that still has a higher likely hood of implementation given it only applies to focusable elements
<Rossen_> ack smfr
<dael> Rossen_: I rec we continue on GH and bring back in a week or two
<Rossen_> ack una
<dael> una: sgtm. Answering about compositing I do think it'll be heavy to calc that b/c happens after paint. We could still do it with alpha included and we don't use that value and apply style declarations using that. Lots of places where want alpha and it multiplies on bg color alpha. I don't htink it's as complex as figuring out composited color. That would be great, but I understand complexity
<dael> Rossen_: Thanks
<dael> Rossen_: Sounds like we should go back to GH. Okay?
<dael> una: Yep
I'm seeing the core use-case here being "I want a well-established 'main color' for an element", and it happens that the nearest "significant" background-color usually carries that information.
The use-case is very valuable! In SVG, the 'color' property ends up carrying that information, via the currentcolor
keyword, because 'color' doesn't do anything in SVG except set that variable. But CSS uses 'color' and uses currentcolor
, and you're looking for a different value.
There have been a lot of objections to actually using 'background-color', for a combination of implementation and specification reasons; mainly, the "nearest significant background-color" seems difficult to specify and difficult to implement performantly. There's also a reasonable objection against the "just use a variable" suggestion; it solves all the specification/implementation issues, but loses the authoring convenience of hooking into already-used stuff.
I don't think this is a knot we can untie, honestly; the use-cases are valuable, but I don't think they outweigh the downsides. But perhaps we could address the core problem more directly, and define an official "main-color" property that is solely used to define a new color keyword (with the same behavior as 'color'+currentcolor
; the property inherits, the keyword computes to itself), effectively being a custom property+var() pair.
This might solve the issue of "nobody can agree on the variable name to use", while still letting us avoid all the issues with trying to infer the color from bg-color?
I have an example. Suppose I wanted to create the following as a Web component:
It'd be great to set the background as a gradient using currentBackgroundColor
& --some-variable
with something like
:host {
contain: content;
box-sizing: border-box;
border: 1px solid black;
background: linear-gradient(to bottom currentBackgroundColor, --some-variable);
}
currentBackgroundColor
would be useful to make sure the absolutely positioned image at the top of the component elegantly visually "breaks" the border.
I think for that reason it should exist in some form. I really like @LeaVerou's idea of a current()
though when I think about it, it seems intuitive currentBackgroundColor
exists as an out-of-the-box variable alongside currentColor
.
Thoughts?
@una Ah so you want it to be inherited somehow? That's not what I would expect for the name of currentBackgroundColor
, and there comes more complexity...
Firstly, all elements have background color even if you do not specify. It's transparent
. Are you proposing that we simply ignore that specific value? Or are you proposing we only use the background color if there is a cascaded value? Either way that would work differently from what currentcolor
does... likely in a worse way.
For your specific example, actually, button
usually comes with a default background, are you proposing some mechanism to ignore non-author rules maybe?
@tabatkins I think color
and currentcolor
can serve the same thing in CSS as SVG. For all browsers, color of text comes from -webkit-text-fill-color
not color
directly. color
is already serving as a built-in variable now. But all text-related properties use that as default value so it might not be ideal to be used as the "main color" still...
But... yeah I think introducing a new inherited property like main-color
would be least complicated for implementation among all solutions proposed here (other than just use variables and not do it at all). Mixing the two keywords would still add impl complexity, but should be more manageable than others.
Most helpful comment
@fantasai I believe this would only really be used when a background color is specified either on the component itself or on a parent, and in that case, I'd find it really useful.
I see dynamic backgrounds frequently in components like cards that have some shared structure, but unique characteristics (i.e. on a media website with a carousel of different types of article preview cards, each with a slightly different background color and matching border to hint at this type).
A note RE: the parent value, since background-color is not inherited, if the card background is lightblue, and one wanted to use
currentBackground
on a child element, they would have to set its background toinherit
. Not ideal but workable. It would be nice if there was a way to grab the first inherited background in this case.closestBackgroundColor
maybe?