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 circle()
and 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 offset-path
take.
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 <path>
.
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
Support
Here’s that flag in Firefox (layout.css.clip-path-path.enabled
):
Update!
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-path
to be able to point to the URL of a<path>
in SVG, likeurl("#clip-path");
shape-outside
to be able to usepath()
shape-outside
to be able to point to a<path>
offset-path
to 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:But a
<path>
element uses the keywords set by thefill-rule
ORclip-rule
properties, depending on the shape’s context. So having a keyword inside thed
property would create a conflict.The
path()
function as currently spec’d foroffset-path
doesn’t include a keyword parameter, because motion only uses the outline, not the fill.We have agreed to use that syntax for
d
(<path>
shape) as a property.But for
clip-path
(and future stuff likeshape-inside
to 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<filled-shape>
=<outline-shape>
(with default fill-rule) |polygon()
andpath()
with keywordsSo, the
d
property would take an<outline-shape>
function, no keywords allowed, and would still use thefill-rule
/clip-rule
properties with no conflict.Another option is to define an
auto
value for the keyword inside the functions, and make that the default. Inclip-path
, anauto
value would behave just like the current default (nonzero
), But ind
, it would behave as “check thefill-rule
orclip-rule
property according to context and use that”. If you did specify a different keyword in a function insided
, 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
fill-rule
/clip-rule
properties, 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:
https://github.com/w3c/csswg-drafts/issues/3468#issuecomment-449760438
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
<clipPath>
element inshape-outside
.In SVG 2 (sections that are currently being deferred to SVG Sometime), the plan was that
shape-outside
andshape-inside
could 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.