Title: CSS Borders and Box Decorations Module Level 4
Shortname: css-borders
Level: 4
Status: WD
Prepare for TR: yes
Date: 2025-12-16
Work Status: Exploring
Group: csswg
ED: https://drafts.csswg.org/css-borders-4/
TR: https://www.w3.org/TR/css-borders-4/
Editor: Elika J. Etemad / fantasai, Apple, http://fantasai.inkedblade.net/contact, w3cid 35400
Editor: Lea Verou, Invited Expert, http://lea.verou.me/about/, w3cid 52258
Editor: Sebastian Zartner, Invited Expert, sebastianzartner@gmail.com, w3cid 64937
Editor: Noam Rosenthal, Google, w3cid 121539
Former Editor: Bert Bos, W3C, bert@w3.org, w3cid 3343
Abstract: This module contains the features of CSS relating to the borders and decorations of boxes on the page.
Ignored Terms: border-*-*-radius, border-*-clip, box-shadow-*, corner-*-shape, corner-*-*-shape, corner-*-*, corner-*
Ignored Vars: block, inline, Li, Ltop, Lbottom, Lleft, Lright, spread, total width, W, Wside, Wleft, Wright, Wtop, Wbottom
Repository: w3c/csswg-drafts
WPT Path Prefix: css/css-borders/
WPT Display: open

Introduction

The properties of this module deal with the decoration of the [=border area=]. It also defines decorations that can be applied to the box.

Module Interactions

This specification extends the parts related to borders and box decorations of CSS Backgrounds and Borders Module Level 3 [[CSS3BG]]. It provides specifications for the added 'corner-*-shape' and 'border-shape' properties, as well as logical shorthands for 'border-*-radius', 'box-shadow-*' longhands, and partial borders via the 'border-limit' and 'border-*-clip' properties. All properties in this module apply to the ''::first-letter'' [=pseudo-element=]. The border-radius properties also apply to the ''::first-line'' [=pseudo-element=]. The UA may (but is not required to) apply the 'border-image' or 'box-shadow' properties to ''::first-line''. The UA must not apply the border-color/style/width properties to ''::first-line''. [[!CSS2]]

Value Definitions

This specification follows the CSS property definition conventions from [[!CSS2]] using the value definition syntax from [[!CSS-VALUES-3]]. Value types not defined in this specification are defined in CSS Values & Units [[!CSS-VALUES-3]]. Combination with other CSS modules may expand the definitions of these value types. For example, combining with CSS Images allows for using CSS gradients as 'background-image' or 'border-image' values. [[CSS-IMAGES-3]] In addition to the property-specific values listed in their definitions, all properties defined in this specification also accept the CSS-wide keywords as their property value. For readability they have not been repeated explicitly.

Borders

The [=border=] can either be a predefined style (solid line, double line, dotted line, pseudo-3D border, etc.) or it can be an image. In the former case, various properties define the style ('border-style'), color ('border-color'), and thickness ('border-width') of the border. border-image-gradient-zero-size-transform-crash.html border-image-width-interpolation-math-functions.html

Line Colors: the 'border-color' properties

	Name: border-top-color, border-right-color, border-bottom-color, border-left-color, border-block-start-color, border-block-end-color, border-inline-start-color, border-inline-end-color
	Value: <> | <>
	Initial: currentcolor
	Applies to: all elements except [=ruby base containers=] and [=ruby annotation containers=]
	Inherited: no
	Logical property group: border-color
	Percentages: N/A
	Computed Value: the computed color and/or a one-dimensional image function
	Animation type: see prose
	
These properties set the foreground color of the [=border=] specified by the 'border-style' properties. The stripes defined by <> follow the shape of the border on the side to which they apply, and are drawn in bands starting from the [=padding edge=] and progressing outwards. The border width at each point defines the |total width| of the stripes at that point.
Using multiple colors for each side:
		.foo {
			border: 30px solid;
			border-color: stripes(dodgerblue, skyblue) stripes(yellow, gold) stripes(lightgreen, limegreen) stripes(indianred, orange);
		}
		
Sample rendering: A box with a border that has four sides,
		          each side having two colors in stripes.
		          The top border is dodger blue and sky blue,
		          the right border is yellow and gold,
		          the bottom border is light green and lime green,
		          and the left border is indian red and orange. The same border colors with ''border-style: dotted'': A box with a border that has four sides,
		          each side having two colors in stripes.
		          The top border is dodger blue and sky blue,
		          the right border is yellow and gold,
		          the bottom border is light green and lime green,
		          and the left border is indian red and orange.
		          The border style is dotted, so the colors appear in dots along the border.
		Name: border-color
		Value: [ <> | <> ]{1,4}
	
'border-color' is a [=shorthand property=] for the four physical 'border-*-color' properties. The four values set the top, right, bottom and left border, respectively. A missing left is the same as right, a missing bottom is the same as top, and a missing right is also the same as top. This is resolved individually for each list item. The [=flow-relative=] properties 'border-block-start-color', 'border-block-end-color', 'border-inline-start-color', and 'border-inline-end-color' correspond to the [=physical=] properties 'border-top-color', 'border-bottom-color', 'border-left-color', and 'border-right-color'. The mapping depends on the element’s 'writing-mode', 'direction', and 'text-orientation'.
	Name: border-block-color, border-inline-color
	Value: <<'border-top-color'>>{1,2}
	
These two shorthand properties set the 'border-block-start-color' & 'border-block-end-color' and 'border-inline-start-color' & 'border-inline-end-color', respectively. The first value represents the start side color, and the second value represents the end side color. If only one value is given, it applies to both the start and end sides. animations/border-color-interpolation.html border-image-displayed-with-transparent-border-color.html color-mix-currentcolor-border-repaint-parent.html color-mix-currentcolor-border-repaint.html currentcolor-border-repaint-parent.html inheritance.sub.html parsing/border-color-computed.html parsing/border-color-invalid.html parsing/border-color-shorthand.html parsing/border-color-valid.html

Line Patterns: the 'border-style' properties

	Name: border-top-style, border-right-style, border-bottom-style, border-left-style, border-block-start-style, border-block-end-style, border-inline-start-style, border-inline-end-style
	Value: <>
	Initial: none
	Applies to: all elements except [=ruby base containers=] and [=ruby annotation containers=]
	Inherited: no
	Logical property group: border-style
	Percentages: N/A
	Computed value: specified keyword
	Animation type: discrete
	
These properties control whether a [=border=] appears, and if it does what style it's drawn in (if it is not overridden by a border image). The [=flow-relative=] properties 'border-block-start-style', 'border-block-end-style', 'border-inline-start-style', and 'border-inline-end-style' correspond to the [=physical=] properties 'border-top-style', 'border-bottom-style', 'border-left-style', and 'border-right-style'. The mapping depends on the element’s 'writing-mode', 'direction', and 'text-orientation'.
	Name: border-block-style, border-inline-style
	Value: <<'border-top-style'>>{1,2}
	
These two shorthand properties set the 'border-block-start-style' & 'border-block-end-style' and 'border-inline-start-style' & 'border-inline-end-style', respectively. The first value represents the start side style, and the second value represents the end side style. If only one value is given, it applies to both the start and end sides.
	Name: border-style
	Value: <<'border-top-style'>>{1,4}
	
'border-style' is a [=shorthand property=] for the four physical 'border-*-style' properties. The four values set the top, right, bottom and left border, respectively. A missing left is the same as right, a missing bottom is the same as top, and a missing right is also the same as top. This is resolved individually for each list item. The style is specified as a <> keyword, where
<> = none | hidden | dotted | dashed | solid | double | groove | ridge | inset | outset
Values have the following meanings:
none
No border. Color and width are ignored (i.e., the border has width 0). Note this means that the initial value of 'border-image-width' will also resolve to zero.
hidden
Same as ''border-style/none'', but has different behavior in the border conflict resolution rules for border-collapsed tables [[!CSS2]].
dotted
A series of round dots.
dashed
A series of square-ended dashes.
solid
A single line segment.
double
Two parallel solid lines with some space between them. (The thickness of the lines is not specified, but the sum of the lines and the space must equal 'border-width'.)
groove
Looks as if it were carved in the canvas. (This is typically achieved by creating a “shadow” from two colors that are slightly lighter and darker than the specified 'border-color'.)
ridge
Looks as if it were coming out of the canvas.
inset
Looks as if the content on the inside of the border is sunken into the canvas. Treated as ''border-style/ridge'' in the collapsing border model. [[!CSS2]]
outset
Looks as if the content on the inside of the border is raised out of the canvas. Treated as ''border-style/groove'' in the collapsing border model. [[!CSS2]]
Borders are drawn in front of the element’s background, but behind the element’s content (in case it overlaps).
Example renderings of the predefined border styles.
Note: Border colors close to black or white may need different color calculations than colors in between in order to create the required “3D” effect of ''border-style/groove'', ''border-style/ridge'', ''border-style/inset'', or ''border-style/outset''. Note: There is no control over the spacing of the dots and dashes, nor over the length of the dashes. Implementations are encouraged to choose a spacing that makes the corners symmetrical. inheritance.sub.html parsing/border-style-computed.html parsing/border-style-invalid.html parsing/border-style-shorthand.html parsing/border-style-valid.html

Line Thickness: the 'border-width' properties

	Name: border-top-width, border-right-width, border-bottom-width, border-left-width, border-block-start-width, border-block-end-width, border-inline-start-width, border-inline-end-width
	Value: <>
	Initial: medium
	Applies to: all elements except [=ruby base containers=] and [=ruby annotation containers=]
	Inherited: no
	Logical property group: border-width
	Percentages: N/A
	Computed value: absolute length, [=snapped as a border width=]
	Animation Type: by computed value
	
These properties specify the thickness of the [=border=], i.e. the border width. Where
<> = <> | hairline | thin | medium | thick

Negative values are invalid. The thin, medium, and thick keywords are equivalent to ''1px'', ''3px'', and ''5px'', respectively. The hairline keyword is a UA-defined length, less than or equal to ''1px'' and equal to an integer number of device pixels at the default page zoom, which represents a "just visible" line. (While it can be as large as ''1px'', on many devices it will be approximately ''0.3px'' to ''0.5px''.) The [=resolved value=] for the 'border-width' properties is the [=used value=]. If the 'border-style' corresponding to a given 'border-width' is ''border-style/none'' or ''border-style/hidden'', then the [=used value|used=] width is 0. The [=flow-relative=] properties 'border-block-start-width', 'border-block-end-width', 'border-inline-start-width', and 'border-inline-end-width' correspond to the [=physical=] properties 'border-top-width', 'border-bottom-width', 'border-left-width', and 'border-right-width'. The mapping depends on the element’s 'writing-mode', 'direction', and 'text-orientation'.

	Name: border-block-width, border-inline-width
	Value: <<'border-top-width'>>{1,2}
	
These two shorthand properties set the 'border-block-start-width' & 'border-block-end-width' and 'border-inline-start-width' & 'border-inline-end-width', respectively. The first value represents the start side width, and the second value represents the end side width. If only one value is given, it applies to both the start and end sides.
	Name: border-width
	Value: <<'border-top-width'>>{1,4}
	
'border-width' is a [=shorthand property=] for the four physical 'border-*-width' properties. The four values set the top, right, bottom and left border, respectively. A missing left is the same as right, a missing bottom is the same as top, and a missing right is also the same as top. This is resolved individually for each list item. Note: Although the [=initial value|initial=] width is ''medium'', the [=initial value|initial=] style is ''border-style/none''; therefore the [=used value|used=] initial width is 0. animations/border-bottom-width-composition.html animations/border-image-width-composition.html animations/border-image-width-interpolation.html animations/border-left-width-composition.html animations/border-right-width-composition.html animations/border-top-width-composition.html animations/border-width-interpolation.html border-bottom-width-medium.html border-bottom-width-thick.html border-bottom-width-thin.html border-left-width-medium.html border-left-width-thick.html border-left-width-thin.html border-right-width-medium.html border-right-width-thick.html border-right-width-thin.html border-top-width-medium.html border-top-width-thick.html border-top-width-thin.html border-width-cssom.html border-width-pixel-snapping-001-a.html border-width-pixel-snapping-001-b.html border-width-small-values-001-a.html border-width-small-values-001-b.html border-width-small-values-001-c.html border-width-small-values-001-d.html border-width-small-values-001-e.html inheritance.sub.html parsing/border-width-computed.html parsing/border-width-invalid.html parsing/border-width-shorthand.html parsing/border-width-valid.html borders-on-sub-unit-sized-elements.html subpixel-borders-with-child-border-box-sizing.html subpixel-borders-with-child.html

