Skip to content

[css-images-3] interpolating cross-fade(A, B) with cross-fade(B, A) #2852

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
fantasai opened this issue Jul 2, 2018 · 5 comments
Open

Comments

@fantasai
Copy link
Collaborator

fantasai commented Jul 2, 2018

Currently we spec that the arguments to cross-fade() are interpolated independently. However, this doesn't handle the case of cross-fade(A, B) to cross-fade(B, A) very nicely: it ends up creating a tree of cross-fades where one isn't necessary.

This is particularly a concern when the cross-fades are triggered by transitions which are reversed partway.

@fantasai
Copy link
Collaborator Author

fantasai commented Jul 2, 2018

Proposed edits:

+ The following table shows some examples of image interpolation. + + + + + + + + +
Start Image + End Image + 50% Interpolation +
''cross-fade(20% A, B)'' + ''cross-fade(40% A, B)'' + ''cross-fade(30% A, B)'' +
''cross-fade(20% A, B)'' + ''cross-fade(60% B, A)'' + ''cross-fade(30% A, B)'' +
''cross-fade(20% A, B)'' + ''cross-fade(20% A, C)'' + ''cross-fade(20% A, cross-fade(50% B, C)'' +
+
+">
diff --git a/css-images-3/Overview.bs b/css-images-3/Overview.bs
index 701eb90..aef55a8 100644
--- a/css-images-3/Overview.bs
+++ b/css-images-3/Overview.bs
@@ -1681,8 +1681,38 @@ Interpolating cross-fade() {#interpolating-image-combinations}
 --------------------------------------------------------------
 
        The three components of ''cross-fade()'' are interpolated independently.
+       However, if the two arguments match,
+       but are in opposite orders,
+       then first invert the percentage and
+       reverse the order of the images of the second ''cross-fade()''
+       before interpolating.
        Note this may result in nested ''cross-fade()'' notations.
 
+       
+ The following table shows some examples of image interpolation. + + + + + + + + +
Start Image + End Image + 50% Interpolation +
''cross-fade(20% A, B)'' + ''cross-fade(40% A, B)'' + ''cross-fade(30% A, B)'' +
''cross-fade(20% A, B)'' + ''cross-fade(60% B, A)'' + ''cross-fade(30% A, B)'' +
''cross-fade(20% A, B)'' + ''cross-fade(20% A, C)'' + ''cross-fade(20% A, cross-fade(50% B, C)'' +
+
+

@fantasai
Copy link
Collaborator Author

fantasai commented Jul 4, 2018

Should probably flip start argument rather than end argument, actually.

@css-meeting-bot
Copy link
Member

css-meeting-bot commented Jul 4, 2018

The Working Group just discussed Images Level 3, and agreed to the following:

  • RESOLVED: cross-fade() takes one or more args, each has an optional %
  • RESOLVED: At computed value time, simplify directly nested cross-fade()s into a single cross-fade()
  • RESOLVED: At computed value time we collapse same values in cross-fade()s and adding their percentages
The full IRC log of that discussion Topic: Images Level 3
ScribeNick: heycam
github: https://github.com//issues/2852
leaverou: we were trying to define interoplation between crossfades more reasonably with Elika yesterday
s/Elika/fantasai/
... when we're interpolating two cross fades with same images in a different order, A B , then B A
... it ends up creating a cross fade of the cross fade
... this comes up a lot, this interpolation happens when you're reversing a transition
... so fantasai suggested when adding a rule, when the images is the same and the order is different, we flip the order and change the percentages to account for it
... so 100% minus what it was
... is that OK? since it's CR we should check
fantasai: the use case for getting this to work simply is that when you're doing transitions between one image and another, when you interrupt that transition, you're half way between
... so you want to interpolate between a crossfade and a start point
... your computed value gets more and more complex
dbaron: is this the only interoplation type that has this problem?
emilio: I suspect it can happen with transform as well
dbaron: yes
birtles: with calc
ericwilligers: with transform didn't we define ...
TabAtkins: the interpolate() function
dbaron: so transform can do the same thing with interpolate() nesting in the same way
fantasai: we should probably do the same thing for transform then
ericwilligers: does interpolate() make cross-fade() redundant?
leaverou: it only helps you get the intermediate values
fantasai: there are use cases for cross fade where the author explicitly wants to fade between two things
... and there are differnet ways of interpolating images, cross fade is one of them
fantasai: the proposed resolution is that interpolating crossfade or the interpolate function, where the end point and start point have opposite order of arguments, you swap the order, so you don't nest the interpolating function
xidorn: shouldn't we just merge things when one side is crossfade A to B, and the other side is A or B?
fantasai: that's the next question
dbaron: what stage is this happening?
fantasai: computed value?
dbaron: so part of the process of computing the value of a nested cross fade is to un-nest
fantasai: no, when you're computing the mid point for
dbaron: so you're changing the interpolation rules
fantasai: yes
Rossen: does that sounds reasonable to people?
dbaron: yes, if you make it consistently apply to other places where this problem comes up
TabAtkins: yes
Rossen: any objections to this? do we need to add a note for the general interpolate function to be added as well?
birtles: I misunderstood
... I thought this was just about computed value simplification of nested cross-fade
ericwilligers: [writes examples on white board]
birtles: I'm just wondering why we're adding rules to interpolation. would the alternative be to say this is how nested crossfades are simplified at computed value time?
... then you don't need to do anything particular for interpolation
fantasai: we could do that
leaverou: I'd be fine with that
dino: cross-fade(A, B, 50%) is not the same as cross-fade(B, A, 50%)
... it's 50% of src-overing the second on top of the first
fantasai: and with transparency?
dino: you can tell the difference between B over A 50% and A over B 50%, yes
ericwilligers: would you advocate nested cross-fades()?
dino: I'd advocate not interpolating
fantasai: I don't think that's a good solution
dino: if we're going to do it, then nested cross-fade(), maybe
leaverou: nested cross-fades() should be supported anyway
dino: so, yes, nested cross-fades() would be my preferred solution
leaverou: I think it's Safari and Chrome at the moment
birtles: pre-fork, so one implementation
TabAtkins: dino your point before about A B 50% and B A 50% being different is wrong, since it's a dissolve
... dissolve op rather than src-over op
... since that's the correct way to fade between two images with potential transparencies
Rossen: do we need a whiteboarding breakout for this?
leaverou: if reversing the order does produce the same image, what's the argument against it
... if nobody has any then why do we need to break out
http://drafts.csswg.org/css-images-3/
https://drafts.csswg.org/css-images-3/#cross-fade-function
TabAtkins: only options are (a) do nothing, allowing nesting, (b) accept these rules for interpolation simplification, or (b) accept these rules for computed value simplification and allow interpolation to fall out
emilio: why (c)?
leaverou: then it also allows us to simplify computed values returned
emilio: I thought the point was nested cross fade is hard
TabAtkins: it's not that it's hard, but in common cases, like repeatedly interrupting a transition, it resutls in a stack of cross-fade()s
... when you could simplify it down
emilio: the difference between (b) and (c) is not observable
TabAtkins: yes it is
emilio: I think I prefer (b)
leaverou: [shows demo]
emilio: if you want to simplify what you interpolate, to avoid growing stacks of cross-fades(), you do it there
... but you also need to do it at computed values
... because the author might have specified a nested cross-fade()
fantasai: the interoplated intermediate value must be a computed value
Note that if we *do* finally do the "any number of images" extension, then we can simplify *all* nested cross-fades, in all situations.
leaverou: if I'm understanding emilio correctly, you don't want to create this thing if you're going to simplify it anyway
... if you're already going to simplify serialization of a specified (and computed) value
emilio: it complicates the code
birtles: I wonder if you're going to need to simplify it first anyway, in order to interpolate potentially nested inputs that you get
ericwilligers: yes
birtles: also will need to do it for addition, assuming that makes sense
leaverou: ideally it would be nice if cross-fade() accepted any number of arguments, and flatten them down to a single one
ericwilligers: then you've got more computations
s/computations/permutations/
leaverou: if you could collapse the tree down to a flat cross fade list of values, it's simpler to apply
TabAtkins: since dissolve commutes, you can collapse all cross fades
dino: plus commutes, dissolve doesn't
dino: what I got wrong is I'm src-overing not plusing
TabAtkins: plusing an appropriate dissolved image commutes, such that you can take nested cross fades and flatten it to a list of images that plus together
leaverou: should we just do that, allow cross-fade() to take a list of arguments
birtles: I think it's nicer from an authoring point of view too
that is, parsing the result of getComputedStyle is easier if you don't need to handle nested cross-fade functions
leaverou: another issue, if you're interpolating between A and cross-fade(A, ...), with the current rules you'll get a nested cross-fade()
... we could define that the A gets promoted to 100% cross-fade, and just interpolate percentage
https://github.com//issues/2853
fantasai: I think the proposal one this one is you get a single cross-fade() with A and B with arguments and the appropriate percentage
leaverou: we can, but if we're collapsing trees of cross-fade()s, it's less important
fantasai: collapsing trees is different from merging
TabAtkins: depends how we collapse
dino: [looking at the issue] wouldn't it be x is between 0 and p, not p and 100?
leaverou: you're interpolating between full A and the cross-fade
... you want it to start at 100
dbaron: I think we should try to resolve both at the same tim
s/tim/time/
... where the simplification happens, turning into multi arg cross-fade(), applies to both
myles: the proposal is change the behavior because it makes it easier to compute?
leaverou: this way you wouldn't need to interpolate to make a new cross-fade() at all
myles: there is a difference between having a tree of cross fades and not having a tree
TabAtkins: nobody has trees yet
... we're trying to avoid that now
TabAtkins: overall proposal is, avoid all trees of cross-fades, in all situations, by making it accept more than two arguments, just dissolve and plus throughout those
fantasai explains that interpolating cross-fade(x% A, B) and cross-fade(y% A, B) results in cross-fade(z% A, B), not a tree of cross-fades()s
... and make nested cross-fade() invalid, and make interpolations between them build the appropriate multi-arg value
this issue about treating interpolation of A & cross-fade(y% A, B) and cross-fade(100% A, B) & cross-fade(y% A, B) the same way
q+ to comment on (a) nesting through other functions and (b) validity of percentages that add to more than 100%
[whiteboard discussion of particular interpolations]
leaverou: I still think nested cross-fades() should be valid, since they could come from variables
myles: if the goal is to avoid avoiding trees, by making a list that has all the nodes of the tree, I don't see why that's better
TabAtkins: you don't need to generate all the intermediate images
myles: is there a behaviour change?
TabAtkins: no
myles: then we should just say "as if", a browser optimization
myles: so we're talking about computed values
florian: do we disallow in specified value?
TabAtkins: before we decide on that, let's look at the core thing
... multi-arg cross-fade(), does it sound reasonable
dino: and you must provide %s up to the last one?
... allowed to go over 100%?
TabAtkins: yes [for first], and no.
TabAtkins: if the percentages add up to over a 100%, you sum them and normalize to 100%
... then the last one gets zero
myles: every time gets a percentage
TabAtkins: except the last
... last one gets what's left over
dino: complete error if you did (A 10%, B, C)?
TabAtkins: syntax error
myles: is the purpose of this that humans will write this? or just to make the getCS output smaller?
TabAtkins: so clearly we want this for interpolation
heycam: Simplifying trees down to one level is same as flat list
heycam: Want to collapse list to minimum number of items
TabAtkins: If the goal is to avoid explosion...
myles: if this is for humans to use, it's useful
ericwilligers: negative %s allowed?
TabAtkins: no, individual %s above 100% should be disallowed
s/disallowed/invalid/
TabAtkins: But we can't syntacitcally restrict the sum
birtles: I'm not 100% sure about the normalization part
... the syntax I like
ericwilligers: not sure about normalization when you have interpolations between lists
birtles: I was thinking, once the bucket's full, the overflow could be dropped
myles: should make it possible for the last one to have a %
florian: to use them as 'fr's?
leaverou: right now, cross-fade() percentage is optional
... probably it should retain this
... right now (A, B), the 50% is implied
... (A 20%, B, C) should make sense
shans: distribute the rest
leaverou: yes
myles: allow the last percentage to be specified, then just weight them
q?
fantasai: if you have (A 20%, C 20%, C 20%)
... you could simply transparent black to take the slack
florian: rather than normalizing to 100%?
fantasai: if you're under
shans: one problem with diff behaviours on either side of 100% gets you non-linearities, bad for animation
ericwilligers: like opacity:1
ack dbaron
dbaron, you wanted to comment on (a) nesting through other functions and (b) validity of percentages that add to more than 100%
TabAtkins: the suggest grammar is, cross-fade() takes one or more args, each has an optional %
... we'll work out what missing %s mean
Rossen: any objections to that?
RESOLVED: cross-fade() takes one or more args, each has an optional %
leaverou: next, collapsing trees of cross-fade()s
... it's much easier to define interpolatino that way
... for authors reading it back
... don't know why we wouldn't collapse it down, esp given it's commutative
emilio: can we disallow nested cross-fade() in specified values?
TabAtkins: no for the same reason you allow nested calc()s
leaverou: with variables
dbaron: two other points
q?
... there are going to be other image-ish functions
... cross-fade() one of these other functions continaing a cross-fade() will be a reasonable thing
... I think the other piece is that I think one of the things that results from disallowing it, everyone has to go and implement that, then later we'll allow it, which is more work
... so we should just allow it now
TabAtkins: agreed
... specified values should allow it. interpolated values collapse to a single value
... interpolated values, don't care?
leaverou: I would collapse
birtles: collapse
fantasai: I thin kso
s/thin kso/think so/
florian: both kinds of smooshing down, flattening tree, and merging items in the list?
leaverou: they are separate issues but I support both
myles: so it's not just a simple substitution, there are formulas to calcalate the %s
TabAtkins: yes. it's just mulitplican tho
RESOLVED: At computed value time, simplify directly nested cross-fade()s into a single cross-fade()
xidorn: that means the flattened value is the canonical form of that
TabAtkins: yes
leaverou: now dropping duplicated images
TabAtkins: if you have multiple args which are the same image
... should the canonical form automatically collapse those together and add their percentage
leaverou: do we have an algorithm for same image?
fantasai: the compued value of the is the absolute URL
Rossen: the reason for simplifying is avoiding growth of the values
leaverou: we should not only combine the duplicates but also sort them
fantasai: I think we need to simplify this, to avoid growing lists
... we can do it very simply
emilio: how do you define sorting images?
myles: if you didn't want this, didn't want to collapse -- internally you want to
heycam: are the cases where we want avoid this?
fantasai: I don't think so
... it's going to be the same when you collapse it all down
fantasai: notion of equality we want is "computed values are the same"
frremy: with gradients, with px and %s ....
fantasai: that's not computed value
... that's used value
RESOLVED: At computed value time we collapse same values in cross-fade()s and adding their percentages
leaverou: sorting
fantasai: you don't want computed value of cross-fade() where you randomly swap the order
fantasai: re-sort into the target order and go from there?
... so don't sort the computed value
... but when interpolating, you re-sort the start point into the end point order
myles: that's cool then CSS doesn't have to define order
so no sorting occurs, for interpolation it falls out of the simplification process
When interpolating be3tween A and B, you just cross-fade(A,B) then collapse; whatever that results in is the answer.

See official minutes

@SelenIT
Copy link
Collaborator

SelenIT commented Aug 20, 2018

Could you please also clarify where is the cross-fade() function currently defined? I see a reference to it in css-image-3, but it seems to link to the definition in css-image-4. Is it intended or did I miss something?

@tabatkins
Copy link
Member

Yeah, it's defined in level 4.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants