CSS Shapes Tutorial

Learn how to create geometric shapes, control text flow, and design engaging layouts with CSS Shapes

What Are CSS Shapes?

CSS Shapes allow you to define geometric shapes that web content can flow around. Unlike traditional rectangular layouts, CSS Shapes enable you to create more organic, magazine-like designs with text that wraps around custom paths.

Key CSS Shape Properties:

  • shape-outside: Defines the shape around which content wraps
  • shape-margin: Adds margin around the shape
  • shape-image-threshold: Specifies transparency threshold for image-based shapes
  • clip-path: Clips an element to a specific shape (visual only)

Why Use CSS Shapes?

  • Create more engaging, magazine-style layouts
  • Break away from traditional rectangular designs
  • Improve visual hierarchy and content flow
  • Enhance storytelling with visual elements
  • Create responsive designs that adapt to different screen sizes

Understanding Shape Functions

Basic Shape Functions

CSS provides several basic shape functions that can be used with shape-outside and clip-path:

  • circle(): Creates a circular shape
  • ellipse(): Creates an elliptical shape
  • inset(): Creates a rectangular shape with optional rounded corners
  • polygon(): Creates a custom polygon with multiple vertices

Reference Box Models

Shapes can be positioned relative to different box models:

  • margin-box: Uses the margin box as reference (default)
  • border-box: Uses the border box as reference
  • padding-box: Uses the padding box as reference
  • content-box: Uses the content box as reference

Creating Shapes with CSS

1. Border Technique

The border technique uses CSS borders to create triangles and other shapes by setting some borders to transparent.

