-
Notifications
You must be signed in to change notification settings - Fork 668
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
[css-shapes] CSS flexibility for path()
s (and let’s fix paths while we’re at it?)
#9889
Comments
Isn’t this almost exactly what #5674 was about? (I’m pretty sure I’m missing something essential here. It’s late.) |
Hadn't seen that! For anyone else, this is the grammar #5674 resulted in: https://drafts.csswg.org/css-shapes-2/#shape-function That’s great news, this means this proposal is a relatively smaller delta that can be used to improve the existing Lots of commonalities. I love that it also uses It does seem to follow SVG precedent a little more closely, whereas the syntax I’m proposing is a more thorough re-architecting, which seems even more appropriate if we're introducing a brand new function. From a quick look some differences are:
Some comments on the current
|
Your proposed ability to merge shapes-as-paths into larger paths is a good idea! I don't see why it would negate the use of move and close commands, tho. Sometimes it's easier and more straightforward to design things as a single path.
I'm not really a fan of this approach. I'm open to being convinced otherwise, but I'd prefer single-axis lines to be specific about whether they're horizontal or vertical, rather than defaulting to one.
I am absolutely in favor of adding more ways to specify arcs; I understand why SVG chose the representation it did (it lets them continue the "start point -> end point" theme all the other commands use, which makes their "you can omit command names" feature flow a little better), but I also think it's genuinely the worst way to specify arcs out of all the common reasonable ways. But again, I don't see why we wouldn't expose SVG's exact arcs as well.
I can see either design as reasonable. I do prefer the current spec design, though: it doesn't require people to spell Note, too, that you can't omit the control points in a smooth cubic; you get the first for free, but still need to specify the second. But that's just a grammar bug, not a substantive comment.
In my personal experience writing SVG by hand, that "most cases" is definitely wrong. I mix absolute vs relative all the time, depending entirely on what's more convenient both for authoring in the moment and editting in the future. It indeed needs to be a per-command thing. (Sometimes it would be useful to be able to split it even finer, and do per-coordinate, but I think the syntax design needed for that to work would be terrible.)
Sure, but
It certainly make more sense than |
Couldn’t agree more regarding better / more ways to express arcs.
|
Thanks for the extensive response @tabatkins!
I addressed this in the proposal, and just edited it a bit for clarity:
I would love a few use cases where this is true!
I think you may have misunderstood, it’s not about lines defaulting to one, it's about endpoints having a single coord syntax for when they are only a horizontal/vertical offset. Lines just take an endpoint. Horizontal and vertical lines are still lines. There is no reason for them to live under a separate command just so we could provide defaults to one of their parameters. I think it should be an explicit goal to keep the number of distinct commands small and easily memorable, and avoid having many different commands for similar but slightly different things, which the original SVG path syntax severely suffers from.
Yes, I see the rationale too, and agreed the ergonomics are terrible for human use.
I think you may have missed that my proposal includes syntax for both. :)
Agreed on most of this.
My most substantive objection to the current syntax would be that I think
Fair enough.
Agreed that ideally you want both terseness and readability, but when they conflict, readability is more important than length. Again, code is written once but read many times. Also remember that we only need the keyword to override the default. FWIW in my proposal I used
Sure, but these are not the only options. Again, we only need one keyword really, to override the default. In CSS color interpolation we use |
General +1 to Tab's comment, also +1 to |
The thing is, tho, we do add things for completeness sometimes, when their lack would be a surprise to authors. Strict adherence to "use-case or gtfo" can result in weird holes in APIs, and gratuitous differences between things that are intended to be very similar or even identical otherwise. Predictability is one aspect of usefulness in an API. That's my feeling here. SVG paths have Move and Close, and these can be expressed in Having the ability to write simple shapes using the existing shape functions, and merge them with a path or other shapes, is great. But forcing people to write it in that way, when the existing functionality to do it all in one path is right there, isn't.
The most obvious use-case is any time a relative move-to is convenient or meaningful. A fresh shape is effectively an absolute move-to, which might be annoying vs just saying "and then start the circle 10px to the side of this". (And I suspect it's not worthwhile to add syntax to allow shifting the coordinate space of another shape function.)
No, I understood what you were referring to here, it's the idea that there's a meaningful default direction for a single length to be pointing in that I disagree with. I don't believe it's very readable to assume that
I agree the SVG path syntax suffers from this (see C/S/Q/T, for example), but I don't think that "minimal command set" should be a goal in and of itself. The command set should be the "right" size, using optionality and control parameters when it helps readability, but feeling free to introduce multiple commands when it helps instead.
Yeah, that's not the best, but I also don't know what to do about it. I don't think Hm, a possibility - what if the coord-pair grammar was
I'm not opposed to this. (Or maybe the curve command's name is
We're already in the context of the I think it might be reasonable to make the size keyword non-optional, in fact; while CSS does have a preference for cw/ccw direction, it doesn't generally have a preference for large vs small things. Forcing it to be always be present ensures that people will have some idea of what it does in order to even write the command.
If we default to the clockwise arc pair, in accordance with CSS's general preference for clockwise angles, then using |
(See next comment for a much shorter actual proposal; this comment is noodling in the problem space.) So, let's talk about better circle commands, since SVG arcs are, indeed, terrible.
Okay, so I think all of these are pretty reasonable; three of them already exist on the web platform, so supporting them has a good consistency argument, and the variant proposed by Lea is a nice simplification of one of them. Let's talk grammars. We already have a grammar for the SVG arcs:
Tho with the discussion here, we might want to fix it up a bit to:
(Tho both of these allow specifying some ellipse-specific options when doing a circle. Maybe instead:
) Lea's simple arc is:
HTML's arc()/ellipse() are:
HTML's arcTo() is:
And expanded to be elliptical:
Lea's suggested arc looks to be doable just as a subset of
We might want to make the "straight line to the start of the arc" for circle/ellipse/corner skippable, In theory, there are more possible ways to define circle segments, but these are the three ways that already exist on the web platform (and thus have consistency as a justification), plus Lea's reasonable simplification of one of them. I don't think we should go any further without strong use-cases; we can easily add shortcut commands all day if we don't control ourselves. |
OKAY. All together, I suggest then that our circle/ellipse command set be:
I'm slightly uncomfortable with the fact that circle/ellipse/corner all use |
One thing to note is that, since SVG commands all rquire an explicit endpoint, you can always "skip" a command by just changing to a This also fixes the existing problem in HTML where, if you do want to draw a rounded rect using just four Like:
That initial While only |
For sequences of multiple control points, why not just say |
I'm open to getting to more usable arc commands. The syntax is such that we can add new types of commands progressively. One point to note is that I think authors will be generally using tools to generate these paths; it's very hard to author these by hand. So ease of generation from tooling will be important, and most tooling in this area will have been written with the current SVG path behavior in mind. |
What kind of tooling do you have in mind that has already been written and would be able to work with CSSified paths? I'd expect any current tooling that works with paths also depends on the current syntax of paths, but perhaps I'm missing some? Also relevant: https://pr-preview.s3.amazonaws.com/w3ctag/design-principles/pull/505.html#text-formats |
I'm thinking of things like https://svg-path.com, https://yqnn.github.io/svg-path-editor/ etc, and tools like Inkscape. There are many tools to generate SVG paths; a lot of |
Can we close this now that the |
I think so. Let’s open new issues if there are any found in the draft. |
One of the things that came out of #9843 was that
path()
would benefit from the kind of flexibility that CSS values afford. Right now it’s an SVG path data string:CSS values would allow paths that adapt to the element geometry and other contextual parameters, and would make it possible to parameterize paths and generate parts of them via variables, solving a host of well established use cases.
Proposal
The main dilemma when doing that is whether to aim for maximum consistency with SVG paths, merely allowing
<length-percentage>
for points but keeping everything else the same, or whether we should try to optimize for human usability as well.As an experiment, I went with the latter, so the proposal below diverges from SVG paths in several ways.
Diverging from SVG also allows us to fix some of the established usability problems with its path syntax, that go beyond mere syntax. When total consistency is desired authors can always use the old syntax.
General syntax
Relative vs absolute clear from the syntax (
to
vsby
), rather than the obscure uppercase vs lowercase distinctionEndpoint can include one or two coordinates. If only one is provided, Y defaults to zero, unless
down
is also specified, in which case X defaults to zero. This sounds weird, but results in very natural syntax (e.g.line by 1em down
)Specific commands
Move To (M) and Close Path (Z)
SVG paths have commands to close and move, so that one can combine multiple shapes into a single path. I think this is an unfortunate coupling of unrelated concepts and we would never consider it today if it weren't so established already.
The proposal below does not include these commands at all, only an absolute starting point in the preamble. Instead, I propose we introduce separate operators to combine multiple shapes into one (union, difference, etc.), with union being by far the most needed (
shape-combine()
below).If the last endpoint does not match the starting point, the path is automatically closed.
Yes, this means creating open paths is not possible. We can always introduce a future flag to prevent this, if it becomes needed in the future.
This may seem strange given existing SVG precedent. My justification is below.
First, I hope we all agree that as a design principle, we want to make common things easy and complex things possible. The simple case is by far more frequently a single closed shape, especially once we consider how CSS shapes are currently used. Subpaths add complexity to that simple case (since you now have to remember to close your paths), and make the syntax more error-prone (since you get unexpected results if you forget to close your paths).
But even worse, even when you do need multiple shapes, this forces you to now express all of them as paths, even when literally all but one are simpler shapes like circles and rects, introducing an ease of use to power cliff. I question whether subpaths ever reflect user intent. I hypothesize that in nearly every case they are a workaround to a different problem, which is to combine multiple existing shapes into a single shape.
Lastly, being able to assume that every CSS basic shape is a single, closed, contiguous shape involves fewer restrictions around what we can use shapes in CSS for.
Again, as a design principle, we don't add things for completeness or because they look cool, but because they are justified by use cases which are common and pervasive. I think we should first prove that subpaths pass that bar before we bake them into
path()
simply because they exist in SVG.Lines (L, H, V)
line to
. This should also make it easier to convert a polygon to a path if we realize we need additional powerround
backported from [css-shapes] Allow optional rounding parameter forpolygon()
#9843Arcs
Curves (S, C, T, Q)
Full Grammar
Layering (MVP vs v1+)
Potential layering could involve:
<shape-combine()>
laterIssues
Relative vs absolute distinction
I have some reservations about using
to
vsby
is natural enough.But even if it is, when a command is relative in SVG, that affects all its parameters. Right now, the grammar is not making that clear — it looks as if it only affects the path endpoint. Do we even need that kind of fine grained control? In most cases a shape is either entirely absolute, or entirely relative (with an absolute start point). Perhaps absolute vs relative could be part of the preamble? Or even the function name?
Integration into SVG?
We could potentially integrate this back into SVG by introducing a set of child elements for
<path>
, e.g.<line>
,<arc>
,<curve>
.<line>
is an existing element though I believe its API is compatible, so I see this as a nice synergy, not a conflict. Alternatively, a<segment>
element with an optionaltype
attribute (defaulting toline
).@svgeesus might be able to provide sources, but I believe child elements for the path segments were discussed in the beginning as a more human friendly alternative and were not chosen only because compactness was considered critical at the time. 25 years later, the tradeoffs are different.
The text was updated successfully, but these errors were encountered: