From c5e2de623976ed5e125c9f85ce9b5f1e44637582 Mon Sep 17 00:00:00 2001
From: Daniil Sakhapov
Date: Fri, 16 Jan 2026 15:02:37 +0100
Subject: [PATCH] Brush the border shape property spec text
Add some structuring, some examples, improve wording.
---
css-borders-4/Overview.bs | 196 +++++++++++++++++++++++++++++++-------
1 file changed, 164 insertions(+), 32 deletions(-)
diff --git a/css-borders-4/Overview.bs b/css-borders-4/Overview.bs
index e75e218c0f68..460efcde325e 100644
--- a/css-borders-4/Overview.bs
+++ b/css-borders-4/Overview.bs
@@ -3148,7 +3148,7 @@ Border Shaping
While 'corner-shape' and 'border-radius' allow some expressiveness to styling a border,
they still work with the assumption that the border is rectangular.
- The 'border-shape' function augments these capabilities,
+ The 'border-shape' property augments these capabilities,
by enabling the author to use any [=basic shape=] to specify the path of the border.
@@ -3165,49 +3165,181 @@ The 'border-shape' property
Animation type: by computed value
-The 'border-shape' property is provided with either a single <> or two <>s,
-resulting in one or two paths, respectively.
+ The 'border-shape' property defines custom shapes for element borders
+ using one or two [=basic shape=] values.
-When two <> values are given, the border is rendered as the shape between the two paths.
-When only a single <> is given, the border is rendered as a stroke with the
-[=relevant side for border shape|relevant side=]'s [=computed value|computed=] [=border width=] as the stroke width.
+
+Syntax and Usage Modes
-The fill color of the border is the [=relevant side for border shape|relevant side=]'s [=computed value|computed=]'border-color'.
+ The 'border-shape' property accepts either a single <> or two <>s:
-When a <> is not given, the default computation of percentage differs based on the number of given <> values.
+ : Single <> (Stroke mode)
+ :: The border is rendered as a stroke along the shape's path,
+ with the stroke width determined by the
+ [=relevant side for border shape|relevant side=]'s [=computed value|computed=] [=border width=].
+ This mode is useful for creating outlined shapes.
-When two <> values are given, the first (outer) one defaults to the [=border box=] and the second (inner) one defaults to the [=padding box=].
-This allows using the different 'border-width' properties to affect the final shape.
+ : Two <>s (Fill mode)
+ :: The border is rendered as the area between the two paths.
+ The first shape defines the outer boundary,
+ and the second shape defines the inner boundary.
+ This mode provides precise control over the border region's geometry.
+ The fill color of the border is the [=relevant side for border shape|relevant side=]'s [=computed value|computed=] 'border-color'.
-When a single <> value is given, the <> defaults to the ''half-border-box'' value, which allows stroking in a way that matches the default border behavior.
+
+Geometry Box References
-The 'border-shape' property is not compatible with 'border-radius' and 'corner-shape'.
-When an element's [=computed value=] of 'border-shape' is not none,
-its 'border-radius' is ignored, as if it was set to 0.
-'corner-shape' is implicitly ignored, as it can only work in tandem with 'border-radius'.
+ When a <> is not explicitly provided,
+ the default reference box depends on the number of <> values:
-An [=outer box-shadow=] follows the outside of the outer path, and an [=inner box-shadow=] follows the inside inner path.
-Both are rendered as a stroke, with a stroke width of spread * 2, clipped by the border shape.
+ : Single <>
+ :: The <> defaults to the ''half-border-box'' value,
+ which positions the stroke to match the default border behavior,
+ with the border extending equally inward and outward from the shape path.
+
+ : Two <>s
+ :: The first (outer) shape defaults to the [=border box=],
+ and the second (inner) shape defaults to the [=padding box=].
+ This allows the 'border-width' properties to naturally affect the final shape.
-'border-shape' does not affect geometry or layout,
-which is still computed using the existing 'border-width' properties.
+
+Examples
-'border-shape' does not affect the flow of content inside the box.
-Note: An author can use 'border-shape' in tandem with 'shape-inside' to create effects that decorate the box and control its text flow at the same time.
+
+ Creating a circular border using stroke mode:
-The inner 'border-shape' clips the [=overflow=] content of the element, in the same manner as 'border-radius',
-as described in
corner clipping.
+
+ .circular-button {
+ width: 100px;
+ height: 100px;
+ border: 5px solid blue;
+ border-shape: circle(50%);
+ }
+
-Issue: how should this affect clipping replaced elements?
+ This creates a circular border with a 5px stroke width.
+
-
-An element's relevant side for border shape is the first side (in the order [=block-start=], [=inline-start=], [=block-end=], and [=inline-end=]) that has a non-''border-style/none'' [=border style=], or [=block-start=] if they're all ''border-style/none''.
- 1. If |element|'s [=computed value|computed=] 'border-block-start-style' is not ''border-style/none'', then return [=block-start=].
- 1. If |element|'s [=computed value|computed=] 'border-inline-start-style' is not ''border-style/none'', then return [=inline-start=].
- 1. If |element|'s [=computed value|computed=] 'border-block-end-style' is not ''border-style/none'', then return [=block-end=].
- 1. If |element|'s [=computed value|computed=] 'border-inline-end-style' is not ''border-style/none'', then return [=inline-end=].
- 1. Return [=block-start=].
-
+
+ Creating a diamond-shaped border using fill mode:
+
+
+ .diamond {
+ width: 200px;
+ height: 200px;
+ border: 10px solid crimson;
+ border-shape:
+ polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)
+ polygon(50% 10%, 90% 50%, 50% 90%, 10% 50%);
+ }
+
+
+ This creates a diamond border by defining outer and inner polygons.
+
+
+
+ Using a custom path shape:
+
+
+ .custom-shape {
+ border: 8px solid green;
+ border-shape: path('M 10,30 A 20,20 0,0,1 50,30 A 20,20 0,0,1 90,30 Q 90,60 50,90 Q 10,60 10,30 z');
+ }
+
+
+ This creates a heart-shaped border using an SVG path.
+
+
+
+ Combining 'border-shape' with different border widths:
+
+
+ .fancy-box {
+ width: 100px;
+ height: 100px;
+ border-top-width: 10px;
+ border-right-width: 5px;
+ border-bottom-width: 10px;
+ border-left-width: 5px;
+ border-style: solid;
+ border-color: purple;
+ border-shape: ellipse(50% 40%);
+ }
+
+
+ The [=relevant side for border shape=] determines which border width is used for the stroke.
+
+
+
+Interactions with Other Properties
+
+
+Interaction with 'border-radius' and 'corner-shape'
+
+ The 'border-shape' property is not compatible with 'border-radius' and 'corner-shape'.
+ When an element's [=computed value=] of 'border-shape' is not none,
+ its 'border-radius' is ignored, as if it was set to 0.
+ 'corner-shape' is implicitly ignored, as it can only work in tandem with 'border-radius'.
+
+ Note: Authors should use either 'border-shape' for custom shapes
+ or 'border-radius'/'corner-shape' for rectangular boxes with styled corners,
+ but not both simultaneously.
+
+
+Interaction with 'box-shadow'
+
+ An [=outer box-shadow=] follows the outside of the outer path,
+ and an [=inner box-shadow=] follows the inside of the inner path.
+ Both are rendered as a stroke, with a stroke width of spread * 2,
+ clipped by the border shape.
+
+
+
+ .shaped-shadow {
+ border-shape: circle(50%);
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
+ }
+
+
+ The shadow follows the circular shape rather than a rectangular box.
+
+
+
+Interaction with Overflow and Clipping
+
+ The inner 'border-shape' clips the [=overflow=] content of the element,
+ in the same manner as 'border-radius',
+ as described in corner clipping.
+
+ Issue: how should this affect clipping replaced elements?
+
+
+Interaction with Layout
+
+ 'border-shape' does not affect geometry or layout,
+ which is still computed using the existing 'border-width' properties.
+ The shaped border is purely a visual effect.
+
+ 'border-shape' does not affect the flow of content inside the box.
+
+ Note: An author can use 'border-shape' in tandem with 'shape-inside'
+ to create effects that both decorate the box and control its text flow.
+
+
+Determining the Relevant Side
+
+
+ An element's relevant side for border shape is the first side (in the order [=block-start=], [=inline-start=], [=block-end=], and [=inline-end=]) that has a non-''border-style/none'' [=border style=], or [=block-start=] if they're all ''border-style/none''.
+ 1. If |element|'s [=computed value|computed=] 'border-block-start-style' is not ''border-style/none'', then return [=block-start=].
+ 1. If |element|'s [=computed value|computed=] 'border-inline-start-style' is not ''border-style/none'', then return [=inline-start=].
+ 1. If |element|'s [=computed value|computed=] 'border-block-end-style' is not ''border-style/none'', then return [=block-end=].
+ 1. If |element|'s [=computed value|computed=] 'border-inline-end-style' is not ''border-style/none'', then return [=inline-end=].
+ 1. Return [=block-start=].
+
+
+ Note: This algorithm ensures consistent behavior when multiple border sides have different styles or widths.
+ The first non-none border side (in logical order) determines the border characteristics
+ used for the shaped border.