Better CSS Shapes Using shape() -- Part 2: More on Arcs

Master advanced arc techniques for creating dynamic sector shapes, ring arcs, and polished circular designs with the CSS shape() function

Understanding the Arc Command Deep Dive

The arc command is the trickiest part of the shape() function, but mastering it unlocks powerful shape possibilities. Building on the fundamentals from Part 1, we'll explore complex arc configurations that create sophisticated visual effects for modern web applications.

When working with arcs, we need to understand the geometry: two points define multiple possible arcs, with four arc variations available (large/small × clockwise/counterclockwise). The radius determines which arcs are valid, and when the radius equals half the distance between points, exactly two arcs are created.

Unlike the polygon() function, shape() supports keyword values like top, bottom, left, right, and center for common positions, making your code more readable and maintainable. This is particularly useful when building responsive layouts with our modern CSS techniques.

The Arc Geometry Explained

When working with arcs, two circles can pass through the same two points, creating four possible arc variations. Understanding this geometry is essential for getting the desired shape every time in your web projects.

Arc Syntax Review

The complete arc syntax is: arc to X Y of R [large|small] [cw|ccw]

  • to: Specifies the endpoint coordinates
  • of R: Sets the arc radius
  • large/small: Determines which arc to draw (major or minor arc)
  • cw/ccw: Sets the drawing direction (clockwise or counter-clockwise)

Visual diagrams help developers understand arc selection. When the radius equals exactly half the distance between two points, only two arcs exist and direction alone determines which one to use. This geometric understanding is foundational for creating precise shapes in your CSS layouts.

Creating Sector (Pie) Shapes

Sectors are essential for pie charts and circular progress indicators. The shape() function makes them dynamic and customizable through CSS variables, enabling interactive data visualizations without JavaScript.

Sector Implementation

The sector shape requires one arc to define the curved edge and one line to connect back to the center. The fill percentage is controlled by a variable V (0-100) using trigonometric calculations that map percentage values to degree positions on a circle.

Sector Shape with Dynamic Fill
1.sector {2 --v: 35; /* [0 100] - controls fill percentage */3 4 aspect-ratio: 1;5 clip-path: shape(from top,6 arc to calc(50% + 50% * sin(var(--v) * 3.6deg))7 calc(50% - 50% * cos(var(--v) * 3.6deg)) of 50% small cw,8 line to center9 );10 border-radius: 50%;11}

The Point Calculation Formula

The arc endpoint coordinates are calculated using trigonometry:

X = 50% + 50% × sin(V × 3.6deg) Y = 50% - 50% × cos(V × 3.6deg)

The multiplier 3.6deg comes from 360° ÷ 100, converting the percentage value (0-100) to degrees for the trigonometric functions. This formula is essential for creating dynamic pie charts and progress indicators in your web applications.

Edge Case: The 100% Problem

When V equals 100, both arc points coincide at the same coordinates, causing the arc definition to break. The solution is to limit V to 99.99 using min():

--_v: min(99.99, var(--v));

This ensures a valid arc is always drawn while still appearing as a full circle. This edge case handling is crucial for building robust interactive components.

Creating Arc (Ring) Shapes

Arcs (circular rings) are more complex than sectors because they require cutting out the inner portion. This creates a ring or donut shape with customizable thickness, perfect for progress rings and decorative indicators.

Arc Shape Structure

An arc shape combines:

  • An outer arc defining the outer boundary
  • A line to the inner circle edge
  • An inner arc in the opposite direction
  • Another line back to the starting point

The thickness is controlled by a CSS variable, allowing dynamic adjustment of the ring's appearance without changing the overall dimensions.

Ring Shape with Variable Thickness
1.arc {2 --v: 35; /* fill percentage [0-100] */3 --b: 30px; /* ring thickness */4 5 --_v: min(99.99, var(--v));6 aspect-ratio: 1;7 8 clip-path: shape(from top,9 /* Outer arc */10 arc to calc(50% + 50% * sin(var(--_v) * 3.6deg))11 calc(50% - 50% * cos(var(--_v) * 3.6deg)) of 50% cw large,12 13 /* Line to inner circle */14 line to calc(50% + (50% - var(--b)) * sin(var(--_v) * 3.6deg))15 calc(50% - (50% - var(--b)) * cos(var(--_v) * 3.6deg)),16 17 /* Inner arc (counter-clockwise) */18 arc to 50% var(--b) of calc(50% - var(--b)) large19 );20 border-radius: 50%;21}

Conditional Arc Sizing

The biggest challenge with dynamic arcs is that the correct arc size (large vs small) depends on the fill value. This conditional logic is essential for creating responsive shapes that work correctly at any fill percentage.

  • When V < 50: Use small arc size
  • When V > 50: Use large arc size

CSS provides two modern approaches to handle this conditional logic, each with different browser support characteristics.

Approach 1: Using @property with if()

Register CSS properties and use inline conditionals to dynamically select the correct arc size:

@property --_v { syntax: '<number>'; inherits: false; initial-value: 35; }
@property --_f { syntax: '<number>'; inherits: false; initial-value: 0; }

.arc {
 --v: 35;
 --_v: min(99.99, var(--v));
 --_f: round(down, var(--_v), 50); /* 0 or 50 */
 --_c: if(style(--_f: 0): small; else: large);
 /* Use var(--_c) in arc definition */
}

The round() function helps categorize values into two buckets, making the conditional logic straightforward to implement.

Approach 2: Style Queries (Better Browser Support)