Border Shorthand Properties

	Name: border-top, border-right, border-bottom, border-left, border-block-start, border-block-end, border-inline-start, border-inline-end
	Value: <> || <> || <>
	Initial: See individual properties
	Applies to: all elements except [=ruby base containers=] and [=ruby annotation containers=]
	Inherited: no
	Percentages: N/A
	Computed value: see individual properties
	Animation Type: see individual properties
	
These [=shorthand properties=] set the 'border-width', 'border-color', and 'border-style' of one side of the [=borders=] of a box. Omitted values are set to their [=initial values=]. The [=flow-relative=] properties 'border-block-start', 'border-block-end', 'border-inline-start', and 'border-inline-end' correspond to the [=physical=] properties 'border-top', 'border-bottom', 'border-left', and 'border-right'. The mapping depends on the element’s 'writing-mode', 'direction', and 'text-orientation'.
	Name: border-block, border-inline
	Value: <<'border-block-start'>>
	
These two shorthand properties set the 'border-block-start' & 'border-block-end' or 'border-inline-start' & 'border-inline-end', respectively, both to the same style.
	Name: border
	Value: <> || <> || <>
	
parsing/border-invalid.html parsing/border-shorthand.html parsing/border-valid.html The 'border' property is a [=shorthand property=] for setting the same 'border-width', 'border-color', and 'border-style' for all four borders of a box. Unlike the shorthand 'margin' and 'padding' properties, the 'border' property cannot set different values on the four borders. To do so, one or more of the other border properties must be used. The 'border' shorthand also resets 'border-image' to its initial value. It is therefore recommended that authors use the 'border' shorthand, rather than other shorthands or the individual properties, to override any border settings earlier in the cascade. This will ensure that 'border-image' has also been reset to allow the new styles to take effect. Note: The CSS Working Group intends for the 'border' shorthand to reset all border properties in future levels of CSS as well. For example, if a border-characters property is introduced in the future to allow glyphs as borders, it will also be reset by the 'border' shorthand. By using the 'border' shorthand to reset borders, authors can be guaranteed a “blank canvas” no matter what properties are introduced in the future.
For example, the first rule below is equivalent to the set of five rules shown after it:
		p { border: solid red }
		p {
		  border-top: solid red;
		  border-right: solid red;
		  border-bottom: solid red;
		  border-left: solid red;
		  border-image: none;
		}
		
Since, to some extent, the properties have overlapping functionality, the order in which the rules are specified is important.
Consider this example:
		blockquote {
		  border-color: red;
		  border-left: double;
		  color: black
		}
		
In the above example, the color of the left border is black, while the other borders are red. This is due to 'border-left' setting the width, style, and color. Since the color value is not given by the 'border-left' property, it will be taken from the 'color' property. The fact that the 'color' property is set after the 'border-left' property is not relevant.

Corners

The [=padding edge=] (inner border) radius is the outer border radius minus the corresponding border thickness. In the case where this results in a negative value, the inner radius is zero. (In such cases the center of the border’s inner curve might not coincide with that of its outer curve.) Likewise the [=content edge=] radius is the [=padding edge=] radius minus the corresponding [=padding=], or if that is negative, zero. The border and padding thicknesses in the curved region are thus interpolated from the adjoining sides, and when two adjoining borders are of different thicknesses the corner will show a smooth transition between the thicker and thinner borders. All border styles (''border-style/solid'', ''border-style/dotted'', ''border-style/inset'', etc.) follow the curve of the border.
The effect of a rounded corner when the two borders it connects are of unequal thickness (left) and the effect of a rounded corner on borders that are thicker than the radius of the corner (right).
Note: If the center of a corner's outer curve is past an opposite [=padding edge=] (in the [=border area=] of a side opposite the corner), the inner curve will not be a full quarter ellipse.
					p { width: 70px; height: 70px; border: solid 30px;
					border-color: orange orange silver silver;
					border-top-right-radius: 100%; }
					
The curved corner is an arc from the top left corner
					          sweeping across the top right corner to the bottom right corner,
					          describing a quarter-ellipse;
					          but since the opposite sides have a border thickness
					          the padding edge curve starts inward from the outer arc's endpoints.
Where the border-radius curve extends into the opposite sides' borders, the arc of the padding edge is less than 90°.
The [=margin edge=], being outside the [=border edge=], calculates its radius by adding the corresponding margin thickness to each border radius, with the corresponding [=outset-adjusted border radius=] applied.
When expanding an [=edge=] that has a [=border radius=], e.g. for computing the [=margin edge=], 'box-shadow' spread, or 'overflow-clip-margin', the different [=border radius=] values are adjusted so that a small rounded corner with a big outset does not appear to be disproportionally round. This is done by computing the corresponding [=outset-adjusted border radius=]. To compute the outset-adjusted border radius given the 2-dimensional [=size=]'s |edge|, |radius|, and |outset|: 1. Let |coverage| be 2 * min(|radius|'s [=width=] / |edge|'s [=width=], |radius|'s [=height=] / |edge|'s [=height=]). 1. Let |adustedRadiusWidth| be the [=adjusted radius dimension=] given |coverage|, |radius|'s [=width=], and |outset|'s [=width=]. 1. Let |adustedRadiusHeight| be the [=adjusted radius dimension=] given |coverage|, |radius|'s [=height=], and |outset|'s [=height=]. 1. Return (|adustedRadiusWidth|, |adustedRadiusHeight|). To compute the adjusted radius dimension given numbers |coverage|, |radius|, and |outset|: 1. If |radius| is greater than |spread|, or if |coverage| is greater than 1, then return |radius| + |outset|. 1. Let |ratio| be |radius| / |outset|. 1. Return |radius| + |outset| * (1 - (1 - |ratio|)3 * (1 - |coverage|3)). Note: this algorithm is designed to reduce the effect of the |outset| (or spread) on the shape of the corner. The |coverage| factor makes this reduction more pronounced for rectangular shapes (where the [=border radius=] is close to 0), and less pronounced for elliptical shapes (where the [=border radius=] is close to 50%).

Corner Clipping

Although border images are not affected by 'border-radius', other effects that clip painting or event handling to the [=border edge|border=], [=padding edge|padding=], or [=content edge|content=] edge must clip to their respective curves. For example, backgrounds clip to the curve specified by 'background-clip', 'overflow' values other than ''visible'' to the curved [=padding edge=] (when 'overflow' on both axes is not ''visible''), [=replaced element=] content to the curved [=content edge=], pointer events to the curved [=border edge=], etc. Note: As 'border-radius' reduces the interactive area of an element authors should make sure the remaining interactive area conforms to recommended minima for the platforms they target; in particular, conforming to recommended minimum touch target sizes may require larger widths and heights when 'border-radius' is used.
This example adds appropriate padding, so that the contents do not overflow the corners. Note that there is no border, but the background will still have rounded corners.
		DIV {
		    background: black;
		    color: white;
		    border-radius: 1em;
		    padding: 1em }
		

Color and Style Transitions

Color and style transitions must be contained within the segment of the border that intersects the smallest rectangle that contains both border radii as well as the center of the inner curve (which may be a point representing the corner of the padding edge, if the border radii are smaller than the [=border width=]). If one of these borders is zero-width, then the other border takes up the entire transitional area. Otherwise, the center of color and style transitions between adjoining borders is a point along the curve that is a continuous monotonic function of the ratio of the border widths. However it is not defined what these transitions look like or what function maps from this ratio to a point on the curve.
Given these corner shapes, color and style transitions must be contained within the green region. In case D the rectangle defined by the border radii does not include the center of the inner curve (which is a sharp corner), so the transition region is expanded to include that corner. Transitions may take up the entire transition region, but are not required to: For example, a gradient color transition between two solid border styles might take up only the region bounded by the tips of the outer radii and the tips of the inner radii (represented in case D by the dark green region).
border-radius-currentcolor.html

Overlapping Curves

Corner curves must not overlap: When the sum of any two adjacent border radii exceeds the size of the border box, UAs must proportionally reduce the used values of all border radii until none of them overlap. The algorithm for reducing radii is as follows: Let f = min(Li/Si), where i ∈ {top, right, bottom, left}, Si is the sum of the two corresponding radii of the corners on side i, and Ltop = Lbottom = the width of the box, and Lleft = Lright = the height of the box. If f < 1, then all corner radii are reduced by multiplying them by f. Note: This formula ensures that quarter circles remain quarter circles and large radii remain larger than smaller ones, but it may reduce corners that were already small enough, which may make borders of nearby elements that should look the same look different. If the curve interferes with UI elements such as scrollbars, the UA may further reduce the used value of the affected border radii (and only the affected border radii) as much as necessary, but no more.
For example, the borders A of the figure below might be the result of
		box-sizing: border-box;
		width: 6em;
		height: 2.5em;
		border-radius: 0.5em 2em 0.5em 2em
		
The height (2.5em) is enough for the specified radii (0.5em plus 2.0em). However, if the height is only 2em,
		box-sizing: border-box;
		width: 6em;
		height: 2em;
		border-radius: 0.5em 2em 0.5em 2em
		
all corners need to be reduced by a factor 0.8 to make them fit. The used border radii thus are 0.4em (instead of 0.5em) and 1.6em (instead of 2em). See borders B in the figure.
rectangle with two tiny rounded corners and two very large ones, on opposite corners
These rounded corner might be the result of ''width: 6em; height: 2.5em; border-radius: 0.5em 2em 0.5em 2em'' for A; and ditto but with ''height: 2em'' for B.

Effect on Tables

The 'border-radius' properties do apply to ''display/table'', ''inline-table'', and ''table-cell'' boxes in separated borders mode (''border-collapse: separate''). When 'border-collapse' is ''border-collapse/collapse'', they have no effect. ttwf-reftest-borderRadius.html

Corner Sizing: the 'border-*-*-radius' properties

	Name: border-top-left-radius, border-top-right-radius, border-bottom-right-radius, border-bottom-left-radius, border-start-start-radius, border-start-end-radius, border-end-start-radius, border-end-end-radius
	Value: <>
	Initial: 0
	Applies to: all elements (but see prose)
	Inherited: no
	Logical property group: border-radius
	Percentages: Refer to corresponding dimension of the border box.
	Computed value: pair of computed <> values
	Animation Type: by computed value
	
The radius is specified as a <> value, where
	<> = <> | <>
	<> = <> [ / <> ]?
	<> = <>{1,2}
	
The two <> values of the 'border-*-radius' properties define the radii of a quarter ellipse that defines the shape of the corner of the outer [=border edge=] (see the diagram below). The first value is the horizontal radius, the second the vertical radius. If the second value is omitted it is copied from the first. If either length is zero, the corner is square, not rounded. Percentages for the horizontal radius refer to the width of the [=border box=], whereas percentages for the vertical radius refer to the height of the [=border box=]. Negative values are invalid. Note: Authors should use the slash syntax, which is preferred for new content, but the legacy syntax (two values separated by whitespace) is supported for backwards compatibility.
Diagram of the inscribed ellipse
The two values of ''border-top-left-radius: 55pt 25pt'' define the curvature of the corner.
This example draws ovals of 15em wide and 10em high:
		DIV.standout {
		    width: 13em;
		    height: 8em;
		    border: solid black 1em;
		    border-radius: 7.5em 5em }
		
The [=flow-relative=] properties 'border-start-start-radius', 'border-start-end-radius', 'border-end-start-radius', and 'border-end-end-radius' correspond to the [=physical=] properties 'border-top-left-radius', 'border-bottom-left-radius', 'border-top-right-radius', and 'border-bottom-right-radius'. The mapping depends on the element’s 'writing-mode', 'direction', and 'text-orientation', with the first start/end giving the block axis side, and the second the inline-axis side (i.e. patterned as 'border-block-inline-radius').

Corner Sizing Shorthands: the 'border-radius' and 'border-*-radius' shorthand properties

