- From: Amelia Bellamy-Royds via GitHub <sysbot+gh@w3.org>
- Date: Mon, 17 Jun 2024 23:15:05 +0000
- To: public-css-archive@w3.org
@bernaferrari asked: > how much do you like the Apple syntax? I agree with @tabatkins (and thanks for the summary, Tab): the Swift UI mesh gradient definition solves many of my complaints with the SVG syntax, although there remain some unavoidable complexities from the mesh-gradient structure: - The grid is defined by the network of points (colour stop positions), not the patches between them. - The curve control points (or none for straight lines) are clearly associated with each point. - The order of points and how they relate to rows/columns of the grid is consistent. - There's no worry about implicit points or curves: control points for curves that don't connect anywhere can be specified and ignored. - The geometry and colours are given as separate objects, so that the same geometry (stored in a variable) can be re-used with a different colour set. - But: it still requires an explicit row & column grid to be defined, and is therefore more complicated to author and adjust than the freeform scatterplot of colour points. I don't like the practice of specifying a 2D structure as a 1D array with width & height attributes to parse it in a grid, but that's common in graphics programming & CSS has a lot more syntactic options to more clearly separate rows of values. As a potential [CSS value-definition syntax](https://drafts.csswg.org/css-values-4/#value-defs) version of that, we'd be looking at something like: ``` mesh-gradient( [<color-interpolation-method> || <mesh-gradient-method>, ]? mesh-points(<mesh-point-grid>) || mesh-colors(<mesh-color-grid>) || <base-color> ) <mesh-gradient-method> = bilinear | bicubic <mesh-color-grid> = <mesh-color>* [ / <mesh-color>* ]* <mesh-color> = <color> | auto <base-color> = <color> <mesh-point-grid> = <mesh-point>* [ / <mesh-point>* ]* <mesh-point> = [ <position> || auto ] ( <mesh-control-point>#{1,4} )? <mesh-control-point> = [<length-percentage> <length-percentage>] | <angle>? && <length-percentage> ``` The mesh-gradient-method would be bilinear by default, because I think that's simpler to render and I believe it's the default for PDF. (Although I don't really know the difference, so I defer to those who do!) The four control points in the mesh-point data structure would be ordered & expanded in a TRBL way. Each control point is defined either as relative lengths in the X and Y axis from the point with percentages relative to the distance in that axis to the next point, or (optionally, my proposal) as an angle (defaulting to straight up, right, down, left as appropriate) and a length with percentages relative to the straight-line distance to the adjacent point on that edge. If omitted (or 0 length), the control point would be the point itself, creating a straight-line approach to that point. (I'm assuming that if CSS adds a logical-directions mode to gradients in general, it would apply as a single keyword that then mirror-flips all geometry as necessary to convert top/bottom to block-start/block-end and right-left to inline-start/inline-end. In other words, I'm not worrying about logical directions at the micro-syntax level.) Auto positions, or those that are omitted (that is, there aren't enough points in any row/column, or the whole position grid is skipped), would be automatically distributed similar to linear gradients: a first/last value in either axis defaulting to 0 or 100%, other stops without positions would be evenly spaced on each axis. (Which means it might be useful to extend the position syntax to support `auto` in one axis but not the other, but I'm not going to define the Value syntax for that.) The base color fills in the space outside the mesh geometry (it's called background color in the Swift API, but I didn't want to confuse with CSS background layers: this is a color that is part of the gradient image). It defaults to transparent. Auto colors use the base color for the corner-points of the mesh, or are automatically interpolated from adjacent color points otherwise (exact algorithm to be defined, but the idea is that it would make it much easier to insert an extra row/column into the grid and only specify colours where you want to tweak them). If colors are omitted (not enough values in each row/column to match the grid points) they would be auto. If you omitted the entire color grid, you'd just get a solid color gradient in the base color. The only thing missing is a way to snap adjacent color points together to get a sharp color-change stripe. In other CSS gradients, you can do this by setting the position to 0 and letting the fix-up algorithm make the length/angle position match the previous point, since it can't be any less. For a mesh grid, I'm not sure whether that fix-up applies. Maybe there could be another position keyword, similar to auto, but to snap to the previous point in a row/column instead of to distribute points evenly? That syntax definition is a lot. What would it look like in actual CSS code? A simple 2D gradient like in @LeaVerou's colour picker example — where you define four corner colors and let the color interpolation space do the rest — would be defined like: ```css mesh-gradient(oklab, mesh-colors(lime, red / cyan, magenta) ); /* except you'd probably define the corner colors in oklab() functions */ ``` The 4-patch / 9-point wavy gradient example from the SVG spec (for which I gave the proposed SVG markup, above) could be defined like this, making using of a variable for the repeated control point geometry of the repetitive wave structure: ```css --wavy: (-25% -25%, 25% -25%, 25% 25%, -25% 25%) ; background-image: mesh-gradient( mesh-points( 50px 50px var(--wavy), 150px 50px var(--wavy), 250px 50px var(--wavy) / 50px 150px var(--wavy), 150px 150px var(--wavy), 250px 150px var(--wavy) / 50px 250px var(--wavy), 150px 250px var(--wavy), 250px 250px var(--wavy) ), mesh-colors ( lightBlue, purple, lightBlue / purple, red, purple / lightBlue, purple, lightBlue ) ); ``` As far as CSS function values go, there's a lot of parts there! But I'd still say it's much more readable (and editable) than the proposed SVG version, and in 1/3 of the code (even if the repetitive geometry helped a lot for this example). I especially like how the colours can easily be read as a grid to get an idea of what it might look like. The absolute dimensions for the points in this example aren't very CSS-y, but they could easily be replaced by percentages, side keywords, or calc expressions to make them offsets from the sides of the box. Any mix of relative, absolute, and percentage lengths can be resolved down to absolute lengths and positions at used-value time, which would then get sent to a rendering engine that's built for PDF-style mesh gradients. **If CSS were to add *both* something like this detailed mesh-gradient syntax *and* a simpler freeform/scatterplot syntax, I think it would meet the objective to "make easy things easy and make difficult things possible."** (But we still need a clear definition of exactly what Adobe Illustrator is doing with those scatterplot points & whether they can be rendered as an equivalent mesh gradient.) And then SVG would just have to [support CSS gradients as fill / stroke](https://drafts.fxtf.org/fill-stroke/), and it would get them too! 😜 -- GitHub Notification of comment by AmeliaBR Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/7648#issuecomment-2174600950 using your GitHub account -- Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config
Received on Monday, 17 June 2024 23:15:06 UTC