Style queries allow conditional styling based on container state, providing a more widely supported approach for dynamic arc sizing:

.arc {
 --v: 35;
 --b: 30px;
 --_v: min(99.99, var(--v));
 --_f: round(down, var(--_v), 50);
 container-name: arc;
}

.arc:before {
 content: "";
 clip-path: shape(from top,
 arc to calc(50% + 50% * sin(var(--_v) * 3.6deg))
 calc(50% - 50% * cos(var(--_v) * 3.6deg)) of 50% cw var(--_c, large),
 /* ... rest of shape ... */
 );
 @container arc style(--_f: 0) { --_c: small; }
}

The default is large, and when --_f equals 0 (V < 50), it switches to small through the container style query. This approach provides better cross-browser compatibility for your interactive web components.

Adding Rounded Edges to Arcs

For polished visuals, rounded arc edges create professional-looking circular elements perfect for loading indicators, badges, and decorative UI components. This technique adds visual refinement that elevates the overall design quality.

The 1% Radius Trick

When drawing quarter-circle arcs, using a tiny radius like 1% works because the browser scales it to create a perfect quarter circle. This eliminates the need to calculate exact radii and simplifies your shape() implementations.

Rounded Arc Implementation

clip-path: shape(from top,
 /* Outer arc with dynamic size */
 arc to calc(50% + 50% * sin(var(--_v) * 3.6deg))
 calc(50% - 50% * cos(var(--_v) * 3.6deg)) of 50% cw var(--_c, large),
 
 /* Inner arc with rounded corner */
 arc to calc(50% + (50% - var(--b)) * sin(var(--_v) * 3.6deg))
 calc(50% - (50% - var(--b)) * cos(var(--_v) * 3.6deg)) of 1% cw,
 
 /* Inner arc back to top */
 arc to 50% var(--b) of calc(50% - var(--b)) var(--_c, large),
 
 /* Top edge with rounded corner */
 arc to top of 1% cw
);

This four-arc approach creates smooth, rounded edges on both the inner and outer boundaries of your ring shapes, resulting in a polished appearance.

Practical Applications

Advanced arc shapes enable a variety of real-world applications in modern web development:

Pie Charts

Dynamic pie charts where each slice can be independently controlled through CSS variables, enabling animations and interactive data visualizations without JavaScript. This approach offers excellent performance for simple chart needs.

Circular Progress Indicators

Loading states and progress indicators with customizable thickness, colors, and animation states. The clip-path approach offers better performance than SVG for simple circular shapes in high-frequency update scenarios.

Decorative Badges and Indicators

Notification badges, status indicators, and decorative elements that maintain crisp edges at any size while supporting responsive design principles. These shapes scale beautifully across different viewport sizes.

Performance Considerations

  • Use CSS custom properties for dynamic values to enable GPU acceleration
  • clip-path with shape() is GPU-accelerated in modern browsers for smooth animations
  • Test on target platforms as support is still limited to recent browser versions
  • Provide graceful degradation for unsupported browsers using @supports queries
Key Arc Techniques

Dynamic Sizing

Use CSS variables to control arc fill percentage and thickness dynamically for flexible components

Conditional Arcs

Handle large/small arc selection with style queries or if() conditionals for robust rendering

Rounded Edges

Add polish with the 1% radius trick for quarter-circle arcs that look professional

Performance

GPU-accelerated clip-path works efficiently for animated shapes with minimal CPU overhead

Browser Support and Compatibility

The shape() function is a modern addition with growing but limited browser support. Understanding current compatibility helps you make informed decisions about progressive enhancement strategies.

Current Support (as of 2025)

  • Chrome: Version 137+ with full shape() support
  • Safari: Version 18.4+ with comprehensive shape() implementation
  • Firefox: Not yet supported (check caniuse.com for updates)

Progressive Enhancement Strategy

  1. Detect support using @supports (clip-path: shape(from 0 0, line to 1px 1px)) {}
  2. Provide a fallback rectangular shape for unsupported browsers
  3. Enhance progressively with arc features when supported
  4. Test animations and transitions on target platforms before deployment

For the latest browser support information, visit caniuse.com/css-shape-function and consider your target audience demographics when deciding how to implement these techniques.

Summary and Next Steps

Mastering the arc command unlocks sophisticated shape capabilities for your web projects:

Key Takeaways:

  • Arc size and direction must match the geometry of your shape for correct rendering
  • Conditional logic (style queries, if()) handles dynamic arc values gracefully
  • The 1% radius trick simplifies quarter-circle arc calculations significantly
  • Combining techniques creates professional-looking circular elements for any application

For even more advanced shape techniques including smooth curves with bezier commands, continue to Part 3: Curves of this series. You'll learn how to create fluid, organic shapes that bring visual interest to your web designs while maintaining excellent performance characteristics.

Explore more advanced CSS techniques to build modern, visually engaging web experiences.

Ready to Build Advanced CSS Shapes?

Our web development team specializes in modern CSS techniques including shape(), clip-path, and advanced animations to create visually stunning interfaces.

Frequently Asked Questions

Sources

  1. CSS-Tricks: Better CSS Shapes Using shape() -- Part 2: More on Arcs - Comprehensive arc command documentation
  2. CSS-Tricks: Better CSS Shapes Using shape() -- Part 1: Lines and Arcs - shape() function fundamentals
  3. W3C CSS Shapes Module Level 1 - Official specification for CSS shapes
  4. MDN: Basic shapes with shape-outside - MDN reference for CSS shapes