Sizing The Corners Of One Side: The 'border-top-radius', 'border-right-radius', 'border-bottom-radius', 'border-left-radius', 'border-block-start-radius', 'border-block-end-radius', 'border-inline-start-radius', 'border-inline-end-radius' shorthands

		Name: border-top-radius, border-right-radius, border-bottom-radius, border-left-radius,
			border-block-start-radius, border-block-end-radius, border-inline-start-radius, border-inline-end-radius
		Value: <>{1,2} [ / <>{1,2} ]?
		Initial: 0
		Applies to: all elements (but see prose)
		Inherited: no
		Percentages: Refer to corresponding dimension of the border box.
		Computed value: see individual properties
		Animation type: see individual properties
	

The 'border-*-radius' shorthands set the two 'border-*-*-radius' longhand properties of the related side. If values are given before and after the slash, then the values before the slash set the horizontal radius and the values after the slash set the vertical radius. If there is no slash, then the values set both radii equally. The two values for the radii are given in the order top-left, top-right for 'border-top-radius', top-right, bottom-right for 'border-right-radius', bottom-left, bottom-right for 'border-bottom-radius', top-left, bottom-left for 'border-left-radius', start-start, start-end for 'border-block-start-radius', end-start, end-end for 'border-block-end-radius' start-start, end-start for 'border-inline-start-radius', and start-end, end-end for 'border-inline-end-radius'. If the second value is omitted it is copied from the first. border-radius-greater-than-width.html tentative/border-radius-side-shorthands/border-radius-side-shorthands-001.html tentative/border-radius-side-shorthands/border-radius-side-shorthands-002.html tentative/parsing/border-block-end-radius-computed.html tentative/parsing/border-block-end-radius-invalid.html tentative/parsing/border-block-end-radius-valid.html tentative/parsing/border-block-start-radius-computed.html tentative/parsing/border-block-start-radius-invalid.html tentative/parsing/border-block-start-radius-valid.html tentative/parsing/border-bottom-radius-computed.html tentative/parsing/border-bottom-radius-invalid.html tentative/parsing/border-bottom-radius-valid.html tentative/parsing/border-inline-end-radius-computed.html tentative/parsing/border-inline-end-radius-invalid.html tentative/parsing/border-inline-end-radius-valid.html tentative/parsing/border-inline-start-radius-computed.html tentative/parsing/border-inline-start-radius-invalid.html tentative/parsing/border-inline-start-radius-valid.html tentative/parsing/border-left-radius-computed.html tentative/parsing/border-left-radius-invalid.html tentative/parsing/border-left-radius-valid.html tentative/parsing/border-right-radius-computed.html tentative/parsing/border-right-radius-invalid.html tentative/parsing/border-right-radius-valid.html tentative/parsing/border-top-radius-computed.html tentative/parsing/border-top-radius-invalid.html tentative/parsing/border-top-radius-valid.html animations/border-bottom-left-radius-composition.html animations/border-bottom-right-radius-composition.html animations/border-radius-interpolation.html animations/border-top-left-radius-composition.html animations/border-top-right-radius-composition.html border-bottom-left-radius-001.xht border-bottom-left-radius-004.xht border-bottom-left-radius-005.xht border-bottom-left-radius-010.xht border-bottom-left-radius-011.xht border-bottom-left-radius-014.xht border-bottom-right-radius-001.xht border-bottom-right-radius-004.xht border-bottom-right-radius-005.xht border-bottom-right-radius-010.xht border-bottom-right-radius-011.xht border-bottom-right-radius-014.xht border-radius-001.xht border-radius-002.xht border-radius-003.xht border-radius-004.xht border-radius-005.xht border-radius-006.xht border-radius-007.xht border-radius-008.xht border-radius-009.xht border-radius-010.xht border-radius-011.xht border-radius-012.html border-radius-013.html border-radius-clip-001.html border-radius-clip-002.htm border-radius-clipping-002.html border-radius-clipping-with-transform-001.html border-radius-css-text.html border-radius-dynamic-from-no-radius.html border-radius-horizontal-value-is-zero.html border-radius-shorthand-002.html border-top-left-radius-001.xht border-top-left-radius-004.xht border-top-left-radius-005.xht border-top-left-radius-010.xht border-top-left-radius-011.xht border-top-left-radius-014.xht border-top-right-radius-001.xht border-top-right-radius-004.xht border-top-right-radius-005.xht border-top-right-radius-010.xht border-top-right-radius-011.xht border-top-right-radius-014.xht box-shadow-border-radius-001.html css-border-radius-001.html inheritance.sub.html inner-border-non-renderable.html parsing/border-radius-computed.html parsing/border-radius-invalid.html parsing/border-radius-valid.html parsing/webkit-border-radius-valid.html

Sizing All Corners At Once: The 'border-radius' shorthand

		Name: border-radius
		Value: <>{1,4} [ / <>{1,4} ]?
	
The 'border-radius' shorthand sets all four 'border-*-radius' properties. If values are given before and after the slash, then the values before the slash set the horizontal radii and the values after the slash set the vertical radii. If there is no slash, then the values set the radii in both axes equally. The four values for each radii are given in the order top-left, top-right, bottom-right, bottom-left. If bottom-left is omitted it is the same as top-right. If bottom-right is omitted it is the same as top-left. If top-right is omitted it is the same as top-left.
		border-radius: 4em;
		
is equivalent to
		border-top-left-radius:     4em;
		border-top-right-radius:    4em;
		border-bottom-right-radius: 4em;
		border-bottom-left-radius:  4em;
		
and
		border-radius: 2em 1em 4em / 0.5em 3em;
		
is equivalent to
		border-top-left-radius:     2em 0.5em;
		border-top-right-radius:    1em 3em;
		border-bottom-right-radius: 4em 0.5em;
		border-bottom-left-radius:  1em 3em;
		

Corner Shaping: the 'corner-*-shape' properties

By default, non-zero 'border-radius' values define a quarter-ellipse corner shape that rounds the affected corners, filling the corner area defined by the 'border-radius' for that corner. However in some cases, other [=corner shapes=] are desired. The 'corner-*-shape' properties (and their shorthands) specify exactly what [=corner shapes=] a box will use for the region defined by its 'border-*-radius' values. The different [=corner shapes=] can all be expressed as different parameters to a superellipse. A superellipse is a generalization of an ellipse, and based on its `k` parameter can express all the shapes between a square, an ellipse, and a notch.
How does a superellipse work? A unit circle is defined by the equation:
x 2 + y 2 = 1
The circle is made from all points (x,y) that satisfy the equation. A given ellipse can then be produced by scaling this shape in the X and/or Y axis. The unit superellipse equation just changes the 2 exponent into a variable. For this spec's purposes, we'll write it as 2K:
x 2 K + y 2 K = 1
The |K| in this equation is the ''superellipse()'' argument. |K| can be any value; setting |K| to 1 gives the standard circle/ellipse equation, but other values define the entire family of superellipse curves: * Values larger than 1 make it more "square": the traditional "squircle" uses a |K| of 2, and a |K| of infinity is a perfect square. (A |K| of only 10 is already nearly indistinguishable from a square; it scales very quickly.) * Values between 0 and 1 make it "flatter"; when |K| is 0 it's a diamond with perfectly flat sides. * Negative values define concave curves, roughly opposite of what you get with positive values: a |K| of -1 gives a nearly elliptical "scoop" that's roughly the opposite of a |K| of 1, a |K| of -2 gives a "squircle" scoop, a |K| of negative infinity gives a square scoop, etc. (Note that most literature on superellipses will write the equation with a simpler xK exponent. The x2K form was chosen here to make the argument ranges easier to reason about: all possible values are valid, the symmetrical shapes are just positive/negative, the "middle" bevel is 0, etc.)
To allow full expression as well as interpolation, the 'corner-shape' properties can provide the superellipse parameter directly using the ''superellipse()'' function, or use one of the supplied keywords which represent commonly used parameters. See the <> definition for details. corner-shape/corner-shape-backdrop-filter.html corner-shape/corner-shape-backdrop-filter-overflow.html corner-shape/corner-shape-bevel-overflow-composite.html corner-shape/corner-shape-bevel-overflow.html corner-shape/corner-shape-computed.html corner-shape/corner-shape-fill.html corner-shape/corner-shape-hittest.html corner-shape/corner-shape-iframe-border.html corner-shape/corner-shape-img-border.html corner-shape/corner-shape-img.html corner-shape/corner-shape-inset-shadow.html corner-shape/corner-shape-invalid.html corner-shape/corner-shape-notch.html corner-shape/corner-shape-outside-left.html corner-shape/corner-shape-outside-right.html corner-shape/corner-shape-overflow-clip-margin.html corner-shape/corner-shape-square.html corner-shape/corner-shape-svg-border.html corner-shape/corner-shape-valid.html corner-shape/corner-shape-video-border.html corner-shape/corner-shape-noop-keyframe.html corner-shape/corner-shape-zoom-overlap-extreme-values-crash.html corner-shape/render-corner-shape.html
		Name: corner-top-left-shape, corner-top-right-shape, corner-bottom-right-shape, corner-bottom-left-shape, corner-start-start-shape, corner-start-end-shape, corner-end-start-shape, corner-end-end-shape
		Value: <>
		Initial: round
		Applies to: all elements where 'border-radius' can apply
		Inherited: no
		Logical property group: corner-shape
		Computed value: the corresponding ''superellipse()'' value
		Animation Type: see [=superellipse interpolation=]
	
The 'corner-*-*-shape' longhand properties set the corner shape for the given corner. The [=flow-relative=] longhands ('corner-start-start-shape', etc.) correspond to the [=physical=] longhands ('corner-top-left-shape', etc.) depending on the element’s 'writing-mode', 'direction', and 'text-orientation'. The first start/end gives the block axis side, and the second the inline-axis side (i.e. patterned as corner-block-inline-shape).
		<> = ''corner-shape/round'' | ''corner-shape/scoop'' | ''corner-shape/bevel'' | ''corner-shape/notch'' | ''corner-shape/square'' | ''corner-shape/squircle'' |
		                       <>
		superellipse() = superellipse(<> | infinity | -infinity)
	
