Repository navigation
[css-values-5] inherit() function: like var() for parent value, for any property #2864
Description
[Edit: We've now defined 'inherit()', but only for custom properties. The issue is left open to track the fuller feature.]
We've declined numerous author requests to extend var() to arbitrary properties, due to the potential for cycles and how expensive cycle detection would be in the general case. However, providing a way to get the parent or inherited value of any property does not cause cycles and still helps with a ton of use cases.
Use cases
Custom property value that depends on parent value
* {
--depth: calc(inherit(--depth, 0) + 1);
}See also: #1962
Font metrics relative to parent
- [css-fonts-4] Percentages in font-weight for relative weights #2690
- [css-fonts] font-weight: bolder and lighter are counter-intuitive #2764
strong {
font-weight: clamp(600, 1.2 * inherit(font-weight), 999);
}And any other numerical typographic metric that can be specified in CSS, e.g. font-stretch, font-style (for variable fonts) etc
Many of the currentBackgroundColor use cases
While this does not address all use cases (since it would only provide an ancestor background color), it does address quite a few, and offers a workaround for others.
Matching nested radii
inherit |
inherit() + calc |
|---|---|
.child {
padding: 1em;
border-radius: calc(inherit(border-radius) - 1em);
}Swapping foreground and background colors
- https://twitter.com/Paceaux/status/1350518907539513346
- https://twitter.com/FremyCompany/status/1350499409168117761
- https://twitter.com/snapeuh/status/1350492392550526979
- https://twitter.com/teacherbuknoy/status/1377094545498775555
.button {
color: inherit(background-color);
background: inherit(color);
}Decorations visually extending the background
https://twitter.com/HugoGiraudel/status/1350496044681990147
blockquote::before {
content: "❝";
color: inherit(background-color);
font-size: 300%;
}Override parent margins (bleed)
- https://twitter.com/stephband/status/135054701479108198
- https://twitter.com/MartijnSaly/status/1350496008594202625
- https://twitter.com/stephband/status/1377068306553782274
.card > header {
margin-top: calc(-1 * inherit(padding-top));
margin-left: calc(-1 * inherit(padding-left));
margin-right: calc(-1 * inherit(padding-right));
}Inherit grandparent value
https://twitter.com/cjw0/status/1350499207648583683
.foo {
--font-size: inherit(font-size);
font-size: 0; /* for animation */
}
.foo > * {
font-size: var(--font-size);
}@property does provide a workaround for this particular case (just register a <length> custom property and set it on .foo’s parent), but not in the general case where no suitable registration synstax exists.
More use cases
- A few more as answers to my tweet (I've come across many, many use cases over the years, but my memory deals poorly with random access, so I shamelessly resorted to lazyweb 😁 )
- [css-values-5] inherit() function: like var() for parent value, for any property #2864 (comment)
- [css-values-5] inherit() function: like var() for parent value, for any property #2864 (comment)
- [css-values-5] inherit() function: like var() for parent value, for any property #2864 (comment)
- [css-values-5] inherit() function: like var() for parent value, for any property #2864 (comment)
Activity
upsuper commentedon Jul 3, 2018
We probably don't want it to be a function, or at least not a function accepting arbitrary property. Different properties may have different underlying storage / handling, so it could be hard if it uses arbitrary property in arbitrary property.
It might be fine to restrict it to properties with only a single numeric value, but I believe in the past we occasionally extend single-value properties into multi-values, so a general mechanism like this may not be future-proofing.
upsuper commentedon Jul 3, 2018
Also it sounds like a dupe of #2764.
jonjohnjohnson commentedon Jul 3, 2018
@FremyCompany mentioned the
cascadeproposal and I imagine this playing into that? #1594 (comment)LeaVerou commentedon Jul 3, 2018
@upsuper Not a dupe of #2764, which is about a special case of this.
Could you elaborate a bit on the underlying storage/handling issue? How could it get in the way? Is it theoretical or are there existing examples of properties that would have issues?
Also, by future-proofing, are you referring to implementation issues or author code?
upsuper commentedon Jul 3, 2018
I wrote that mostly concerning the implementation difficulties in mind, since we (in Stylo) use lots of different types to handle subtle differences between properties. But I realized that it is actually not a problem of types, but the differences themselves. For example,
word-spacingandletter-spacingis almost the same except that the former accepts<percentage>in addition tonormal | <length>. If any property can be referenced to any property, we would need a mechanism to extract only certain type of value, with either a fallback or just treating as invalid at computed-value time.Such mechanism has its own issue, that supported type at a value position may depend on the context, and can change as CSS evolves. For example, there is plan to allow division between two dimensions, which may enable
<percentage>being used in a property accepting only<dimension>as far as you divide it with another percentage. Also there is some idea about allowingautoincalcfor some properties. Those kind of changes may affect above-mentioned mechanism.For spec about how to handle it. Actually the above has something related to future-proofing already.
LeaVerou commentedon Jul 3, 2018
It doesn't need to retain anything about the type, just serialize the value and use it the same as when
var()is used.upsuper commentedon Jul 3, 2018
OK, so I misunderstood the approach you are proposing. This approach is probably better to some extent, although I'm a bit concerned that serialization of computed value of properties may not be as well-defined and interoperable as token stream used by custom properties.
tabatkins commentedon Jul 3, 2018
Discussion with dbaron suggested that the effect would be that you basically just sub in the serialization of the computed value (probably per the well-specified serialization in Typed OM).
If the property you're subbing in doesn't work for the property you're subbing into, it would follow the same rules as var(), and make it invalid at computed-value time.
CyberAP commentedon Oct 29, 2018
Shouldn't it be called
computed()then, instead ofinherit()? Makes more sense to me and it is more declarative, than an imperativeinherit.Or just simply
prop()as it's a direct CSS property reference here.LeaVerou commentedon Jan 17, 2021
I just came across this issue again looking for something else and was reminded of how useful this would be.
@tabatkins wrote
It sounds like there is a clear implementation path, but the discussion just stalled 2 years ago.
Can we move it forwards?
I promised in the first post that if this is feasible, I could try and collect a list of use cases. Here are a few:
font-stretch,font-style(for variable fonts) etccurrentBackgroundColor([css-color-5] AddcurrentBackgroundColorVariable #5292) can be resolved with thisborder-radiusset to parentborder-radiusminus padding + border [source]margin-leftset tocalc(-1 * inherit(padding-left))1 2 3Edit: Added these to OP, for convenience.
In terms of how it should behave, a few more thoughts:
inherit(background-color)ends up walking up the ancestors and returning e.g. the page's background? OTOH, that might actually be the background you're seeing...var(). The fallback would apply when the returned value isinitial.inherit(border-color)cannot be used).inherit(),inherited(),parent(),ancestor(),closest()Loirooriol commentedon Jan 18, 2021
In general I don't think walking ancestors makes much sense for non-inherited properties. Even for inherited ones it may be undesirable. So I would just return the parent value.
But using the fallback for initial values would be inconsistent with
var()andenv(). I think the fallback should be used when the serialization of the computed value is the empty string (like a guaranteed-invalid value, or a shorthand that can't represent the values of its longhands). IMO custom behaviors for specific values should be achieved with conditionals (#5624).If this feature is based on serializations, then it doesn't seem problematic to me. Just try to serialize the shorthand, and return that in case of success, or empty string otherwise. When reparsed, empty string can be treated as a guaranteed-invalid value, and use the fallback value if provided, or become IACVT otherwise.
LeaVerou commentedon Jan 18, 2021
@Loirooriol
I suppose that's more predictable (and probably more performant and easier to implement). After all, if one wants the value from a specific ancestor, there's an easy workaround:
The fallback for
var(--foo)is applied when--fooisinitial([demo],(https://dabblet.com/gist/b49604259b2765fec0966ba649dad8c8) spec). I agree with your reasoning however, especially since this allows shorthands to be used, which is really important.env()has an entirely different fallback mechanism (falls back when the name is not recognized, not depending on the value).I really like this. 💯
Loirooriol commentedon Jan 18, 2021
Ah, yes, that's because the initial value for unregistered custom properties is the guaranteed-invalid value, which is what triggers the fallback. But if you register the property with some other initial value, then
initialdoesn't trigger the fallback invar(), so I guess it shouldn't ininherit()either.andruud commentedon Mar 25, 2021
Sounds like it's already settled, but I'll emphasize anyway that this is something we should definitely not do.
We recently (-ish) invented the equivalent token sequence, so we can just re-use that for this.
I've been trying to think about whether or not the new "cross property inheritance" proposed here creates any significant new problems (performance, complexity, etc) for style recalcs. I think it should be fine. It's similar to situations that must anyway be dealt with via
var()and explicit inheritance of non-inherited properties.This looks like a relatively "easy win", so I'm supportive, FWIW. 👍
95 remaining items
EisenbergEffect commentedon May 7, 2024
I've been using the same technique that @kizu describes to work around the lack of
inherit(), particularly in design system scenarios where color layer adaptations are needed for accessibility. I'd love to seeinherit()make it into the spec as it's a much cleaner solution than the container query hacks for this type of thing.una commentedon Jun 12, 2024
Another usecase would be essentially enabling #5292 (
currentBackgroundColor) and other similar values. Would be highly useful!i.e. Leveraging
background-colorto apply border styles:[css-values-5] Define inherit() for custom properties #2864
fantasai commentedon Oct 28, 2024
This is now edited in for custom properties as resolved. Leaving the issue open for the more general discussion.
beratbayram commentedon Jan 9, 2025
Maybe we could re-use var() ? Since custom properties have to start with two dashes, it will be easy to distinguish them.
Loirooriol commentedon Jan 9, 2025
@beratbayram No,
var()gets the value from the current element, not from the parent, so it would be extremely confusing and inconsistent.LeaVerou commentedon Jan 11, 2025
Also,
inherit()works for custom properties too (and will be implement ONLY for custom properties first!) and has a different meaning thanvar().brandonmcconnell commentedon Apr 22, 2025
@LeaVerou You may want to update the title to use
css-values-5instead ofcss-values-4, as this feature to be included in thevalues-5spec, notvalues-4.[-][css-values-4] inherit() function: like var() for parent value, for any property[/-][+][css-values-5] inherit() function: like var() for parent value, for any property[/+]Crissov commentedon Oct 15, 2025
Since this is still open and Blink intents to prototype, I’m not opening a new issue: Is there any chance the
inherit()function could behave more likeinheritglobal keywords in that it always refers to the (custom) property it is used within? That means, drop the first parameter, thus only expect an optional fallback value.For accessing ancestral values from arbitrary properties, there could either be a separate function like
parent()/parental()or the first parameter could just be made optional although I don’t see how that would work reliably.Crissov commentedon Jan 9, 2026
Just for the record, MathML introduces an
add()function to CSS which takes the parent (numeric) value and adds the parameter to it, but it is only specified for itsmath-depthproperty.