One thing that has long surprised (and saddened) me is that the
clip-path property, as awesome as it is, only takes a few values. The
ellipse() functions are nice, but hiding overflows and rounding with
border-radius generally helps there already. Perhaps the most useful value is
polygon() because it allows us to draw a shape out of straight lines at arbitrary points.
Update: all three browser engines have clip-path: path() now. Yay!
Here’s a demo of each value:
The sad part comes in when you find out that
clip-path doesn’t accept
path(). C’mon it’s got path in the name! The path syntax, which comes from SVG, is the ultimate syntax. It allows us to draw literally any shape.
More confusingly, there already is a
path() function, which is what properties like
I was once so flabbergasted by all this that I turned it into a full conference talk.
The talk goes into the
shape-outside property and how it can’t use
path(). It also goes into the fact that we can change the
d property of a literal
I don’t really blame anyone, though. This is weird stuff and it’s being implemented by different teams, which inevitably results in different outcomes. Even the fact that SVG uses unit-less values in the
<path d=""> syntax is a little weird and an anomaly in CSS-land. How that behaves, how values with units behave, what comma-syntax is allowed and disallowed, and what the DOM returns when asked is plenty to make your head spin.
Anyway! Along comes Firefox with an implementation!
Does anyone know if clip-path: path() is behind a flag in chrome or something. Can’t seem to find it, but they do support offset-path: path(), so figured they would support both.
Thanks @CSS and @ChromiumDev friends.https://t.co/YTmwcnilRB works behind a flag in FF. Chrome?
— Estelle Weyl (@estellevw) September 13, 2018
Here’s that flag in Firefox (
Also shipped in Firefox 71 today — support for using SVG path() syntax with Clip Path in CSS.
Yup — this is now a thing:
clip-path: path(‘M0.5,1 C0.5,1,0,0.7,0,0.3 A0.25,0.25,1,1,1,0.5,0.3 A0.25,0.25,1,1,1,1,0.3 C1,0.7,0.5,1,0.5,1 Z’);
— Jen Simmons (@jensimmons) December 3, 2019
And here’s a demo…
you’ll see a square in unsupported browsers and a heart in the ones that support
clip-path: path(); — which is only Firefox Nightly with the flag turned on at the time of this writing.
Now, all we need is:
clip-pathto be able to point to the URL of a
<path>in SVG, like
shape-outsideto be able to use
shape-outsideto be able to point to a
offset-pathto take all the other shape functions
- Probably a bunch of specs to make sure this is all handled cleanly (Good luck, team!)
- Browsers to implement it all
(I started this as a twitter comment, but it turned into a thread, so I figured it would fit better here! And then after I’d written it here, I realized that to collect feedback it should also be on the working group’s issue tracker. So it’s copied there, please add your votes: https://github.com/w3c/csswg-drafts/issues/3468 )
## Re: “bunch of specs—Good luck, team!”
The tricky part is fill-rule. The
polygon()function includes fill-rule keywords as an optional first parameter:
<path>element uses the keywords set by the
clip-ruleproperties, depending on the shape’s context. So having a keyword inside the
dproperty would create a conflict.
path()function as currently spec’d for
offset-pathdoesn’t include a keyword parameter, because motion only uses the outline, not the fill.
We have agreed to use that syntax for
<path>shape) as a property.
clip-path(and future stuff like
shape-insideto define the text wrapping area as a shape), we need to know which fill rule to use.
One idea I mused about (but never wrote down) is to define two different CSS data types, one of which is a super class of the other:
<outline-shape>doesn’t have fill-rule keywords
<outline-shape>(with default fill-rule) |
dproperty would take an
<outline-shape>function, no keywords allowed, and would still use the
clip-ruleproperties with no conflict.
Another option is to define an
autovalue for the keyword inside the functions, and make that the default. In
autovalue would behave just like the current default (
nonzero), But in
d, it would behave as “check the
clip-ruleproperty according to context and use that”. If you did specify a different keyword in a function inside
d, it would override the other properties:
A side benefit, in my opinion, is that this means we could long-term plan to deprecate usage of the
clip-ruleproperties, which are already super annoying in the way they depend on context. If you want context-specific keyword values in the CSS function notation, you could use inherited CSS variable values.
But the most important benefit of either of these approaches is that they would allow all the shape functions (possibly minus fill-rule keywords) to be used in all the shape-related properties!!!
If you have opinions on any and all of this, please let us (CSS/SVG editors) and browser teams know! At this point, I’d really like to pick one option so that we can get the full suite of shape functions in all the related properties:
There are still a few other spec-related things that need to be tidied, like animation rules and how much the syntax of path strings gets normalized when you call
getComputedStyle()or otherwise serialize from the DOM. But there isn’t much disagreement there, it’s just a matter of hammering out the details.
(Well, and then there are all sorts of future enhancements I’d like to see, like being able to concatenate multiple path strings stored in variables, or use units in paths. But that’s for later…)
By the way, I am intrigued by the idea of being able to use an SVG
In SVG 2 (sections that are currently being deferred to SVG Sometime), the plan was that
shape-insidecould directly reference a single SVG shape element (like a
<path>). But maybe referencing a
<clipPath>makes more sense, because a clipPath already defines rules for scaling it to fit a referencing element?
Anyway, if you have more ideas on that particular suggestion, Chris, I’d love to see them in the official issue tracker.