Join GitHub today
GitHub is home to over 36 million developers working together to host and review code, manage projects, and build software together.Sign up
[css-shapes-1] Degenerate polygons with positive shape-margin #2375
If a degenerate polygon has a positive shape-margin, it is practically useful for it to NOT have an empty float area. One example is an animated shape-outside: polygon with a shape-margin where the points in the polygon are momentarily made colinear. If the float area becomes empty in this case, the float area would collapse, only to abruptly reappear when the animation moved the points into an area-enclosing shape.
It would be useful for the spec to define the float area in the cases where the polygon is degenerate, but has a positive shape-margin. There are three cases:
@astearns As far as identifying empty floats goes, it makes it easier, since you'd only need to check the shape's geometry if the
I created a test case: https://codepen.io/AmeliaBR/pen/rJRyyw?editors=1100
I agree with @bradwerth that it would be preferable to apply the margin to a zero-area shape, in the same manner as stroking that shape with a stroke twice the margin's width.
In fact, for
So the use case from @AmeliaBR is to be able to specify a shape that matches the inked area of an SVG path? That works for a simple line (non-dash, etc.) case, but not generally. For this case it might be better to get the inked area as an image and wrap around that.
There are also degenerate circles, ellipses and inset rects (which might need a larger value of shape-margin than merely >0 to amount to non-empty)
I'm open to considering the change if there's a good reason to take it. We did consider this case in the early stages of the spec, and went back and forth a few times over it (as I recall).
One case we considered is when a shape has a zero-width strut (for whatever reason). Say you have a triangle with a zero-width spur coming out from one of the vertices. If you animate shape-margin from zero to some positive value, then it's a bit surprising to have content jump away from what was previously an invisible part of the shape. It might be better to consider zero-width lines as contributing to the shape-outside wrapping effect to avoid that discontinuity.
I wasn't really thinking of that as a driving use case, more as a way to conceptualize & visualize it.
I agree that the main use case is to have a consistent transition from an almost-linear shape to an exactly linear shape, or for a shape being animated down/up from point (if you really wanted to animate it down to nothing, you could always animate down the margin to 0, to create a smooth transition).
Yes, I think so. The more I play around with it, the more it makes sense to use any edge as the boundary, regardless of fill area.
I added two more samples to my test case, both using a cross shape. In the first, the cross is exact, so that there is zero fill area and the float layout ignores the polygon. In the second, a few points have been shifted by a tenth of a pixel and the layout is completely different (although the difference in the SVG visualization of the same shape is imperceptible to my eyes). Both the vertical and the horizontal lines of the cross affect the layout.
I see two options, each with minor drawbacks (and I consider the current state of the spec to have a minor drawback as well, shown by this issue)
Interesting counter-example. I have used "zero-width struts" in clip-path shapes, but I would never have expected them to be transparent in a shape-outside situation. You could always construct that shape so that the connecting strut is on the far edge, but then it wouldn't be convertible for the opposite float direction. Either way, I think the better solution for that use case is to support
This seems most consistent and intuitive, considering that floats are in some sense checking for the edges of the shape, not checking for a nearby area associated with the shape. Adopting this into the spec would resolve things for circle and ellipse (with a 0 radius they would collapse to a point or a line). It would simplify the implementation for polygon though require some clarification about polygons with 1 or 2 vertices (do they define a point / line). The challenging one will be inset. If box is inset more than 100%, it either should be treated as a point or line (where?) or as an inside-out polygon. Neither option is particularly intuitive, but this all seems more intuitive than a shape disappearing when it has no positive area.
We're shipping support for shape-outside in Firefox 62. On this issue of shape areas versus edges, we are not compliant with the spec as written. We decided to ship our implementation enforcing these principles:
I'm not too keen on this point. Could result in weird rounding errors where it is difficult to shrink the rectangle to exactly zero. I would rather limit the inset rectangle to a minimum of zero width/zero height, using rules similar to how border-radius values that add to greater than 100% are adjusted.
I would support that as long as the spec defines the location of the point. Where should it be in a case like inset(100% 100% 50% 50%)? The two choices I would find most intuitive are either at the center of the original rect, or at the center of the inverted rect.
My suggestion to use
For inset rectangles, the calculation would be simpler,* because you're not worried about maintaining the aspect ratio of a corner curve:
That means that if the insets on opposite sides are equal, the collapsed point/line would be in the exact middle of the reference box. If one inset is 9 times the opposite inset, the point would be 1/10th of the distance across.
It would be at the same point as
* Unless you wanted to also scale down the border-radius curves proportionally, in which case things could get complicated. But if I'm reading the function definition correctly, the border radiuses apply after the insetting happens (e.g., a border-radius of 10% would be 10% of the inset shape, not the original box), so it's probably best to keep that as a separate step, with its own adjustments.
The Working Group just discussed
The full IRC log of that discussion<dael> Topic: Degenerate polygons with positive shape-margin
<dael> github: https://github.com//issues/2375
<dael> TabAtkins: The current shape spec has test about degenerate polygons. It makes them not create a shape, text can pierce through.
<dael> TabAtkins: It doesn't have a special case for a positive shape margin where actual exclusion area is non-0. We should ammend the spec so things with positive shape margin are treated as having a postive area
<dael> TabAtkins: Issue goes further that the ruling about Degenerate polygons is wrong and we should remove. SVG has similar issue where if trying to stroke a path and size of box for stroking is determined by fill rectangle. Can be 0 area and triggers special cases where it isn't stroked and causes strange cases.
<dael> TabAtkins: Get similar issues where if animating polygon and if all points lin up you temp get entire layout to shift as it no longer excludes. Issue argues we remove special casing
<dael> TabAtkins: I looked at our code with iank_ and he supports it b/c it's removing special case
<dael> TabAtkins: Only complication is you can have negative margins and it can shrink spacing to 0. With degenrate rule you didn't have to worry about where 0 is. AmeliaBR suggestion sounds reasonable at first glance to solve. It's relatively corner case.
<dael> TabAtkins: Larger is should 0 area be an exlucsion
<dael> TabAtkins: Chrome supports the change
<dael> Rossen: Other prospective?
<myles> what is inverted space
<dael> astearns: I support what's discussed in issue. q: you can have polygons with inverted areas, not just a line but they're crossing and inverted area inside. If you have a positive shape margin in that case does it have to overcome the inverted space or do we define inverted space to uninvert
<myles> winding order?
<dael> TabAtkins: Good q, don't have best answer. Related to whe you over-deflate. Shoudl a really big neg margin cause positive shape. Should they
<tantek> there's a similar question / issue with negative outlines
<dael> fantasai: They don't. We won't change that.
<dael> TabAtkins: Why?
<dael> fantasai: Right now if you have a float with neg margin on both sides that won't turn into a positive shape
<dael> TabAtkins: It's a shape-maargin not a normal one.
<dael> fantasai: shape-margin is positive only?
<dael> TabAtkins: Nope
<dael> fantasai: I still think same principle should apply. Why can't you create a rectangle with the same behavior as a float.
<dael> TabAtkins: There's a lot of difference with shape and shape-margin so I don't know yet. I'm happy to figure it out as we go along. DOn't think we need to resolve to resolve this issue
<tantek> regarding what astearns said about inverted areas, here is another way we end up with inverted areas (and incompat) https://github.com//issues/2892
<dael> astearns: Clarification: It sounded like polygons with jsut lines and a positive shape margin will add their shape to exclusion area. Also polygons that are just lines will include line edge even w/o margins
<dael> TabAtkins: Correct
<dael> TabAtkins: There's a special case in our shape code and it skips by it currently. We just remove that check.
<dael> astearns: I propse we take what's in the issue, put in spec, and attempt to spec inverted areas and bring to group
<dael> iank_: One other thing, I filed an issue, but there will be bugs if we do just a paragraph. When we do this change I'd prefer we define how a line-box intrudes into a float with a shape outside and write out algo.
<dael> iank_: Otherwise someone will do something slightly different and we get compat bugs
<dael> iank_: It's issue [looking]
<dael> iank_: #2949
<dael> iank_: I looked at Moz code and they have same concept in their code
<dael> astearns: Thanks
<dael> Rossen: Going back to this issue
<dael> Rossen: Can we take the resolution proposed by TabAtkins?
<dael> astearns: I'm fine
<dael> TabAtkins: proposal: we take what's in the issue, put in spec, and attempt to spec inverted areas and bring to group
<dael> Rossen: Objections?
<dael> astearns: Agree with issue and bring it into the spec to match
<dael> Rossen: Accept the changes as stated in the issue. Objections?
<dael> RESOLVED: Accept the changes as stated in the issue