round
The [=corner shape=] is a quarter of a convex ellipse. Equivalent to ''superellipse(1)''. Note: This is the initial value of 'corner-shape' properties, as it was the behavior of 'border-radius' before 'corner-shape' existed.
squircle
The [=corner shape=] is a quarter of a "squircle", a convex curve between ''corner-shape/round'' and ''corner-shape/square''. Equivalent to ''superellipse(2)''.
square
The [=corner shape=] is a convex 90deg angle. Equivalent to ''superellipse(infinity)''. Note: This looks identical to the "normal" square corner you get from ''border-radius: 0'', but it can smoothly animate with the other 'corner-shape' values.
bevel
The [=corner shape=] is a straight diagonal line, neither convex nor concave. Equivalent to ''superellipse(0)''.
scoop
The [=corner shape=] is a concave quarter-ellipse. Equivalent to ''superellipse(-1)''.
notch
The [=corner shape=] is a concave 90deg angle. Equivalent to ''superellipse(-infinity)''.
superellipse(K)
The [=corner shape=] is a quarter of a superellipse. The argument |K| is the superellipse parameter, and it defines a superellipse using an exponent of 2K. See the note in [[#corner-shaping]] for an explanation of the mathematical definition of a superellipse, and what various K values mean. See [[#corner-shape-rendering]] for precise details of how the superellipse is computed and rendered.
Different ''superellipse()'' values for the top right corner: infinity, 1, 0, -1, and -infinity.
Note: If 'border-radius' is not specified (or is set to 0), the [=corner area=] is zero-sized as well, and 'corner-shape' won't have any effect. 'corner-*-shape' does not alter the [=overflow=] rules for 'border-*-radius', except insofar as it shapes the corners differently; elements are still clipped by the shaped border as normal. The curve specified by 'corner-*-shape' defines the outer edge of the border. The inner edge of the border follows the curve of the outer edge (in a way that's not necessarily expressible as a superellipse curve), with a nearly consistent distance from the outer edge throughout, (or a linearly increasing distance if the 'border-width' of the two border edges meeting at the the corner are not uniform). 'corner-*-shape' also affects the rendering of 'box-shadow', and how the [=overflow clip edge=] is shaped when it's extended from the box, but these do not directly follow the 'corner-*-shape' path like the inner border edge does. Instead, it scales the 'corner-shape' path in an axis-aligned manner.

Corner Shaping Shorthands: the 'corner-shape' and 'corner-*-shape' shorthand properties

Shaping The Corners Of One Side: The 'corner-*-shape' shorthands:

	Name: corner-top-shape, corner-right-shape, corner-bottom-shape, corner-left-shape,
		corner-block-start-shape, corner-block-end-shape, corner-inline-start-shape, corner-inline-end-shape
	Value: <<'corner-top-left-shape'>>{1,2}
	
The 'corner-*-shape' shorthands set the two 'corner-*-*-shape' properties of the related side. If only one value is given, the second value defaults to the same value. For the physical shorthands ('corner-top-shape', etc.), the values are either in left/right order, or top/bottom order, whichever axis is meaningful for the property. That is, ''corner-top-shape: round square'' sets ''corner-top-left-shape: round; corner-top-right-shape: square;''. For the logical shorthands ('corner-block-start-shape', etc.), the values are always in start/end order in the other axis. That is, ''corner-block-start-shape: round square'' sets ''corner-start-start-shape: round; corner-start-end-shape: square;''.

Shaping All Corners At Once: The 'corner-shape' shorthand

		Name: corner-shape
		Value: <<'corner-top-left-shape'>>{1,4}
		Initial: round
		Applies to: all elements where 'border-radius' can apply
		Inherited: no
		Animation type: see individual properties
	
The 'corner-shape' property specifies the shape of the box's corners, within the region specified by 'border-radius'. The four values set the top, right, bottom and left shape, respectively. A missing left is the same as right, a missing bottom is the same as top, and a missing right is also the same as top.

Corner Sizing & Shaping Shorthands: the 'corner' and 'corner-*' shorthand properties

Sizing & shaping a corner: The 'corner-top-left', 'corner-top-right', 'corner-bottom-right', 'corner-bottom-left', 'corner-start-start', 'corner-start-end', 'corner-end-start', 'corner-end-end' shorthands

		Name: corner-top-left, corner-top-right, corner-bottom-left, corner-bottom-right,
			corner-start-start, corner-start-end, corner-end-start, corner-end-end
		Value: <<'border-top-left-radius'>> || <<'corner-top-left-shape'>>
		Initial: 0
		Applies to: all elements (but see prose)
		Inherited: no
		Percentages: Refer to corresponding dimension of the border box.
		Computed value: see individual properties
		Animation type: see individual properties
	
The 'corner-*-*' shorthands set the two 'corner-*-*-shape' and 'border-*-*-radius' longhand properties of the related side. See the corresponding 'corner-*-*-shape' and 'border-*-*-radius' properties for further details.

Sizing & shaping rhe Corners Of One Side: The 'corner-top', 'corner-right', 'corner-bottom', 'corner-left', 'corner-block-start', 'corner-block-end', 'corner-inline-start', 'corner-inline-end' shorthands

		Name: corner-top, corner-right, corner-bottom, corner-left,
			corner-block-start, corner-block-end, corner-inline-start, corner-inline-end
		Value: <<'border-top-radius'>> || <<'corner-top-shape'>>
		Initial: 0
		Applies to: all elements (but see prose)
		Inherited: no
		Percentages: Refer to corresponding dimension of the border box.
		Computed value: see individual properties
		Animation type: see individual properties
	
The 'corner-*' shorthands set the two 'corner-*-shape' longhand properties and two 'border-*-radius' longhand properties of the related side. See the corresponding 'corner-*-shape' and 'border-*-radius' properties for further details.

Sizing & Shaping All Corners At Once: The 'corner' shorthand

		Name: corner
		Value: <<'border-radius'>> || <<'corner-shape'>>
		Initial: 0
		Applies to: all elements (but see prose)
		Inherited: no
		Percentages: Refer to corresponding dimension of the border box.
		Computed value: see individual properties
		Animation type: see individual properties
	
The 'corner' shorthand sets the 'corner-*-shape' and 'border-*-radius' longhands all together.

Rendering 'corner-shape'

When rendering elements with shaped corners, the element's [=border contour path=] needs to be offset, based on [=border=], [=outline=], 'box-shadow', 'overflow-clip-margin' and more. When rendering borders or outlines, the offset is aligned to the curve of the element's shape. When rendering 'box-shadow' or offsetting for 'overflow-clip-margin', the offset is also aligned to the same curve in the other direction, and the curve continues to the outer edge. An [=/element=] |element|'s outer contour is the [=border contour path=] given |element| and |element|'s [=border edge=]. An [=/element=] |element|'s inner contour is the [=border contour path=] given |element| and |element|'s [=border width=]. An [=/element=]'s [=border=] is rendered in the area between its [=outer contour=] and its [=inner contour=]. An [=/element=]'s [=outline=] follows the [=outer contour=] with the [=used value|used=] 'outline-width' and 'outline-offset'. The precise way in which it is rendered is implementation-defined. An [=/element=]'s [=overflow=] area is shaped by its [=inner contour=]. An [=/element=]'s [=overflow clip edge=] is shaped by the [=border contour path=] given |element|, and an [=uniform inset from an outset=] given |element|'s [=used value|used=] 'overflow-clip-margin'. Each shadow of [=/element=]'s 'box-shadow' is shaped by the [=border contour path=] given |element|, and an [=uniform inset from an outset=] given the shadow's [=used value|used=] 'box-shadow-spread'. An uniform inset from an outset given a number |outset| is an [=edge=] whose value is -|outset| in all directions.
Vector Math Helpers
A two-dimensional vector is a pair of numbers (x, y).
A point extended by vectors given a {{DOMPointReadOnly}} |p| and a [=/list=] of [=two-dimensional vector=]s |vectors|: 1. Let |x| be |p|'s {{DOMPointReadOnly/x}}. 1. Let |y| be |p|'s {{DOMPointReadOnly/y}}. 1. [=list/For each=] |v| in |vectors|: 1. Increment |x| by |v|[0]; 1. Increment |y| by |v|[1]; 1. Return a new {{DOMPointReadOnly}} whose {{DOMPointReadOnly/x}} is |x| and whose {{DOMPointReadOnly/y}} is |y|.
To scale a [=two-dimensional vector=] |v| by a number |factor|, return (|v|[0] ⋅ |factor|, |v|[1] ⋅ |factor|).
To normalize a [=two-dimensional vector=] |v|: 1. Let |l| be hypot(|v|[0], |v|[1]). 1. If |l| is 0, return |v|. 1. Return (|v|[0] / |l|, |v|[1] / |l|).
The perpendicular of a [=two-dimensional vector=] |v| is (-|v|[1], |v|[0]). The vector between two points, given {{DOMPoint}}s |a| and |b|, is (|b|'s {{DOMPointReadOnly/x}} - |a|'s {{DOMPointReadOnly/x}}, |b|'s {{DOMPointReadOnly/y}} - |a|'s {{DOMPointReadOnly/y}}).
Computing a contoured path
This algorithm describes how to compute a path with shaped corners (a path that is either inset or outset from the original). To avoid the complexities of defining how superellipses intersect, the algorithm simplifies the process by specifying that each corner is "clipped out" of the path. The specific implementation details of this clipping operation are left to implementations.
To compute an [=/element=] |element|'s border contour path given numbers |topInset|, |rightInset|, |bottomInset|, |leftInset|: 1. Let |borderRect| be |element|'s [=border box=]. 1. Let |unshapedTargetRect| be |borderRect|, inset by |topInset|, |rightInset|, |bottomInset|, |leftInset|. Note: If this is a shadow or 'overflow-clip-margin', the insets would have negative values and |unshapedTargetRect| would become an outset of |borderRect|. 1. Let |path| be a path that contains |unshapedTargetRect|. 1. Let |scaleFactor| be the [=opposite corner scale factor=] given |element|. 1. Let |adjustedRadius| be the following steps given a property |P|, and numbers |insetX| and |insetY|: 1. Let |radius| be |element|'s [=used value=] of |P|. 1. If |insetX| and |insetY| are zero, return |radius|. 1. If |insetX| or |insetY| are positive, then return (|radius|'s [=width=] ⋅ |scaleFactor|, |radius|'s [=height=] ⋅ |scaleFactor|). 1. Let |adjustedRadiusInOutsetCoordinates| be the [=outset-adjusted border radius=] given |borderRect|'s size, |radius|, and (-|insetX|, -|insetY|). 1. Return (|adjustedRadiusInOutsetCoordinates|'s [=width=] - |insetX|, |adjustedRadiusInOutsetCoordinates|'s [=height=] - |insetY|). 1. Let |adjustedTopRightRadius| be the |adjustedRadius| given 'border-top-right-radius', |insetRight|, and |insetTop|. 1. Let |adjustedBottomRightRadius| be the |adjustedRadius| given 'border-bottom-right-radius', |insetRight|, and |insetBottom|. 1. Let |adjustedBottomLeftRadius| be the |adjustedRadius| given 'border-bottom-left-radius', |insetLeft|, and |insetBottom|. 1. Let |adjustedTopLeftRadius| be the |adjustedRadius| given 'border-top-left-radius', |insetLeft|, and |insetTop|. 1. Clip out from |path|, the [=border-aligned corner clip-out path=] given |borderRect|'s right, |borderRect|'s top, (-|adjustedTopRightRadius|[0], 0), (0, |adjustedTopRightRadius|[1]), |element|'s [=computed value|computed=] 'corner-top-right-shape', |topInset|, and |rightInset|. 1. Clip out from |path|, the [=border-aligned corner clip-out path=] given |borderRect|'s right, |borderRect|'s bottom, (0, -|adjustedBottomRightRadius|[1]), (-|adjustedBottomRightRadius|[0], 0), |element|'s [=computed value|computed=] 'corner-bottom-right-shape', |rightInset|, and |bottomInset|. 1. Clip out from |path|, the [=border-aligned corner clip-out path=] given |borderRect|'s left, |borderRect|'s bottom, (|adjustedBottomLeftRadius|[0], 0), (0, -|adjustedBottomLeftRadius|[1]), |element|'s [=computed value|computed=] 'corner-bottom-left-shape', |bottomInset|, and |leftInset|. 1. Clip out from |path|, the [=border-aligned corner clip-out path=] given |borderRect|'s left, |borderRect|'s top, (0, |adjustedTopLeftRadius|[1]), (|adjustedTopLeftRadius|[0], 0), |element|'s [=computed value|computed=] 'corner-top-left-shape', |leftInset|, and |topInset|. 1. Return |path|. To get the border-aligned corner clip-out path given a {{DOMPointReadOnly}} |originalCornerOuter|, a [=two-dimensional vector=] |vectorTowardsStart|, a [=two-dimensional vector=] |vectorTowardsEnd|, a [=superellipse parameter=] |curvature|, and numbers |startInset| and |endInset|: 1. If |curvature| is ∞, then return an empty path. 1. Let |clampedHalfCorner| be the [=normalized superellipse half corner=] given clamp(|curvature|, -1, 1). 1. Let |originalCornerStart| be |originalCornerOuter|, [=point extended by vectors|extended by=] « |vectorTowardsStart| ». 1. Let |originalCornerEnd| be |originalCornerOuter|, [=point extended by vectors|extended by=] « |vectorTowardsEnd| ». 1. Let |originalCornerCenter| be |originalCornerOuter|, [=point extended by vectors|extended by=] « |vectorTowardsStart|, |vectorTowardsEnd| ». 1. Let |extendStart| be a [=vector between two points|vector between=] |originalCornerStart| and |originalCornerCenter|, [=two-dimensional vector/normalize|normalized=] and [=two-dimensional vector/scale|scaled by=] |startInset|. 1. Let |extendEnd| be a [=vector between two points|vector between=] |originalCornerEnd| and |originalCornerCenter|, [=two-dimensional vector/normalize|normalized=] and [=two-dimensional vector/scale|scaled by=] |endInset|. 1. Let |clipStart| be |originalCornerStart|, [=point extended by vectors|extended by=] « |extendStart| ». 1. Let |clipEnd| be |originalCornerEnd|, [=point extended by vectors|extended by=] « |extendEnd| ». 1. Let |clipOuter| be |originalCornerOuter|, [=point extended by vectors|extended by=] « |extendStart|, |extendEnd| ». 1. Let |vectorFromStartToControlPoint| be the the [=two-dimensional vector=] (2 ⋅ |clampedHalfCorner| - 0.5, 1.5 - 2 ⋅ |clampedHalfCorner|). 1. Let |singlePixelVectorFromStartToControlPoint| be the |vectorFromStartToControlPoint|, [=two-dimensional vector/normalize|normalized=]. 1. Let |strokeA|, |strokeB| be the [=two-dimensional vector/perpendicular=] of |singlePixelVectorFromStartToControlPoint|. 1. Let |offset1| be [=vector between two points|the vector between=] |originalCornerStart| and |outerCorner|, [=two-dimensional vector/normalize|normalized=] and [=two-dimensional vector/scale|scaled by=] |startInset| ⋅ |strokeA|. 1. Let |offset2| be [=vector between two points|the vector between=] |outerCorner| and |originalCornerEnd|, [=two-dimensional vector/normalize|normalized=] and [=two-dimensional vector/scale|scaled by=] |startInset| ⋅ |strokeB|. 1. Let |offset3| be [=vector between two points|the vector between=] |originalCornerEnd| and |originalCornerCenter|, [=two-dimensional vector/normalize|normalized=] and [=two-dimensional vector/scale|scaled by=] |endInset| ⋅ |strokeB|. 1. Let |offset4| be [=vector between two points|the vector between=] |originalCornerCenter| and |originalCornerStart|, [=two-dimensional vector/normalize|normalized=] and [=two-dimensional vector/scale|scaled by=] |endInset| ⋅ |strokeA|. 1. Let |adjustedCornerStart| be |originalCornerStart|, [=point extended by vectors|extended by=] « |offset1|, |offset2| ». 1. Let |adjustedCornerEnd| be |originalCornerEnd|, [=point extended by vectors|extended by=] « |offset3|, |offset4| ». 1. Let |adjustedCornerCenter| be |originalCornerCenter|, [=point extended by vectors|extended by=] « |offset4|, |offset1| ». 1. Let |adjustedCornerOuter| be |originalCornerOuter|, [=point extended by vectors|extended by=] « |offset2|, |offset3| ». 1. Let |curveCenter| be |adjustedCornerOuter| if |curvature| is less than 0, |adjustedCornerCenter| otherwise. 1. Let |mapPointToCorner| be the following steps: given numbers |x| and |y|: 1. Let |v1| be [=vector between two points|the vector between=] |curveCenter| and |adjustedCornerEnd|, [=two-dimensional vector/scale|scaled by=] |x|. 1. Let |v2| be [=vector between two points|the vector between=] |curveCenter| and |adjustedCornerStart|, [=two-dimensional vector/scale|scaled by=] |y|. 1. Return the {{DOMPointReadOnly}} at (|x|, |y|), [=point extended by vectors|extended by=] « |v1|, |v2| ». 1. Let |controlPoint| be the result of calling |mapPointToCorner| given |vectorFromStartToControlPoint|'s {{DOMPointReadOnly/y}} and 1 - |unitVectorFromStartToControlPoint|'s {{DOMPointReadOnly/x}}. 1. Let |axisAlignedCornerStart| be the intersection between the lines (|adjustedCornerStart|, |controlPoint|) and (|clipStart|, |clipOuter|). If the lines are parallel, let it be adjustedCornerStart. 1. Let |axisAlignedCornerEnd| be the intersection between the lines (|adjustedCornerEnd|, |controlPoint|) and (|clipEnd|, |clipOuter|). If the lines are parallel, let it be adjustedCornerEnd. Note: |axisAlignedCornerStart| and |axisAlignedCornerEnd| act as "miters" when rendering an outset. They are a straight extension of the curve's tangent, intersecting with the unshaped target rect. 1. Let |path| be a path, starting at |axisAlignedCornerStart|. 1. If |curvature| is -∞: 1. Extend |path| to |adjustedCornerStart|. 1. Extend |path| to |adjustedCornerCenter|. 1. Extend |path| to |adjustedCornerEnd|. 1. Otherwise: 1. Let |K| be 0.5-abs(|curvature|). 1. For every |T| between 0 and 1, in an [=implementation-approximated=] manner, extend |path| to the result of calling |mapPointToCorner| given |T||K| and (1 - |T|)|K|. 1. Extend |path| to |axisAlignedCornerEnd|. 1. Extend |path| to |clipOuter|. 1. Return |path|.
corner-shape/corners-computed.html corner-shape/corners-invalid.html corner-shape/corners-valid.html

Constraining opposite radii

When concave 'corner-shape' values are present (the [=superellipse parameter=] is negative), diagonally opposite corners might overlap each other.

The following example would create overlapping corners if not constrained.

		div {
			corner-shape: scoop;
			border-top-left-radius: 80%;
			border-bottom-right-radius: 80%;
		}
	
To prevent this, the four radii are constrained to prevent overlaps. This is done by computing a hull polygon for each of the opposite corners, and finding the highest downscale factor which, if applied to both corners, would make it so that the polygons would not intersect.
To compute the opposite corner scale factor given an [=/element=] |element|: 1. Let |rect| be |element|'s [=border box=]. 1. Let |topRightHull| be a the [=normalized inner corner hull=] given |element|'s [=computed value|computed=] 'corner-top-right-shape', mapped to the rectangle (|rect|'s [=width dimension=] - |element|'s [=computed value|computed=] horizontal 'border-top-right-radius', 0, |rect|'s [=computed value|computed=] 'border-top-right-radius'). 1. Let |bottomRightHull| be a the [=normalized inner corner hull=] given |element|'s [=computed value|computed=] 'corner-bottom-right-shape', rotated by 90deg with (0.5, 0.5) as an origin, and mapped to the rectangle (|rect|'s [=width dimension=] - |element|'s [=computed value|computed=] horizontal 'border-bottom-right-radius', |rect|'s [=height dimension=] - |element|'s [=computed value|computed=] vertical 'border-bottom-right-radius', |element|'s [=computed value|computed=] 'border-bottom-right-radius'). 1. Let |bottomLeftHull| be a the [=normalized inner corner hull=] given |element|'s [=computed value|computed=] 'corner-bottom-right-shape', rotated by 180deg with (0.5, 0.5) as an origin, and mapped to the rectangle (0, |rect|'s [=height dimension=] - |element|'s [=computed value|computed=] vertical 'border-bottom-left-radius', |element|'s [=computed value|computed=] 'border-bottom-left-radius'). 1. Let |topLeftHull| be a the [=normalized inner corner hull=] given |element|'s [=computed value|computed=] 'corner-top-left-shape', rotated by 270deg with (0.5, 0.5) as an origin, mapped to (0, 0, |element|'s [=computed value|computed=] 'border-top-left-radius'). 1. Let |scaleFactorA| be the highest number which, if both |topLeftHull| and |bottomRightHull| were scaled by, using their first point as the origin, those polygons would not intersect. 1. Let |scaleFactorB| be the highest number which, if both |topRightHull| and |bottomLeftHull| were scaled by, using their first point as the origin, those polygons would not intersect. 1. Return min(1, |scaleFactorA|, |scaleFactorB|).

Interpolating corner shapes

Since a <> can always be expressed by a ''superellipse()'' with an [=superellipse parameter=] variable, interpolating between two <>s is done by interpolating the [=superellipse parameter=] itself. Since it uses a log2, interpolating it linearly would result in an effect where concave corners interpolate at a much higher velocity than convex corners. To balance that, the superellipse interpolation formula describes how a [=superellipse parameter=] is converted to a value between 0 and 1, and vice versa:
To compute the normalized superellipse half corner given a [=superellipse parameter=] |s|, return the first matching statement, switching on |s|:
: -∞ :: Return 0. : ∞ :: Return 1. : Otherwise :: 1. Let |k| be 0.5abs(|s|). 1. Let |convexHalfCorner| be 0.51/|k|. 1. If |s| is less than 0, return 1 - |convexHalfCorner|. 1. Return |convexHalfCorner|.
To compute the normalized inner corner hull given a [=superellipse parameter=] |curvature|: 1. If |curvature| is greater than or equal to zero, return a triangle betwen « (1, 1), (1, 0), (0, 1) ». 1. Let |axisLineA| be a line between (1, 0) and (1, 1). 1. Let |axisLineB| be a line between (0, 1) and (1, 1). 1. Let |normalizedHalfCorner| be the [=normalized superellipse half corner=] given |curvature|. 1. Let |halfCornerPoint| be (|normalizedHalfCorner|, 1 - |normalizedHalfCorner|). 1. Let |lineFromCenterToHalfCorner| be a line between (0, 0) and |halfCornerPoint|. 1. Let |tangentLine| be the line perpendicular to |lineFromCenterToHalfCorner|, at |halfCornerPoint|. 1. Let |intersectionA| be the intersection between |axisLineA| and |tangentLine|. 1. Let |intersectionB| be the intersection between |axisLineB| and |tangentLine|. 1. Return a pentagon between the points « (1, 1), (1, 0), |intersectionA|, |intersectionB|, (0, 1), (1, 1) ».
To interpolate a [=superellipse parameter=] |s| to an interpolation value between 0 and 1, return the [=normalized superellipse half corner=] given |s|.
To convert a <> |interpolationValue| back to a [=superellipse parameter=], switch on |interpolationValue|:
: 0 :: Return -∞. : 0.5 :: Return 0. : 1 :: Return ∞. : Otherwise :: 1. Let |convexHalfCorner| be |interpolationValue|. 1. If |interpolationValue| is less than 0.5, set |convexHalfCorner| to 1 - |interpolationValue|. 1. Let |k| be ln(0.5) / ln(|convexHalfCorner|). 1. Let |s| be log2(|k|). 1. If |interpolationValue| is less than 0.5, return -|s|. 1. Return |s|.
corner-shape/corner-shape-interpolation.html

Border Images

Authors can specify an image to be used in place of the border styles. In this case, the border's design is taken from the sides and corners of an image specified with 'border-image-source', whose pieces may be sliced, scaled, and stretched in various ways to fit the size of the [=border image area=]. The border-image properties do not affect layout: layout of the box, its content, and surrounding content is based on the 'border-width' and 'border-style' properties only.
This example creates a top and bottom border consisting of a whole number of orange diamonds and a left and right border of a single, stretched diamond. The corners are diamonds of a different color. The image to tile is as follows. Apart from the diamonds, it is transparent: Tile for border The image is 81 by 81 pixels and has to be divided into 9 equal parts. The style rules could thus be as follows:
		DIV {
		  border: double orange 1em;
		  border-image: url("border.png") 27 round stretch;
		 }
		
The result, when applied to a DIV of 12 by 5em, will be similar to this: Element with a diamond border
This shows a more complicated example, demonstrating how the border image corresponds to the fallback border-style but can also extend beyond the border area. The border image is a wavy green border with an extended corner effect:
Diagram: The border image shows a wavy green border
			          with more exaggerated waves towards the corners,
			          which are capped by a disconnected green circle.
			          Four cuts at 124px offsets from each side
			          divide the image into 124px-wide square corners,
			          124px-wide but thin side slices,
			          and a small center square.
The 'border-image-source' image, with the four 'border-image-slice' cuts at 124px dividing the image into nine parts.
The rest of the border properties then interact to lay out the tiles as follows:
Diagram: The image-less (fallback) rendering
			          has a green double border.
			          The rendering with border-image shows the wavy green border,
			          ith the waves getting longer as they reach the corners.
			          The corner tiles render as 124px-wide squares
			          and the side tiles repeat a whole number of times
			          to fill the space in between.
			          Because of the gradual corner effects,
			          the tiles extend deep into the padding area.
			          The whole border image effect is outset 31px,
			          so that the troughs of the waves align
			          just outside the padding edge.
Diagram of all border-image properties and how they interact, and showing the rendering with and without the border-image in effect.
Here, even though the 'border-width' is 12px, the 'border-image-width' property computes to 124px. The [=border image area=] is then outset 31px from the [=border box=] and into the [=margin area=]. If the border-image fails to load (or if border images are not supported by the UA), the fallback rendering uses a green double border.
Notice that the 'border' shorthand resets 'border-image'. This makes it easy to turn off or reset all border effects:
		.notebox {
		  border: double orange;
		  /* must set 'border' shorthand first, otherwise it erases 'border-image' */
		  border-image: url("border.png") 30 round;
		  /* but other 'border' properties can be set after */
		  border-width: thin thick;
		}
		...
		.sidebar .notebox {
		  box-shadow: 0 0 5px gray;
		  border-radius: 5px;
		  border: none; /* turn off all borders */
		  /* 'border' shorthand resets 'border-image' */
		}
		

Image Source: the 'border-image-source' property

	Name: border-image-source
	Value: none | <>
	Initial: none
	Applies to: All elements, except internal table elements when 'border-collapse' is ''border-collapse/collapse''
	Inherited: no
	Percentages: N/A
	Computed value: the keyword ''border-image-source/none'' or the computed <>
	Animation type: discrete
	
animations/border-image-source-interpolation.html css3-border-image-source.html parsing/border-image-source-computed.sub.html parsing/border-image-source-invalid.html parsing/border-image-source-valid.html Specifies an image to use as a border in place of the rendering specified by the 'border-style' properties and, if given the ''fill'' keyword in 'border-image-slice', as an additional image backdrop for the element. If the value is ''border-image-source/none'' or if the image cannot be displayed (or the property doesn't apply), the border styles will be used; otherwise the element's 'border-style' borders are not drawn and this border image is drawn as described in the sections below.

Image Slicing: the 'border-image-slice' property

	Name: border-image-slice
	Value: [<> | <>]{1,4} && fill?
	Initial: 100%
	Applies to: All elements, except internal table elements when 'border-collapse' is ''border-collapse/collapse''
	Inherited: no
	Percentages: refer to size of the border image
	Computed value: four values, each either a number or percentage; plus a ''fill'' keyword if specified
	Animation type: by computed value
	
animations/border-image-slice-composition.html animations/border-image-slice-interpolation-stability.html animations/border-image-slice-interpolation.html border-image-slice-001.xht border-image-slice-002.xht border-image-slice-003.xht border-image-slice-004.htm border-image-slice-005.htm border-image-slice-006.htm border-image-slice-007.htm border-image-slice-fill-001.html border-image-slice-fill-002.html border-image-slice-fill-003.html border-image-slice-percentage.html border-image-slice-shorthand-reset.html parsing/border-image-slice-computed.html parsing/border-image-slice-invalid.html parsing/border-image-slice-valid.html This property specifies inward offsets from the top, right, bottom, and left edges of the image, dividing it into nine regions: four corners, four edges and a middle. The middle image part is discarded (treated as fully transparent) unless the ''fill'' keyword is present. (It is drawn over the background; see Drawing the Border Image.) If there is only one component value, it applies to all sides. If there are two values, the top and bottom are set to the first value and the right and left are set to the second. If there are three values, the top is set to the first value, the left and right are set to the second, and the bottom is set to the third. If there are four values they apply to the top, right, bottom, and left, respectively.
<>
Percentages are relative to the size of the image: the width of the image for the horizontal offsets, the height for vertical offsets.
<>
Numbers represent pixels in the image (if the image is a raster image) or vector coordinates (if the image is a vector image).
fill
The ''fill'' keyword, if present, causes the middle part of the border-image to be preserved. (By default it is discarded, i.e., treated as empty.)
Negative values are invalid. Computed values larger than the size of the image are interpreted as ''100%''. The regions given by the 'border-image-slice' values may overlap. However if the sum of the right and left widths is equal to or greater than the width of the image, the images for the top and bottom edge and the middle part are empty-- which has the same effect as if a nonempty transparent image had been specified for those parts. Analogously for the top and bottom values. If the image must be sized to determine the slices (for example, for SVG images with no [=natural dimensions=]), then it is sized using the default sizing algorithm with no [=specified size=] and the [=border image area=] as the [=default object size=].
Diagram: two horizontal cuts and two vertical cuts through an image
Diagram illustrating the cuts corresponding to the value ''25% 30% 12% 20%''

Drawing Areas: the 'border-image-width' property

	Name: border-image-width
	Value: [ <> | <> | auto ]{1,4}
	Initial: 1
	Applies to: All elements,
		except internal table elements when 'border-collapse' is ''border-collapse/collapse''
	Inherited: no
	Percentages: Relative to width/height of the [=border image area=]
	Computed value: four values,
		each either a number,
		the keyword ''border-image-width/auto'',
		or a computed <> value
	Animation type: by computed value
	
border-image-width-001.htm border-image-width-005.xht border-image-width-006.xht border-image-width-007.xht border-image-width-008.html border-image-width-009.html border-image-width-should-extend-to-padding.html parsing/border-image-width-computed.html parsing/border-image-width-invalid.html parsing/border-image-width-valid.html The [=border image=] is drawn inside an area called the border image area. This is an area whose boundaries by default correspond to the [=border box=], see 'border-image-outset'. The four values of 'border-image-width' specify offsets that are used to divide the [=border image area=] into nine regions. The offsets represent inward distances from the top, right, bottom, and left sides of the area, respectively. If there is only one component value, it applies to all sides. If there are two values, the top and bottom are set to the first value and the right and left are set to the second. If there are three values, the top is set to the first value, the left and right are set to the second, and the bottom is set to the third. If there are four values they apply to the top, right, bottom, and left, respectively. Values have the following meanings:
<>
Percentages refer to the size of the [=border image area=]: the width of the area for horizontal offsets, the height for vertical offsets.
<>
Numbers represent multiples of the corresponding computed border-width.
auto
If ''border-image-width/auto'' is specified then the used 'border-image-width' is the [=natural size|natural=] width or height (whichever is applicable) of the corresponding image slice (see 'border-image-slice'). If the image does not have the required [=natural dimension=] then the corresponding computed 'border-width' is used instead.
Negative values are invalid for any 'border-image-width' values. If two opposite 'border-image-width' offsets are large enough that they overlap, then the [=used values=] of all 'border-image-width' offsets are proportionally reduced until they no longer overlap. In mathematical notation: Given Lwidth as the width of the [=border image area=], Lheight as its height, and Wside as the 'border-image-width' offset for the side side, let f = min(Lwidth/(Wleft+Wright), Lheight/(Wtop+Wbottom)). If f < 1, then all W are reduced by multiplying them by f.

Edge Overhang: the 'border-image-outset' property

	Name: border-image-outset
	Value: [ <> | <> ]{1,4}
	Initial: 0
	Applies to: All elements, except internal table elements when 'border-collapse' is ''border-collapse/collapse''
	Inherited: no
	Percentages: N/A
	Computed value: four values, each a number or absolute length
	Animation type: by computed value
	
animations/border-image-outset-composition.html animations/border-image-outset-interpolation.html border-image-outset-003.html parsing/border-image-outset-computed.html parsing/border-image-outset-invalid.html parsing/border-image-outset-valid.html The values specify the amount by which the [=border image area=] extends beyond the [=border box=]. If there is only one component value, it applies to all sides. If there are two values, the top and bottom are set to the first value and the right and left are set to the second. If there are three values, the top is set to the first value, the left and right are set to the second, and the bottom is set to the third. If there are four values they apply to the top, right, bottom, and left, respectively.
<>
Represents an outset of the specified length.
<>
Represents an outset of the specified multiple of the corresponding computed border-width.
Negative values are invalid. Portions of the border-image that are rendered outside the [=border box=] are [=ink overflow=] and do not trigger scrolling. Also such portions are invisible to mouse events and do not capture such events on behalf of the element. Note: Even though they never cause a scrolling mechanism, outset images may still be clipped by an ancestor or by the viewport.

Image Tiling: the 'border-image-repeat' property

	Name: border-image-repeat
	Value: [ stretch | repeat | round | space ]{1,2}
	Initial: stretch
	Applies to: All elements, except internal table elements when 'border-collapse' is ''border-collapse/collapse''
	Inherited: no
	Percentages: N/A
	Computed value: two keywords, one per axis
	Animation type: discrete
	
animations/discrete-no-interpolation.html border-image-repeat-002.htm border-image-repeat-004.htm border-image-repeat-005.html border-image-repeat-1.html border-image-repeat-repeat-001.html border-image-repeat-round-003.html border-image-repeat-round-1.html border-image-repeat-round-2.html border-image-repeat-round-stretch-001.html border-image-repeat-round.html border-image-repeat-space-011.html border-image-repeat-space-1.html border-image-repeat-space-10.html border-image-repeat-space-2.html border-image-repeat-space-3.html border-image-repeat-space-4-ref-1.html border-image-repeat-space-4.html border-image-repeat-space-5-ref-1.html border-image-repeat-space-5.html border-image-repeat-space-6.html border-image-repeat-space-7.html border-image-repeat-space-8.html border-image-repeat-space-9.html border-image-repeat-stretch-round-001.html border-image-repeat_repeatnegx_none_50px.html css3-border-image-repeat-repeat.html css3-border-image-repeat-stretch.html parsing/border-image-repeat-computed.html parsing/border-image-repeat-invalid.html parsing/border-image-repeat-valid.html This property specifies how the images for the sides and the middle part of the [=border image=] are scaled and tiled. The first keyword applies to the horizontal scaling and tiling of the top, middle and bottom parts, the second to the vertical scaling and tiling of the left, middle and right parts; see Drawing the Border Image. If the second keyword is absent, it is assumed to be the same as the first. Values have the following meanings:
stretch
The image is stretched to fill its corresponding [=region=].
repeat
The image is tiled (repeated) to fill its corresponding [=region=].
round
The image is tiled (repeated) to fill its corresponding [=region=]. If it does not fill the area with a whole number of tiles, the image is rescaled so that it does.
space
The image is tiled (repeated) to fill its corresponding [=region=]. If it does not fill the region with a whole number of tiles, the extra space is distributed around the tiles.
The exact process for scaling and tiling the border-image parts is given in the section below.

Drawing the Border Image

After the [=border image=] given by 'border-image-source' is sliced by the 'border-image-slice' values, the resulting nine images are scaled, positioned, and tiled into their corresponding [=border image regions=] in four steps:
  1. Scale to 'border-image-width'.
    • The two images for the top and bottom edges are made as tall as the top and bottom [=border image regions=], respectively, and their width is scaled proportionally.
    • The images for the left and right edges are made as wide as the left and right [=border image regions=], respectively, and their height is scaled proportionally.
    • The corner images are scaled to be as wide and as tall as the their respective [=border image regions=].
    • The middle image's width is scaled by the same factor as the top image unless that factor is zero or infinity, in which case the scaling factor of the bottom is substituted, and failing that, the width is not scaled. The height of the middle image is scaled by the same factor as the left image unless that factor is zero or infinity, in which case the scaling factor of the right image is substituted, and failing that, the height is not scaled.
  2. Scale to 'border-image-repeat'.
    • If the first keyword is ''border-image-repeat/stretch'', the top, middle and bottom images are further scaled to be as wide as the middle region of the [=border image area=]. The height is not changed any further.
    • If the first keyword is ''border-image-repeat/round'', the top, middle and bottom images are resized in width, so that exactly a whole number of them fit in the middle region of the [=border image area=], exactly as for ''background-repeat/round'' in the 'background-repeat' property.
    • If the first keyword is ''border-image-repeat/repeat'' or ''border-image-repeat/space'', the top, middle, and bottom images are not changed any further.
    • The effects of ''border-image-repeat/stretch'', ''border-image-repeat/round'', ''border-image-repeat/repeat'', and ''border-image-repeat/space'' for the second keyword are analogous, acting on the height of the left, middle and right images.
  3. Position the first tile.
    • If the first keyword is ''border-image-repeat/repeat'', the top, middle, and bottom images are centered horizontally in their respective regions. Otherwise the images are placed at the left edge of their respective regions of the [=border image area=].
    • If the second keyword is ''border-image-repeat/repeat'', the left, middle, and right images are centered vertically in their respective regions. Otherwise the images are placed at the top edge of their respective regions of the [=border image area=].
  4. Tile and draw.
    • The images are then tiled to fill their respective regions.
    • In the case of ''border-image-repeat/space'', any partial tiles are discarded and the extra space distributed before, after, and between the tiles. (I.e. the gap before the first tile, the gap after the last tile, and the gaps between tiles are equalized.) This can result in empty border-image side regions.
    • The images are drawn at the same stacking level as normal borders: immediately in front of the background layers.
    • The middle image is not drawn unless ''fill'' was specified for 'border-image-source'.

Border Image Shorthand: the 'border-image' property

	Name: border-image
	Value: <<'border-image-source'>> || <<'border-image-slice'>> [ / <<'border-image-width'>> | / <<'border-image-width'>>? / <<'border-image-outset'>> ]? || <<'border-image-repeat'>>
	Initial: See individual properties
	Applies to: See individual properties
	Inherited: no
	Percentages: N/A
	Computed value: See individual properties
	Animation Type: See individual properties
	
border-image-002.html border-image-003.html border-image-004.html border-image-006.html border-image-007.html border-image-011.html border-image-012.html border-image-013.html border-image-017.xht border-image-018.xht border-image-019.xht border-image-020.xht border-image-calc.html border-image-image-type-001.htm border-image-image-type-002.htm border-image-image-type-003.htm border-image-image-type-004.htm border-image-image-type-005.htm border-image-round-and-stretch.html border-image-shorthand-001.htm border-image-shorthand-002.htm border-image-shorthand-003.htm border-image-space-001.html parsing/border-image-invalid.html parsing/border-image-shorthand.sub.html parsing/border-image-valid.html This is a shorthand property for setting 'border-image-source', 'border-image-slice', 'border-image-width', 'border-image-outset', and 'border-image-repeat' in a single declaration. Omitted values are set to their [=initial values=].

Effect on Tables

The 'border-image' properties apply to the border of tables and inline tables that have 'border-collapse' set to ''border-collapse/collapse''. However, this specification does not define how such an image border is rendered. In particular, it does not define how the image border interacts with the borders of cells, rows and row groups at the edges of the table (see border conflict resolution in [[!CSS2]]). It is expected that a future specification will define the rendering. It is recommended that UAs do not apply border images to tables with collapsed borders until then.

Partial borders

Not Ready For Implementation

This section is not yet ready for implementation. It exists in this repository to record the ideas and promote discussion.

Before attempting to implement anything of this section, please contact the CSSWG at www-style@w3.org.

CSS borders traditionally cover an entire border edge. Sometimes, however, it can be useful to hide some parts of the border. Issue: Here are two proposals for doing this: the second one is from GCPM, the first one is an attempt to recast it more readably. The names are terrible, known problem, proposals accepted. There is a problem with conceiving this as clipping: if you have dotted borders, you want whole dots always, not parts of dots. So it should be a drawing limit, not a clip.

Partial Borders: the 'border-limit' property

		Name: border-limit
		Value: all | [ sides | corners ] <>?
					| [ top | right | bottom | left ] <>
		Initial: all
		Applies to: all elements, except table element when 'border-collapse' is ''collapse''
		Inherited: no
		Percentages: relative to border-box
		Animation type: discrete
	

By default, the entire border is drawn. However, border rendering can be limited to only part of a border. The keyword specifies which part, and the length or percentage specifies how much.

''all''
The entire border is drawn.
''sides''
The sides are drawn up to but not including the corners (as defined by the border radii). A length or percentage is measured from the center of each side: ''50%'' draws the middle 50% of the border; by default the entire side is drawn.
''corners''
The corners are drawn plus the specified distance into the sides if specified. A length is measured from the closest edge of the corner area. A percentage is measured from the absolute corner of the border box.
''left''
''right''
For the left and right (vertical) sides, draws the entire side and corner. For the top and bottom (horizontal) sides, draws the left/right portion, as specified. Distances are measured as for ''corners''.
''top''
''bottom''
For the top and bottom (horizontal) sides, draws the entire side and corner. For the left and right (vertical) sides, draws the top/bottom portion, as specified. Distances are measured as for ''corners''.

The following example draws only the middle 50% of the sides.

			div {
				border: solid;
				border-limit: sides 50%;
			}
		

The following example draws only the curved parts of the corners.

			div {
				border: solid;
				border-radius: 1em 2em;
				border-limit: corners;
			}
		

The following example draws only the left 4em of the top border.

			div {
				border-top: solid;
				border-limit: left 4em;
			}
		

The following example draws only the first 10px of each corner:

			div {
				border: solid;
				border-limit: corners 10px;
			}
		

The following example draws the curved part of the corner plus 5px along the sides:

			div {
				border: solid;
				border-radius: 5px;
				border-limit: corners 5px;
			}
		

The following example draws the curved part of the corner and all of the side except the middle 40%.

			div {
				border: solid;
				border-radius: 5px;
				border-limit: corners 30%;
			}
		

The 'border-clip' properties

		Name: border-top-clip, border-right-clip, border-bottom-clip, border-left-clip,
			border-block-start-clip, border-block-end-clip, border-inline-start-clip, border-inline-end-clip
		Value: none | [ <> | <> ]+
		Initial: none
		Inherited: no
		Logical property group: border-clip
		Percentages: refer to length of border-edge side
		Computed value: ''border-top-clip/none'', or a list consisting of absolute lengths, or percentages as specified
		Animation type: by computed value
	

These properties split their respective borders into parts along the border edge. The first part is visible, the second is invisible, the third part is visible, etc. Parts can be specified with lengths, percentages, or flexible lengths (expressed by the ''fr'' unit, as per [[CSS3GRID]]). The ''border-top-clip/none'' value means that the border is not split, but shown normally. The [=flow-relative=] longhands ('border-block-start-clip', etc.) correspond to the [=physical=] longhands ('border-top-clip', etc.) depending on the element’s 'writing-mode', 'direction', and 'text-orientation'.

		Name: border-block-clip, border-inline-clip
		Value: <<'border-top-clip'>>
	
These two [=shorthand properties=] set the 'border-block-start-clip' & 'border-block-end-clip' and 'border-inline-start-clip' & 'border-inline-end-clip', respectively.
		Name: border-clip
		Value: <<'border-top-clip'>>
	
'border-clip' is a [=shorthand property=] for the longhand properties, setting all four sides to the same value. If the listed parts are shorter than the border, any remaining border is split proportionally between the specified flexible lengths. If there are no flexible lengths, the behavior is as if ''1fr'' had been specified at the end of the list. If the listed parts are longer than the border, the specified parts will be shown in full until the end of the border. In this case, all flexible lengths will be zero. For horizontal borders, parts are listed from left to right. For vertical borders, parts are listed from top to bottom. The exact border parts are determined by laying out the specified border parts with all flexible lengths initially set to zero. Any remaining border is split proportionally between the flexible lengths specified.
border-clip: 10px 1fr 10px;
			border-top-clip: 10px 1fr 10px;
			border-bottom-clip: 10px 1fr 10px;
			border-right-clip: 5px 1fr 5px;
			border-left-clip: 5px 1fr 5px;
		

By making the first part have zero length, the inverse border of the previous example can easily be created:

			border-top-clip: 0 10px 1fr 10px;
			border-bottom-clip: 0 10px 1fr 10px;
			border-right-clip: 0 5px 1fr 5px;
			border-left-clip: 0 5px 1fr 5px;
		
			border: thin solid black;
			border-clip: 0 1fr; /* hide borders */
			border-top-clip: 10px 1fr 10px; /* make certain borders visible */
			border-bottom-clip: 10px 1fr 10px;
		
			border-top: thin solid black;
			border-bottom: thin solid black;
			border-top-clip: 10px;
			border-bottom-clip: 10px;
		
			border-top: thin solid black;
			border-clip: 10px;
		

This rendering:

				A sentence consists of words¹.
			
				¹ Most often.
			
can be achieved with this style sheet:
			@footnote {
				border-top: thin solid black;
				border-clip: 4em;
			}
		
			border: 4px solid black;
			border-top-clip: 40px 20px 0 1fr 20px 20px 0 1fr 40px;
		

In this example, there will be a visible 40px border part on each end of the top border. Inside the 40px border parts, there will be an invisible border part of at least 20px. Inside these invisible border parts, there will be visible border parts, each 20px long with 20px invisible border parts between them.

The fragments are shown in red for illustrative purposes; they should not be visible in compliant UAs.

			border: 4px solid black;
			border-top-clip: 3fr 10px 2fr 10px 1fr 10px 10px 10px 1fr 10px 2fr 10px 3fr;
		

All but one of the visible border parts are represented as flexible lengths in this example. The length of these border parts will change when the width of the element changes. Here is one rendering where 1fr ends up being 10px:

Here is another rendering where 1fr ends up being 30px:

The fragments are shown in red for illustrative purposes; they should be black in compliant UAs.

tentative/parsing/border-clip-computed.html tentative/parsing/border-clip-invalid.html tentative/parsing/border-clip-valid.html

Drop Shadows

Coloring shadows: the 'box-shadow-color' property

		Name: box-shadow-color
		Value: <>#
		Initial: currentcolor
		Applies to: all elements
		Inherited: no
		Percentages: N/A
		Computed value: list, each item a computed color
		Animation type: by computed value
	

The 'box-shadow-color' property defines one or more drop shadow colors. The property accepts a comma-separated list of shadow colors.

See the section [[css-backgrounds-3#shadow-layers|“Layering, Layout, and Other Details”]] for how 'box-shadow-color' interacts with other comma-separated drop shadow properties to form each drop shadow layer. tentative/parsing/box-shadow-color-computed.html tentative/parsing/box-shadow-color-invalid.html tentative/parsing/box-shadow-color-valid.html

Offsetting shadows: the 'box-shadow-offset' property

		Name: box-shadow-offset
		Value: [ none | <>{1,2} ]#
		Initial: none
		Applies to: all elements
		Inherited: no
		Percentages: N/A
		Computed value: list, each item either ''box-shadow-offset/none'' or a pair of offsets
			(horizontal and vertical) from the element‘s box
		Animation type: by computed value,
			treating ''box-shadow-offset/none'' as ''0 0''
			when interpolated with non-''box-shadow-offset/none'' values.
	

The 'box-shadow-offset' property defines one or more drop shadow offsets. The property accepts a comma-separated list. Each item in that list can either be the ''box-shadow-offset/none'' value, which indicates no shadow, a pair of <> values, which define the horizontal and vertical offsets, or a single <> value, which sets both offsets to the same value.

none
The shadow will not be rendered. The values of other box shadow properties corresponding to this shadow have no effect.
1st <>
Specifies the horizontal offset of the shadow. A positive value draws a shadow that is offset to the right of the box, a negative length to the left. If only one <> value is specified, it sets both the horizontal and vertical offsets to that value.
2nd <>
Specifies the vertical offset of the shadow. A positive value offsets the shadow down, a negative one up.

See the section [[css-backgrounds-3#shadow-layers|“Layering, Layout, and Other Details”]] for how 'box-shadow-offset' interacts with other comma-separated drop shadow properties to form each drop shadow layer. tentative/parsing/box-shadow-offset-computed.html tentative/parsing/box-shadow-offset-invalid.html tentative/parsing/box-shadow-offset-valid.html

Blurring shadows: the 'box-shadow-blur' property

		Name: box-shadow-blur
		Value: <>#
		Initial: 0
		Applies to: all elements
		Inherited: no
		Percentages: N/A
		Computed value: list, each item a <>
		Animation type: by computed value
	

The 'box-shadow-blur' property defines one or more blur radii for drop shadows. The property accepts a comma-separated list of <> values.

Negative values are invalid. If the blur value is zero, the shadow’s edge is sharp. Otherwise, the larger the value, the more the shadow’s edge is blurred. See [[css-backgrounds-3#shadow-blur|Shadow Blurring]], below.

See the section [[css-backgrounds-3#shadow-layers|“Layering, Layout, and Other Details”]] for how 'box-shadow-blur' interacts with other comma-separated drop shadow properties to form each drop shadow layer. tentative/parsing/box-shadow-blur-computed.html tentative/parsing/box-shadow-blur-invalid.html tentative/parsing/box-shadow-blur-valid.html

Spreading shadows: the 'box-shadow-spread' property

		Name: box-shadow-spread
		Value: <>#
		Initial: 0
		Applies to: all elements
		Inherited: no
		Percentages: N/A
		Computed value: list, each item a <>
		Animation type: by computed value
	

The 'box-shadow-spread' property defines one or more spread distances for drop shadows. The property accepts a comma-separated list of <> values.

Positive values cause the shadow to expand in all directions by the specified radius. Negative values cause the shadow to contract. See [[css-backgrounds-3#shadow-shape|Shadow Shape]], below.

Note that for inner shadows, expanding the shadow (creating more shadow area) means contracting the shadow’s perimeter shape.

See the section [[css-backgrounds-3#shadow-layers|“Layering, Layout, and Other Details”]] for how 'box-shadow-spread' interacts with other comma-separated drop shadow properties to form each drop shadow layer. tentative/parsing/box-shadow-spread-computed.html tentative/parsing/box-shadow-spread-invalid.html tentative/parsing/box-shadow-spread-valid.html

Spreading shadows: the 'box-shadow-position' property

		Name: box-shadow-position
		Value: [ outset | inset ]#
		Initial: outset
		Applies to: all elements
		Inherited: no
		Percentages: N/A
		Computed value: list, each item one of the keywords
		Animation type: by computed value
	

The 'box-shadow-position' property defines one or more drop shadow positions. The property accepts a comma-separated list of ''box-shadow-position/outset'' and ''box-shadow-position/inset'' keywords.

outset
Causes the drop shadow to be an outer box-shadow. That means, one that shadows the box onto the canvas, as if it were lifted above the canvas.
inset
Causes the drop shadow to be an inner box-shadow. That means, one that shadows the canvas onto the box, as if the box were cut out of the canvas and shifted behind it.

See the section [[css-backgrounds-3#shadow-layers|“Layering, Layout, and Other Details”]] for how 'box-shadow-position' interacts with other comma-separated drop shadow properties to form each drop shadow layer. tentative/parsing/box-shadow-position-computed.html tentative/parsing/box-shadow-position-invalid.html tentative/parsing/box-shadow-position-valid.html

Drop Shadows Shorthand: the 'box-shadow' property

		Name: box-shadow
		Value: <>#
		Initial: none
		Applies to: all elements
		Inherited: no
		Percentages: N/A
		Computed value: see individual properties
		Animation type: see individual properties
	

The 'box-shadow' property attaches one or more drop-shadows to the box. The property accepts a comma-separated list of shadows, ordered front to back.

Each shadow is given as a <>, outlining the 'box-shadow-offset' defined by two <> values, and optional values for the 'box-shadow-blur', 'box-shadow-spread', 'box-shadow-color', and 'box-shadow-position'. Omitted lengths are ''0''; omitted colors default to ''transparent'' when the specified offset is ''box-shadow-offset/none'' and to ''currentcolor'' otherwise. Note: To avoid ambiguities in parsing the different <> values, the offset has to be specified as two <> values, in opposite to the 'box-shadow-offset' property, where a single <> value can be used to specify both offsets.

	<> = <<'box-shadow-color'>>? && [ [ none | <>{2} ] [ <<'box-shadow-blur'>> <<'box-shadow-spread'>>? ]? ] && <<'box-shadow-position'>>?
The example below demonstrates the effects of spread and blur on the shadow:
		width: 100px; height: 100px;
		border: 12px solid blue; background-color: orange;
		border-top-left-radius: 60px 90px;
		border-bottom-right-radius: 60px 90px;
		box-shadow: 64px 64px 12px 40px rgba(0,0,0,0.4),
		            12px 12px 0px 8px rgba(0,0,0,0.4) inset;
		
The sample code above would create a 100px×100px orange box with a 12px blue border,
			          whose top right / bottom left corners are sharp and tob left / bottom right corners are elliptically curved.
			          Two shadows are created: an inner one, which due to its offset and spread creates a 20px-wide band of darker orange along the top and left sides of the box (curving to match the rounded top left border shape);
			          and an outer one, creating a 204px×204px gray duplicate of the shape seemingly behind the box,
			          offset 24px down and 24px to the right of the box's top and left edges.
			          Applying the 12px blur radius to the outer shadow creates a gradual shift from the shadow color to transparent along its edges
			          which is visibly apparent for 24px centered along the edge of the shadow.

Shadow Shape, Spread, and Knockout

An [=outer box-shadow=] casts a shadow as if the border-box of the element were opaque. Assuming a spread distance of zero, its perimeter has the exact same size and shape as the border box. The shadow is drawn outside the border edge only: it is clipped inside the border-box of the element. An [=inner box-shadow=] casts a shadow as if everything outside the padding edge were opaque. Assuming a spread distance of zero, its perimeter has the exact same size and shape as the padding box. The shadow is drawn inside the padding edge only: it is clipped outside the padding box of the element. If a [=spread distance=] is defined, the shadow perimeter defined above is expanded outward (for [=outer box-shadows=]) or contracted inward (for [=inner box-shadows=]) by outsetting (insetting, for inner shadows) the shadow's straight edges by the [=spread distance=] (and flooring the resulting width/height at zero).
Below are some examples of an orange box with a blue border being given a drop shadow.

					border:5px solid blue;
					background-color:orange;
					width: 144px;
					height: 144px;
					
border-radius: 20px;
border-radius: 0;

					box-shadow:
					  rgba(0,0,0,0.4)
					  10px 10px;
					
A round-cornered box with a light gray shadow the same shape
					          as the border box offset 10px to the right and 10px down
					          from directly underneath the box. A square-cornered box with a light gray shadow the same shape
					          as the border box offset 10px to the right and 10px down
					          from directly underneath the box.

					box-shadow:
					  rgba(0,0,0,0.4)
					  10px 10px
					  inset
					
A round-cornered box with a light gray shadow the inverse shape
					          of the padding box filling 10px in from the top and left edges
					          (just inside the border). A square-cornered box with a light gray shadow the inverse shape
					          of the padding box filling 10px in from the top and left edges
					          (just inside the border).

					box-shadow:
					  rgba(0,0,0,0.4)
					  10px 10px 0
					  10px /* spread */
					
A round-cornered box with a light gray shadow the same shape
					          as the box but 20px taller and wider and offset so that the
					          top and left edges of the shadow are directly underneath the
					          top and left edges of the box. A square-cornered box with a light gray shadow the same shape
					          as the box but 20px taller and wider and offset so that the
					          top and left edges of the shadow are directly underneath the
					          top and left edges of the box.

					box-shadow:
					  rgba(0,0,0,0.4)
					  10px 10px 0
					  10px /* spread */
					  inset
					
A round-cornered box with a light gray shadow the inverse shape
					          of the box but 20px narrower and shorter filling 20px in from
					          the top and left edges (just inside the border). A round-cornered box with a light gray shadow the inverse shape
					          of the box but 20px narrower and shorter filling 20px in from
					          the top and left edges (just inside the border).
To preserve the box's shape when spread is applied, the corner radii of the shadow are also increased (decreased, for inner shadows) from the border-box (padding-box) radii by adding (subtracting) the [=spread distance=] (and flooring at zero). For outer shadows, the [=border radius=] is then [=outset-adjusted border radius|adjusted=], independently in each dimension, to preserve the sharpness of rounded corners. The 'border-image' does not affect the shape of the box-shadow.

Blurring Shadow Edges

A non-zero [=blur radius=] indicates that the resulting shadow should be blurred, such as by a Gaussian filter. The exact algorithm is not defined; however the resulting shadow must approximate (with each pixel being within 5% of its expected value) the image that would be generated by applying to the shadow a Gaussian blur with a standard deviation equal to half the blur radius. Note: This means for a long, straight shadow edge, the blur radius will create a visibly apparent color transition approximately the twice length of the blur radius that is perpendicular to and centered on the shadow's edge, and that ranges from almost the full shadow color at the endpoint inside the shadow to almost fully transparent at the endpoint outside it.

Layering, Layout, and Other Details

Drop shadows are declared in the [=coordinated value list=] constructed from the 'box-shadow-*' properties, which form a [=coordinating list property group=] with 'box-shadow-offset' as the [=coordinating list base property=]. See [[css-values-4#linked-properties]]. The shadow effects are applied front-to-back: the first shadow is on top and the others are layered behind. Shadows do not influence layout and may overlap (or be overlapped by) other boxes and text or their shadows. In terms of stacking contexts and the painting order, the outer box-shadows of an element are drawn immediately below the background of that element, and the inner shadows of an element are drawn immediately above the background of that element (below the borders and border image, if any). Unless otherwise specified, drop shadows are only applied to the [=principal box=]. If the affected box has multiple fragments, the shadows are applied as specified in 'box-decoration-break'. Shadows do not trigger scrolling or increase the size of the scrollable area. Outer shadows have no effect on internal table elements in the collapsing border model. If a shadow is defined for single border edge in the collapsing border model that has multiple border thicknesses (e.g. an outer shadow on a table where one row has thicker borders than the others, or an inner shadow on a rowspanning table cell that adjoins cells with different border thicknesses), the exact position and rendering of its shadows are undefined.

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' property augments these capabilities, by enabling the author to use any [=basic shape=] to specify the path of the border.

The 'border-shape' property

		Name: border-shape
		Value: none | [ <> <>?]{1,2}
		Initial: none
		Applies to: all elements
		Inherited: no
		Percentages: see prose
		Computed value: list, each item a computed color
		Animation type: by computed value
	
The 'border-shape' property defines custom shapes for element borders using one or two [=basic shape=] values.

Syntax and Usage Modes

The 'border-shape' property accepts either a single <> or two <>s: : 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. : 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'.

Geometry Box References

When a <> is not explicitly provided, the default reference box depends on the number of <> values: : 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.

Examples

Creating a circular border using stroke mode:
		.circular-button {
			width: 100px;
			height: 100px;
			border: 5px solid blue;
			border-shape: circle(50%);
		}
		
This creates a circular border with a 5px stroke width.
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=] is cast as if the shape defined by the outer path were opaque. An [=inner box-shadow=] is cast as if everything outside the shape defined by the inner path were opaque. For both inner and outer shadows, the shadow shape is expanded or contracted by the spread distance, blurred by the blur radius, and then clipped by the 'border-shape', adhering to the standard 'box-shadow' painting rules.
		.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. tentative/border-shape/border-shape-clips-background.html tentative/border-shape/border-shape-double-shape-default.html tentative/border-shape/border-shape-inner-outer.html tentative/border-shape/border-shape-overflow.html tentative/border-shape/border-shape-shadow.html tentative/border-shape/border-shape-geometry-box.html tentative/border-shape/border-shape-half-border-box-default.html tentative/border-shape/border-shape-overflow-solid-background.html tentative/border-shape/border-shape-stroke-from-border.html tentative/border-shape/border-shape-stroke-invalidation.html tentative/parsing/border-shape-computed.html tentative/parsing/border-shape-invalid.html tentative/parsing/border-shape-valid.html

Privacy Considerations

No new privacy considerations have been reported on this specification.

Security Considerations

No new security considerations have been reported on this specification.

Changes

Changes since the First Public Working Draft of 22 July 2025

* Added 'corner-*' shorthands * Renamed corners to 'corner' * Added Web Platform Tests coverage * Incorporated full text of [[CSS3BG]] related to borders and shadows * Renamed 'border-clip-*' properties to 'border-*-clip' and added logical longhands and shorthands * Renamed normal value of 'border-*-clip' properties to ''border-top-clip/none'' * Added new syntax for 'border-*-*-radius' longhands using a slash to separate horizontal and vertical radii * Allowed a single <> value for 'box-shadow-offset' to set both offsets to the same value * Changed the special case of 'border-width' having a value of ''0'' when 'border-style' is ''border-style/none'' or ''border-style/hidden'' from a computed-value effect to a resolved-value effect. (Issue 11494)

Additions since [[CSS3BG]]

* <> as value for 'border-color' and its longhands * Added physical and logical 'border-*-radius' shorthands * Added 'corner-shape' and 'corner-*-shape' shorthands, plus related 'corner' and 'corner-*' shorthands * Added 'border-shape' * Added partial borders via 'border-limit' and 'border-*-clip' properties * Added 'box-shadow-*' longhands and turned 'box-shadow' into a shorthand * Moved logical border properties from [[CSS-LOGICAL-1]] to this spec.

Acknowledgments

In addition to the many contributors to the [[CSS1]], [[CSS2]], and [[CSS3BG]] predecessors to this module, the editors would like to thank Tab Atkins, Noam Rosenthal, Håkon Wium Lie, Oriol Brufau, and Guillaume Lebas for their suggestions and feedback specifically for this Level 4.