.triangle { width: 0; height: 0; border-left: 50px solid transparent; border-right: 50px solid transparent; border-bottom: 100px solid #3498db; }

2. Transform Technique

CSS transforms can skew, rotate, and scale elements to create various geometric shapes.

.parallelogram { width: 150px; height: 100px; transform: skew(20deg); } .rhombus { width: 150px; height: 150px; transform: rotate(45deg); }

3. Pseudo-element Technique

Using ::before and ::after pseudo-elements allows you to create complex shapes by combining multiple elements.

.heart::before, .heart::after { content: ""; position: absolute; width: 75px; height: 120px; background: #e74c3c; border-radius: 75px 75px 0 0; transform: rotate(-45deg); transform-origin: 0 100%; } .heart::after { left: 0; transform: rotate(45deg); transform-origin: 100% 100%; }

Practical Applications of CSS Shapes

1. Magazine-Style Layouts

Create engaging layouts that mimic print magazine designs:

  • Text wrapping around images with custom shapes
  • Pull quotes with distinctive shapes
  • Section dividers with organic shapes
  • Asymmetric layouts that break the grid

2. Creative UI Elements

Enhance user interfaces with custom-shaped elements:

  • Custom-shaped buttons and navigation elements
  • Unique card designs with non-rectangular shapes
  • Creative loading indicators and progress bars
  • Distinctive form elements and input fields

3. Data Visualization

Use shapes to enhance data presentation:

  • Custom chart elements and data points
  • Infographic elements with distinctive shapes
  • Progress indicators with geometric designs
  • Rating systems with star and other shapes

Performance Considerations

Potential Performance Issues

  • Complex polygon shapes with many points
  • Animating shapes on many elements simultaneously
  • Using image-based shapes with large images
  • Applying shapes to elements with complex content
  • Older browsers may have performance limitations

Optimization Tips

  • Use simpler shapes when possible
  • Limit the number of points in polygons
  • Consider using will-change for animations
  • Test performance on target devices
  • Provide fallbacks for older browsers

Browser Support & Compatibility

Current Support Status

CSS Shapes have good support in modern browsers, but there are some considerations:

  • Basic shape functions supported in Chrome 37+, Firefox 62+, Safari 10.1+, Edge 79+
  • Shape-outside property requires browser prefix in some cases
  • Internet Explorer has no support for CSS Shapes
  • Mobile browsers generally have good support
  • Always test on your target browsers and devices

Progressive Enhancement Strategy:

For critical design elements, consider providing fallbacks for browsers that Don't support CSS Shapes. You can use feature detection with @supports to provide alternative styling.

@supports (shape-outside: circle(50%)) { .shape-element { shape-outside: circle(50%); clip-path: circle(50%); } } @supports not (shape-outside: circle(50%)) { .shape-element { float: left; margin-right: 1rem; border-radius: 50%; } }

CSS Shapes Implementation

Complete Example Code

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>CSS Shapes Tutorial</title>
  <style>
    * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }
    
    :root {
      --primary-color: #6a11cb;
      --secondary-color: #2575fc;
      --accent-color: #ff416c;
      --dark-color: #2c3e50;
      --light-color: #f8f9fa;
      --text-color: #333;
      --text-light: #fff;
      --spacing-sm: 0.5rem;
      --spacing-md: 1rem;
      --spacing-lg: 1.5rem;
      --spacing-xl: 2rem;
      --border-radius: 0.5rem;
      --font-main: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
      --font-heading: 'Montserrat', sans-serif;
    }
    
    body {
      font-family: var(--font-main);
      line-height: 1.6;
      color: var(--text-color);
      background: linear-gradient(135deg, var(--light-color) 0%, #eef2f5 100%);
      padding: var(--spacing-md);
      min-height: 100vh;
    }
    
    .container {
      max-width: 1200px;
      margin: 0 auto;
    }
    
    header {
      text-align: center;
      margin-bottom: var(--spacing-xl);
      padding: var(--spacing-lg);
      background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
      color: var(--text-light);
      border-radius: var(--border-radius);
      box-shadow: 0 4px 15px rgba(0,0,0,0.1);
    }
    
    h1 {
      font-family: var(--font-heading);
      font-size: clamp(1.8rem, 5vw, 3rem);
      margin-bottom: var(--spacing-sm);
    }
    
    h2 {
      font-family: var(--font-heading);
      font-size: clamp(1.4rem, 4vw, 2rem);
      margin: var(--spacing-lg) 0 var(--spacing-md);
      color: var(--dark-color);
      padding-bottom: var(--spacing-sm);
      border-bottom: 2px solid var(--primary-color);
    }
    
    .example {
      background: white;
      border-radius: var(--border-radius);
      padding: var(--spacing-lg);
      margin-bottom: var(--spacing-lg);
      box-shadow: 0 5px 15px rgba(0,0,0,0.08);
    }
    
    .demo {
      border: 2px solid #e9ecef;
      border-radius: var(--border-radius);
      padding: var(--spacing-lg);
      margin: var(--spacing-md) 0;
      background: #f8f9fa;
    }
    
    .shape-container {
      display: flex;
      flex-wrap: wrap;
      gap: var(--spacing-md);
      justify-content: center;
    }
    
    .shape-item {
      width: 150px;
      height: 150px;
      display: flex;
      align-items: center;
      justify-content: center;
      color: white;
      font-weight: bold;
      position: relative;
    }
    
    .shape-label {
      position: absolute;
      bottom: -25px;
      left: 0;
      right: 0;
      text-align: center;
      font-size: 0.8rem;
      color: var(--dark-color);
    }
    
    .code-block {
      background: #2d2d2d;
      color: #f8f8f2;
      padding: var(--spacing-md);
      border-radius: var(--border-radius);
      overflow-x: auto;
      margin: var(--spacing-md) 0;
      font-family: 'Consolas', 'Monaco', monospace;
      font-size: 0.875rem;
    }
    
    .btn {
      display: inline-block;
      padding: var(--spacing-sm) var(--spacing-md);
      background: var(--primary-color);
      color: var(--text-light);
      border: none;
      border-radius: var(--border-radius);
      cursor: pointer;
      font-size: 0.875rem;
      margin-right: var(--spacing-sm);
      transition: all 0.3s ease;
    }
    
    .btn:hover {
      background: #5a0fb5;
      transform: translateY(-2px);
    }
    
    .btn-copy {
      background: var(--secondary-color);
    }
    
    .btn-copy:hover {
      background: #1c67e3;
    }
    
    /* Basic CSS Shapes */
    .circle {
      width: 150px;
      height: 150px;
      background: linear-gradient(45deg, var(--primary-color), var(--secondary-color));
      border-radius: 50%;
    }
    
    .oval {
      width: 150px;
      height: 100px;
      background: linear-gradient(45deg, var(--primary-color), var(--secondary-color));
      border-radius: 50%;
    }
    
    .triangle {
      width: 0;
      height: 0;
      border-left: 75px solid transparent;
      border-right: 75px solid transparent;
      border-bottom: 150px solid var(--primary-color);
    }
    
    .triangle-up {
      width: 0;
      height: 0;
      border-left: 75px solid transparent;
      border-right: 75px solid transparent;
      border-bottom: 150px solid var(--primary-color);
    }
    
    .triangle-down {
      width: 0;
      height: 0;
      border-left: 75px solid transparent;
      border-right: 75px solid transparent;
      border-top: 150px solid var(--secondary-color);
    }
    
    .triangle-left {
      width: 0;
      height: 0;
      border-top: 75px solid transparent;
      border-right: 150px solid var(--accent-color);
      border-bottom: 75px solid transparent;
    }
    
    .triangle-right {
      width: 0;
      height: 0;
      border-top: 75px solid transparent;
      border-left: 150px solid var(--accent-color);
      border-bottom: 75px solid transparent;
    }
    
    /* Advanced Shapes */
    .trapezoid {
      width: 150px;
      height: 0;
      border-bottom: 100px solid var(--primary-color);
      border-left: 25px solid transparent;
      border-right: 25px solid transparent;
    }
    
    .parallelogram {
      width: 150px;
      height: 100px;
      background: linear-gradient(45deg, var(--primary-color), var(--secondary-color));
      transform: skew(20deg);
    }
    
    .rhombus {
      width: 150px;
      height: 150px;
      background: linear-gradient(45deg, var(--primary-color), var(--secondary-color));
      transform: rotate(45deg);
      margin: 30px;
    }
    
    .rhombus-inner {
      transform: rotate(-45deg);
      text-align: center;
      width: 100%;
    }
    
    .pentagon {
      width: 150px;
      height: 0;
      position: relative;
      border-width: 0 38px 110px 38px;
      border-style: solid;
      border-color: transparent transparent var(--primary-color) transparent;
    }
    
    .pentagon:after {
      content: "";
      position: absolute;
      border-width: 110px 75px 0 75px;
      border-style: solid;
      border-color: var(--primary-color) transparent transparent transparent;
      top: 110px;
      left: -75px;
    }
    
    .hexagon {
      width: 150px;
      height: 86px;
      background: var(--primary-color);
      position: relative;
    }
    
    .hexagon:before,
    .hexagon:after {
      content: "";
      position: absolute;
      width: 0;
      border-left: 75px solid transparent;
      border-right: 75px solid transparent;
    }
    
    .hexagon:before {
      bottom: 100%;
      border-bottom: 43px solid var(--primary-color);
    }
    
    .hexagon:after {
      top: 100%;
      border-top: 43px solid var(--primary-color);
    }
    
    .octagon {
      width: 150px;
      height: 150px;
      background: var(--primary-color);
      position: relative;
    }
    
    .octagon:before {
      content: "";
      position: absolute;
      top: 0;
      left: 0;
      border-bottom: 53px solid var(--primary-color);
      border-left: 53px solid var(--light-color);
      border-right: 53px solid var(--light-color);
      width: 44px;
      height: 0;
    }
    
    .octagon:after {
      content: "";
      position: absolute;
      bottom: 0;
      left: 0;
      border-top: 53px solid var(--primary-color);
      border-left: 53px solid var(--light-color);
      border-right: 53px solid var(--light-color);
      width: 44px;
      height: 0;
    }
    
    /* Heart Shape */
    .heart {
      position: relative;
      width: 150px;
      height: 135px;
    }
    
    .heart:before,
    .heart:after {
      content: "";
      position: absolute;
      left: 75px;
      top: 0;
      width: 75px;
      height: 120px;
      background: var(--accent-color);
      border-radius: 75px 75px 0 0;
      transform: rotate(-45deg);
      transform-origin: 0 100%;
    }
    
    .heart:after {
      left: 0;
      transform: rotate(45deg);
      transform-origin: 100% 100%;
    }
    
    /* Star Shape */
    .star {
      width: 0;
      height: 0;
      position: relative;
      display: block;
      margin: 50px 0;
      color: var(--primary-color);
      border-right: 100px solid transparent;
      border-bottom: 70px solid var(--primary-color);
      border-left: 100px solid transparent;
      transform: rotate(35deg);
    }
    
    .star:before {
      content: "";
      position: absolute;
      height: 0;
      width: 0;
      top: -45px;
      left: -65px;
      border-bottom: 80px solid var(--primary-color);
      border-left: 30px solid transparent;
      border-right: 30px solid transparent;
      transform: rotate(-35deg);
    }
    
    .star:after {
      content: "";
      position: absolute;
      top: 3px;
      left: -105px;
      width: 0;
      height: 0;
      color: var(--primary-color);
      border-right: 100px solid transparent;
      border-bottom: 70px solid var(--primary-color);
      border-left: 100px solid transparent;
      transform: rotate(-70deg);
    }
    
    /* Infinity Symbol */
    .infinity {
      width: 150px;
      height: 70px;
      position: relative;
    }
    
    .infinity:before,
    .infinity:after {
      content: "";
      position: absolute;
      top: 0;
      left: 0;
      width: 60px;
      height: 60px;
      border: 10px solid var(--primary-color);
      border-radius: 50px 50px 0 50px;
      transform: rotate(-45deg);
    }
    
    .infinity:after {
      left: auto;
      right: 0;
      border-radius: 50px 50px 50px 0;
      transform: rotate(45deg);
    }
    
    /* Moon Shape */
    .moon {
      width: 150px;
      height: 150px;
      border-radius: 50%;
      box-shadow: 15px 15px 0 0 var(--primary-color);
    }
    
    /* CSS Shapes for Text Wrapping */
    .shape-wrap-demo {
      width: 100%;
      max-width: 600px;
      margin: 0 auto;
    }
    
    .shape-article {
      background: white;
      padding: var(--spacing-md);
      border-radius: var(--border-radius);
    }
    
    .shape-circle-left {
      width: 200px;
      height: 200px;
      float: left;
      shape-outside: circle(50%);
      clip-path: circle(50%);
      background: linear-gradient(45deg, var(--primary-color), var(--secondary-color));
      margin: 0 var(--spacing-md) var(--spacing-md) 0;
    }
    
    .shape-polygon-right {
      width: 200px;
      height: 200px;
      float: right;
      shape-outside: polygon(0 0, 100% 0, 100% 100%, 0 70%);
      clip-path: polygon(0 0, 100% 0, 100% 100%, 0 70%);
      background: linear-gradient(45deg, var(--accent-color), #ff4b2b);
      margin: 0 0 var(--spacing-md) var(--spacing-md);
    }
    
    /* Animation Examples */
    .animated-shape {
      width: 150px;
      height: 150px;
      background: linear-gradient(45deg, var(--primary-color), var(--secondary-color));
      border-radius: 50%;
      animation: pulse 2s infinite;
    }
    
    @keyframes pulse {
      0% {
        transform: scale(1);
        box-shadow: 0 0 0 0 rgba(106, 17, 203, 0.7);
      }
      50% {
        transform: scale(1.1);
        box-shadow: 0 0 20px 10px rgba(106, 17, 203, 0);
      }
      100% {
        transform: scale(1);
        box-shadow: 0 0 0 0 rgba(106, 17, 203, 0);
      }
    }
    
    .morphing-shape {
      width: 150px;
      height: 150px;
      background: linear-gradient(45deg, var(--primary-color), var(--secondary-color));
      animation: morph 8s infinite;
      border-radius: 50%;
    }
    
    @keyframes morph {
      0% {
        border-radius: 50%;
      }
      25% {
        border-radius: 50% 50% 50% 0;
      }
      50% {
        border-radius: 50% 50% 0 0;
      }
      75% {
        border-radius: 50% 0 0 0;
      }
      100% {
        border-radius: 50%;
      }
    }
  </style>
</head>
<body>
  <div class="container">
    <header>
      <h1>CSS Shapes Tutorial</h1>
      <p>Create geometric shapes and control text flow with CSS</p>
    </header>
    
    <section class="example">
      <h2>1. Basic Shapes</h2>
      <p>CSS allows you to create various geometric shapes using basic properties.</p>
      
      <div class="demo">
        <div class="shape-container">
          <div class="shape-item circle">
            Circle
            <div class="shape-label">border-radius: 50%</div>
          </div>
          <div class="shape-item oval">
            Oval
            <div class="shape-label">border-radius: 50% (different width/height)</div>
          </div>
          <div class="shape-item triangle-up">
            Triangle
            <div class="shape-label">border technique</div>
          </div>
          <div class="shape-item trapezoid">
            Trapezoid
            <div class="shape-label">border technique</div>
          </div>
        </div>
      </div>
      
      <div class="code-block">
        /* Circle */
        .circle {
          width: 150px;
          height: 150px;
          border-radius: 50%;
        }
        
        /* Oval */
        .oval {
          width: 150px;
          height: 100px;
          border-radius: 50%;
        }
        
        /* Triangle */
        .triangle-up {
          width: 0;
          height: 0;
          border-left: 75px solid transparent;
          border-right: 75px solid transparent;
          border-bottom: 150px solid #3498db;
        }
        
        /* Trapezoid */
        .trapezoid {
          width: 150px;
          height: 0;
          border-bottom: 100px solid #3498db;
          border-left: 25px solid transparent;
          border-right: 25px solid transparent;
        }
      </div>
    </section>
    
    <section class="example">
      <h2>2. Advanced Shapes</h2>
      <p>More complex shapes can be created with CSS using transforms and pseudo-elements.</p>
      
      <div class="demo">
        <div class="shape-container">
          <div class="shape-item parallelogram">
            Parallelogram
            <div class="shape-label">transform: skew()</div>
          </div>
          <div class="shape-item rhombus">
            <div class="rhombus-inner">Rhombus</div>
            <div class="shape-label">transform: rotate(45deg)</div>
          </div>
          <div class="shape-item pentagon">
            Pentagon
            <div class="shape-label">border technique + pseudo-element</div>
          </div>
          <div class="shape-item hexagon">
            Hexagon
            <div class="shape-label">pseudo-elements</div>
          </div>
        </div>
      </div>
      
      <div class="code-block">
        /* Parallelogram */
        .parallelogram {
          width: 150px;
          height: 100px;
          transform: skew(20deg);
        }
        
        /* Rhombus */
        .rhombus {
          width: 150px;
          height: 150px;
          transform: rotate(45deg);
        }
        
        /* Pentagon */
        .pentagon {
          width: 150px;
          height: 0;
          position: relative;
          border-width: 0 38px 110px 38px;
          border-style: solid;
          border-color: transparent transparent #3498db transparent;
        }
        
        .pentagon:after {
          content: "";
          position: absolute;
          border-width: 110px 75px 0 75px;
          border-style: solid;
          border-color: #3498db transparent transparent transparent;
          top: 110px;
          left: -75px;
        }
      </div>
    </section>
    
    <section class="example">
      <h2>3. Creative Shapes</h2>
      <p>CSS can create organic and creative shapes beyond basic geometry.</p>
      
      <div class="demo">
        <div class="shape-container">
          <div class="shape-item heart">
            <div class="shape-label">Heart (pseudo-elements)</div>
          </div>
          <div class="shape-item star">
            <div class="shape-label">Star (pseudo-elements)</div>
          </div>
          <div class="shape-item infinity">
            <div class="shape-label">Infinity (pseudo-elements)</div>
          </div>
          <div class="shape-item moon">
            <div class="shape-label">Moon (box-shadow technique)</div>
          </div>
        </div>
      </div>
      
      <div class="code-block">
        /* Heart */
        .heart:before,
        .heart:after {
          content: "";
          position: absolute;
          width: 75px;
          height: 120px;
          background: #e74c3c;
          border-radius: 75px 75px 0 0;
          transform: rotate(-45deg);
          transform-origin: 0 100%;
        }
        
        .heart:after {
          left: 0;
          transform: rotate(45deg);
          transform-origin: 100% 100%;
        }
        
        /* Moon */
        .moon {
          width: 150px;
          height: 150px;
          border-radius: 50%;
          box-shadow: 15px 15px 0 0 #3498db;
        }
      </div>
    </section>
    
    <section class="example">
      <h2>4. Shape-Outside for Text Wrapping</h2>
      <p>The shape-outside property allows text to wrap around custom shapes.</p>
      
      <div class="demo">
        <div class="shape-wrap-demo">
          <div class="shape-circle-left"></div>
          <div class="shape-polygon-right"></div>
          <div class="shape-article">
            <h3>Text Wrapping with CSS Shapes</h3>
            <p>CSS shapes allow you to wrap text around custom paths instead of just rectangular boxes. This creates more interesting and dynamic layouts that were previously only possible with image editing software.</p>
            <p>The shape-outside property defines the shape around which inline content should wrap. With this property, you can create circular, elliptical, or polygonal text wraps.</p>
            <p>Combined with the clip-path property, you can both define the wrapping shape and visually clip the element to that same shape. This creates a cohesive design where the visual appearance matches the text flow.</p>
            <p>CSS shapes work best with floated elements. The browser calculates the shape's boundaries and flows the text around them, creating magazine-like layouts with pure CSS.</p>
          </div>
        </div>
      </div>
      
      <div class="code-block">
        .shape-circle-left {
          width: 200px;
          height: 200px;
          float: left;
          shape-outside: circle(50%);
          clip-path: circle(50%);
          background: linear-gradient(45deg, #6a11cb, #2575fc);
          margin: 0 1rem 1rem 0;
        }
        
        .shape-polygon-right {
          width: 200px;
          height: 200px;
          float: right;
          shape-outside: polygon(0 0, 100% 0, 100% 100%, 0 70%);
          clip-path: polygon(0 0, 100% 0, 100% 100%, 0 70%);
          background: linear-gradient(45deg, #ff416c, #ff4b2b);
          margin: 0 0 1rem 1rem;
        }
      </div>
    </section>
    
    <section class="example">
      <h2>5. Animated Shapes</h2>
      <p>CSS animations can bring shapes to life with movement and transformations.</p>
      
      <div class="demo">
        <div class="shape-container">
          <div class="shape-item animated-shape">
            Pulse
            <div class="shape-label">animation: pulse</div>
          </div>
          <div class="shape-item morphing-shape">
            Morph
            <div class="shape-label">animated border-radius</div>
          </div>
        </div>
      </div>
      
      <div class="code-block">
        /* Pulsing animation */
        .animated-shape {
          animation: pulse 2s infinite;
        }
        
        @keyframes pulse {
          0% {
            transform: scale(1);
            box-shadow: 0 0 0 0 rgba(106, 17, 203, 0.7);
          }
          50% {
            transform: scale(1.1);
            box-shadow: 0 0 20px 10px rgba(106, 17, 203, 0);
          }
          100% {
            transform: scale(1);
            box-shadow: 0 0 0 0 rgba(106, 17, 203, 0);
          }
        }
        
        /* Morphing animation */
        .morphing-shape {
          animation: morph 8s infinite;
          border-radius: 50%;
        }
        
        @keyframes morph {
          0% {
            border-radius: 50%;
          }
          25% {
            border-radius: 50% 50% 50% 0;
          }
          50% {
            border-radius: 50% 50% 0 0;
          }
          75% {
            border-radius: 50% 0 0 0;
          }
          100% {
            border-radius: 50%;
          }
        }
      </div>
    </section>
  </div>
</body>
</html>

CSS Shapes Best Practices

Do's

  • Use percentage values for responsive designs
  • Experiment with different shape functions
  • Combine shape-outside with clip-path for visual consistency
  • Test across different browsers and devices
  • Use feature detection for progressive enhancement

Don'ts

  • Don't overuse complex shapes that impact performance
  • Avoid too many points in polygon functions
  • Don't rely solely on shapes for critical content
  • Avoid using shapes for large numbers of elements
  • Don't forget to provide fallbacks for older browsers

Ready to Experiment with CSS Shapes?

Try these CSS Shapes examples in our interactive editor. Create your own shapes, experiment with text wrapping, and discover how you can transform your layouts with geometric designs.

< PreviousNext >