[CSSWG] Minutes New York F2F 2022-08-03 Part III: CSS Backgrounds; CSS Values [css-backgrounds] [css-values]

  These are the official CSSWG minutes.
  Unless you're correcting the minutes,
 Please respond by starting a new thread
   with an appropriate subject line.

CSS Backgrounds

  - oriol created a demo (
https://people.igalia.com/obrufau/testcases/shadow-radius/ )
      of some possible solutions for issue #7103 (The shape of
      box-shadow should be a circle for a box with border-radius:50%
      and big spread).
      - There was some preference to combining a few examples to get
          the best behavior such as combining 2 & 3.
      - Whatever is decided here should also be applied toward outlines
          for consistency.
      - This sparked some new ideas that also need to be coded for a
          visual demo. Once those are complete, the group will revisit
          this issue.

CSS Values

  - RESOLVED: Add random() and random-item(), mark open issues; goes
              into values-5 (Issue #2826: random() function)


Agenda: https://github.com/w3c/csswg-drafts/projects/30

Scribe: TabAtkins

CSS Backgrounds

Shape of box-shadow spread
  github: https://github.com/w3c/csswg-drafts/issues/7103

  fantasai: I think we should have demos before we discuss this
  Rossen: oriol made those an hour ago
  oriol: You can see a comparison of the different algorithms
  oriol: I didn't find an algorithm that works perfectly for all
  oriol: but maybe I'm leaning towards the last one in the demo
  oriol: [demos]
  <bramus> https://people.igalia.com/obrufau/testcases/shadow-radius/

  oriol: First is no polyfill at all, browser does different things
  oriol: This is chromium
  oriol: Here's current spec, where a circular element is a
         non-circular shadow
  oriol: Here's another showing that same, with an ellipse
  oriol: Another algorithm is to increase radius by spread
  oriol: Similar to firefox, but firefox has a special case for 0
         radius that isn't continuous
  oriol: otherwise I'd say it's not a bad algorithm
  oriol: There are some variant algorithms that take the border radius,
         express it as a percentage, then apply the same % to the shadow
  oriol: good in some cases, but in this ellipse case it gets flat edges
  oriol: Using the maximum axis improves some cases but not all
  oriol: ellipse is still flat
  oriol: Then my original proposal is each percentage is taken
         independently per axis
  oriol: This works good I'd say, but has problem shown in this long
         round rect,
  oriol: where the shadow gets an elliptical corner when the original
         element was circular corner
  oriol: So final variant, finds percentages in each axis, then tries
         to, for each corner, if the radius has changed its aspect
         ratio relative to the element, it tries to increase one
         component to hit the same aspect-ratio
  oriol: with the limitation that it prevents the radius from going to
  oriol: We have a restriction that the x component of top-left and
         top-right radius shouldn't exceed the width; the spec has an
         adjustment for that
  oriol: so the constraint we apply here is we increase one component
         to restore the aspect ratio, without breaking this constraint
  oriol: I think this is the best I could find
  oriol: 0 radius gives square shadow, 1px gives mostly-square shadow
  oriol: circle and ellipse are still pretty round
  oriol: circular corners stay circular on the shadow even with long
  oriol: In this example (a "cup" shape) the shadow looks like it
         becomes thinner, but it is the same arc in both the shape and
         the shadow
  oriol: So this is the best idea I could find
  oriol: if people want to play with this they can look at the source,
         it's a standalone page
  <lea> would be nice if one could input their own dimension/spread/
        radius values to see the result with the different algorithms
  oriol: [explains how to modify the demo]
  Rossen: fantastic, thanks for putting in the time for this
  <lea> Yes, so great to have a demo! thanks oriol!

  dbaron: I was looking at the cases where you said your preferred
          algorithm wasn't great
  dbaron: I agree it's not that great, like the 3rd from the end case
  dbaron: It seems what the algorithm is doing wrong is producing too
          large a radius
  dbaron: don't know why
  dbaron: The problem there is the radius we're ending up with seems
          larger than it should be
  oriol: Both arcs are circular
  oriol: inner element has border-radius of 39/39
  oriol: shadow has border radius of 107/107
  oriol: so x and y components are equal
  oriol: almost no radius in the top left, and the shadow similarly has
         almost no radius there

  fantasai: Last time we discussed this I wanted to ask...
  fantasai: We have a formula in the spec, and the original proposal
            that's to use the same percentages
  fantasai: so, could we decide which formula to use based on whether
            the original radius was expressed in lengths or percentages?
  fantasai: so if you have oval that's 50%, the spread would also be 50%
  fantasai: whereas if it was 200px/100px, we'd use the old formula
  fantasai: So rather than just doing math on the absolute value, carry
            over the initial intent

  fantasai: A different alternative would be
  fantasai: Looking at these tests, the ones that look bad in the old
            formula are the ones where the length of the straight part
            of the border are 0 or close
  fantasai: whereas the bad ones for %s are where the straight side is
            pretty long
  fantasai: so we could have two different formulas, using one when the
            straight side is 0 or the other when large
  fantasai: and between the two for some distance, such as radius =
            straight side to 0, we interpolate the formulas

  oriol: re: the first thing, choosing the algorithm depending on
         whether the author specified length or %
  oriol: I didn't consider that
  oriol: Issue is you can get the same shape in either way
  oriol: Seems strange to have two equivalent shapes for the element
         can produce different shadows
  fantasai: yeah but consider I have an element that's short, and the
            border-radius makes a semicircle, I might want that because
            I want a pillshaped box
  fantasai: *or* it might be a consequence of this box being short, and
            I have a set of boxes with rounded corners and straight
            sides, so I'd prefer the shadow generally to have straight
  fantasai: Dunno if it's a great idea. Authors might not think about
            their intent, and instead just shove in numbers that get a
  oriol: Could be a possibility
  oriol: Didn't consider it, to have it differentiate would have to

  oriol: re: the other thing about combining algorithms
  oriol: You were mentioning the old algorithm, what browsers used to
         do and firefox still does
  fantasai: My understanding is chrome updated to current spec and
            realized there were problems
  fantasai: The cases that work poorly are those where you want to get
            a round shape
  fantasai: in those %s work great
  fantasai: but they work bad for rounded corners on a rectangular
            shape, that's where current spec works well
  fantasai: so using both formulas and interpolating might be a way to
            get good results in more cases
  oriol: But then how do you do this interpolation?
  fantasai: You look at the straight side, if it's 0 you use percent
            formula. If it's longer than the radius, use the old
            formula. Between those two, you do linear interp

  lea: Not super confident since this is the first time I've seen this
  lea: but looking through these algorithms
  lea: as an author, anything with a percent produces surprising
       results in some cases
  lea: The one that produces the least surprise, to me at least, is to
       increase radius by spread
  lea: except that it produces round from 0 radius
  lea: This was chrome's behavior before they changed?
  oriol: Yes, firefox has a discontinuity at 0
  lea: So maybe because I was used to previous behavior, this makes
       sense to me
  lea: Is discontinuity acceptable?
  oriol: Another possibility is adding another initial value like
         "none" which keeps the shadow straight
  fantasai: If you think about this in terms of being a drop shadow,
            instead of a way to get a rounded corner outline, the
            results of "increase radius by spread" the results are
            clearly pretty unreasonable
  fantasai: If you switch to current spec it looks a little more like
            an actual shadow
  fantasai: the problem with current spec is the case with circles and
  lea: So you're proposing neither of these
  fantasai: I'm proposing using current spec for first three examples,
            percent of side in the next two, and some interpolate in
            the rest
  fantasai: so formula I'm suggesting would be... 5th and 6th case
            would be current spec
  fantasai: 7th case would get you a combo, one axis would use each
  fantasai: Second to last would be percent
  lea: I think it's hard to picture how it looks
  fantasai: yeah I can code it up
  lea: I think we should definitely avoid that if you have a fully
       curved shape, the shadow should have any straight edges
  fantasai: Right, that's the issue we're trying to solve

  emilio: The other place where this pops up is outlines
  emilio: Do you propose to change both?
  fantasai: Both seems reasonable
  emilio: You're right that firefox's behavior for second case doesn't
          make sense for shadows, but I think it makes sense for an
  TabAtkins: Right I think outline is like a border
  emilio: So right now outline works like a border
  fantasai: So there's a discontinuity at zero
  Rossen: Spec has a cubic interpolation
  fantasai: Been in spec for a long time, chrome just implemented it
            and discovered problems
  fantasai: so I think using whatever we end up for spread radius would
            probably look good, but I think having continuous behavior
            generally is also pretty good
  fantasai: so might want to use same for both

  dbaron: First to emilio, I'm in favor of having a single algorithm in
          CSS for expanding a rounded rect
  dbaron: That is the direction I was pushing when I code-reviewed the
          patch that led to this in the first place
  <emilio> +1 to have a single algorithm
  dbaron: I'd like us to be consistent in inflation

  dbaron: The other point about inflating rounded rects, is you always
          start from the border edge and do a single inflation
  dbaron: you never do it from another algorithm
  dbaron: because inflate(10)+inflate(10) might be different than
          inflate(20), and certainly inflate(10)+inflate(-10) is
          definitely not the identity
  dbaron: can avoid problems by starting from the border edge always
  dbaron: One reason to keep these consistent is people might have both
          at the same time
  dbaron: if outline and shadow use different algorithms, that'll look
  dbaron: I think we'll be okay with a single algorithm

  dbaron: Looking through oriol's demos, I think the best results
          generally come from option 2 or 3
  dbaron: While I understand the goal was to find the right compromise
          between 2 and 3, I think the percent options didn't really
          work out
  dbaron: I think the goal should be to find the right way to
          compromise between those two
  dbaron: There's also the 2-variant that is what browsers did before,
          which has the 0 discontinuity
  dbaron: so maybe a comp between 2 and 3

  TabAtkins: Next steps, code up fantasai's idea
  TabAtkins: Anyone with other ideas, put them in the demo as well
  TabAtkins: Revisit in 2 weeks to decide?
  Rossen: Again, thanks to oriol for the demo
  <emilio> oriol++

CSS Values
  scribe: fantasai

random() function
  github: https://github.com/w3c/csswg-drafts/issues/2826

  <TabAtkins> https://github.com/w3c/csswg-drafts/issues/2826#issuecomment-1204305712
  TabAtkins: This final comment is the current proposal
  TabAtkins: Idea we've thrown around for awhile
  TabAtkins: no urgency, but if people like it we can do it
  TabAtkins: People have asked for random() function in CSS for a long
  TabAtkins: to use random colors, random positions, etc.
  TabAtkins: We've always rejected for good reasons, which is that
             randomness is stateful
  TabAtkins: I believe I have a solution
  TabAtkins: and would allow for JS to fill in the remaining use cases
             not covered

  TabAtkins: Proposal as shown in linked comment is 2 functions
  TabAtkins: 1) random() which takes some optional seed parameters
  TabAtkins: low, high, and optionally a resolution
  TabAtkins: same output type as math functions
  TabAtkins: Resolves to <number> between low and high, stepped by
  TabAtkins: Important bit is the seed param, you can provide a custom
  TabAtkins: function with same seed and same low/high will always give
             same value throughout the document
  TabAtkins: so you can relayout and get the same result
  TabAtkins: and you can have the same result in multiple places in the
  TabAtkins: In addition to custom-ident, could give per-element keyword
  TabAtkins: which gives a different result per element, but same
             result on the same element (?)
  TabAtkins: Second function is similar, but it uses the output as an
             index into a list of values
  TabAtkins: and selects a random one for you
  TabAtkins: that's it!

  lea: If you have custom property from 0 to 1 you can select any value
       based on custom property
  TabAtkins: If you need randomness that resolves at different times,
             you can use JS to poke it
  TabAtkins: or adjust seed value

  flackr: This reminds me an issue with paint API where you want
          predictable random numbers, so that you wouldn't be exposed
          to when something is painting
  flackr: ...
  TabAtkins: That paint API issue is pending a predictable random value
             in TC39
  TabAtkins: but using this, could get a predictable random value in
             CSS and use that
  flackr: But not a bunch of random values
  TabAtkins: Not an arbitrary number of random values, need API to
  emilio: Debugging this is going to be fun

  miriam: As someone who uses a lot of randomness in my styles
  miriam: this would allow me to do that without reprocessing my
          stylesheet every time I want an update to the randomness so I
          really like this proposal

  fantasai: I think this sounds pretty good
  <bramus> thumbs up from me as well
  fantasai: I like the idea of using custom ident to coordinate without
            having to use numbers, just let the browser do it

  fantasai: One comment I have right now is random-item(), which has a
            first argument that returns an index, then a list of items
            that you select that index from, you might want that to be
            generic, not specific to randomness
  fantasai: so you can index into a lit of values with attr() or a
            variable, etc
  fantasai: so rather than having a random item function, having
            something like nth-item() that takes a number and list
  fantasai: Also you probably want to separate the list with semicolons,
            like we're doing for mix() and (previously) toggle()
  <bkardell> I like what fantasai is throwing down

  TabAtkins: That was brought up earlier in the thread
  TabAtkins: Reason I didn't do that is because then you need to know
             the length of the list ahead of time to know what the
             random number is
  emilio: mod?
  TabAtkins: non-uniform results
  TabAtkins: also generic function probably doesn't want to mod
  TabAtkins: So yes, having nth-item is something we should have
  TabAtkins: and it is just slightly too un-ergonomic to use for
             randomness, unless we already add a count method
  TabAtkins: and then you have to either repeat your list or whatever
  TabAtkins: A lot of mess for just give me an item from this list
  TabAtkins: which I anticipate being reasonably item
  TabAtkins: not a strike against nth-item()
  fantasai: If we want them separate, I think we should do them together

  TabAtkins: Last point about semicolon. I might. Does mean that syntax
             that random and random-item is different
  TabAtkins: but that might be fine
  TabAtkins: Yeah, probably fine, probably should do that. I agree

  emilio: 1st, what is the syntax for the item in random item?
  emilio: tokens?
  TabAtkins: <declaration-value>
  emilio: So just a bunch of token
  TabAtkins: It's basically variable expansion
  emilio: random() presumably doesn't work like that
  TabAtkins: Correct, it's a math function
  TabAtkins: We could have them both work at variable time, but making
             it work as math is a little more useful
  emilio: Implementation-wise, a lot of stuff relies on being able to
          filter numbers at parse time
  emilio: basically once we're done parsing, translate function
  emilio: So implementation-wise ...
  TabAtkins: Already have that problem in calc()
  emilio: For raw numbers, yes
  emilio: Right now impl heavily rely on
  TabAtkins: Until you implement calc() per values-4
  emilio: If you want this right now, that's where most of the
          complexity is
  emilio: just wanted to mention that
  TabAtkins: I'm trying to remember reason why having as a math
             function is more useful than var()
  TabAtkins: but I can't quite recall
  Rossen: Keep thinking, then

  emilio: The seed is not mandatory?
  TabAtkins: Yes, lack of seed is a seed. It's not arbitrary
  TabAtkins: If you say random(1,10) you get same random value every

  lea: Several things, first I would like to express support. This is
       amazing. I've definitely used JS for this many times
  lea: It would be nice if we could combine and have one function, do
       we fundamentally need a different one for integers vs ?
  TabAtkins: That's literally what we're doing, it returns numbers and
             there's a step
  TabAtkins: Look at the last comment
  lea: Oh!! That's nice!!
  TabAtkins: [re-explains why having random-item() rather than
             nth-item(random()) ]
  fantasai: We can have both. nth-item() and random-item() can have
            parallel syntax and parallel functionality, and both exist
  lea: My other points are not relevant anymore then :)
  lea: It would also solve a host of use cases if you provide a list of
       values and get the index back, e.g. have higher-level custom
       properties and map to other values. Open issue in Web Components
       for awhile
  TabAtkins: Unrelated issue

  fantasai: What's the computed value?
  fantasai: If you put it on an inherited property needs to be the same
            value on every element it inherits through
  TabAtkins: Not necessarily, if you ???
  fantasai: If you take line-height to a random value for line-height
  fantasai: you get a different on each descendant?
  TabAtkins: It would not, it needs to be resolved to something stable
  TabAtkins: If it's a math function it resolves to a number
  TabAtkins: otherwise it might resolve later, e.g., if you have a
  fantasai: Is it returning a number or a length / percent?
  TabAtkins: Depends on the argument
  fantasai: Needs to be clarified properly
  fantasai: so that it inherits properly

  emilio: Why can't it resolve to a number, and then output resolves
  TabAtkins: Say you want a value between 10% and 50% and step of
             100px, how many values is that?
  emilio: So like clamp( ... )
  TabAtkins: If you clamp, you're non-uniform
  TabAtkins: You need to know exactly how many steps between your low
             and high
  emilio: So how would you express that with your proposal
  <TabAtkins> random(..., 10%, 50%, by 100px)
  emilio: That's a lot more complex than I was expecting
  emilio: You have to keep that function around everywhere wherever you
          can accept the percentage all the way through calc()
  TabAtkins: I think it's why it had to be a math function, to get that
             to work
  fantasai: If you restrict it to the same type it you don't have that
            problem right?
  emilio: What fantasai's saying, if you want a percentage random
          between 50% and 100%, you don't have to wait until used value
  emilio: so as long as you restrict it to the same type
  TabAtkins: Lengths can only be computed at used value type
  fantasai: No?
  TabAtkins: For now we've always made sure it's the case
  fantasai: Lengths are always computable to an absolute length

  Rossen: We're going too deep here. Let's put it in a spec
  Rossen: and then make progress on it
  Rossen: It seems like the group supports this generally
  Rossen: so let's do that
  Rossen: Let's try to add this to ...
  fantasai: values-5
  TabAtkins: I'm comfortable to limiting to matching types, if that
             ends up
  TabAtkins: I'd still be ok
  Rossen: So proposal is to add them and maybe restrict it to numbers?
  Rossen: to CSS Values 5

  <fantasai> For the record, I'd really like to restrict this to same
             type for low/high/step
  TabAtkins: The way it's written, you might not get the same result
             across pages. Might not get same result on reload
  dholbert: I hope we can document the algorithm so that it's stable
            between browsers
  TabAtkins: I think that's a great argument that reloads are not
             stable. But re-layout shouldn't be unstable
  lea: I think reloads should absolutely not be stable
  lea: If you want a random color for your theme ever time page loads
       etc, if you get the same thing you might as well pre-compute and
       be done with it
  emilio: With preprocessors, you can't do the per-element behavior
  emilio: That said, depending on how this function computes/resolves/
  emilio: Maybe not un-defeatable, but there's a bunch of optimizations
          that engines have to share styles across elements ...
  emilio: it's a bit unfortunate
  TabAtkins: Alternative is people manually decorate their functions
  emilio: Harder to do than * { z-index: random() }
  TabAtkins: True

  Rossen: Any objections?

  RESOLVED: Add random() and random-item(), mark open issues; goes into

  <TabAtkins> * { position: relative; z-index: random(per-element, 0,
              2e9); }
  <miriam> ^ this is now considered 'best practice'

Received on Wednesday, 31 August 2022 11:03:39 UTC