Stay organized with collections
Save and categorize content based on your preferences.
Wrapping content around custom paths
Razvan Caliman
For a long time, web designers have been forced to create within the constraints of the rectangle. Most content on the web is still trapped in simple boxes because most creative ventures into non-rectangular layout end in frustration. That is about to change with the introduction of CSS Shapes, available starting with Chrome 37.
CSS Shapes allow web designers to wrap content around custom paths, like circles, ellipses and polygons, thus breaking free from the constraints of the rectangle.
Shapes can be defined manually or they can be inferred from images.
Let's look at a very simple example.
Perhaps you've been as naïve as me when first floating an image with transparent parts expecting the content to wrap and fill the gaps, only to be disappointed by the rectangular wrap shape persisting around the element. CSS Shapes can be used to solve this problem.
The shape-outside: url(image.png) CSS declaration tells the browser to extract a shape from the image.
The shape-image-threshold property defines the minimum opacity level of pixels that will be used to create the shape. Its value must be in the range between 0.0 (fully transparent) and 1.0 (fully opaque). So, shape-image-threshold: 0.5 means that only pixels with opacity 50% and above will be used to create the shape.
The float property is key here. While the shape-outside property defines the shape of the area around which content will wrap, without the float, you won't see the effects of the shape.
Elements have a float area on the opposite side of their float value. For example, if an element with a coffee cup image is being floated left, the float area will be created to the right of the cup. Even though you can engineer an image with gaps on both sides, content will only wrap around the shape on the opposite side designated by the float property, left or right, never both.
In the future, it will be possible to use shape-outside on elements which are not floated with the introduction CSS Exclusions.
Creating shapes manually
Beyond extracting shapes from images, you can also code them manually. You can choose from a few functional values to create shapes: circle(), ellipse(), inset() and polygon(). Each shape function accepts a set of coordinates and it is paired with a reference box which establishes the coordinate system. More about reference boxes in a moment.
The circle() function
The full notation for a circle shape value is circle(r at cx cy) where r is the radius of the circle, while cx and cy are coordinates of the circle center on the X-axis and Y-axis. The coordinates for the circle center are optional. If you omit them, the center of the element (the intersection of its diagonals) will be used as the default.
In the example above, content will wrap around the outside of a circular path. The single argument 50% specifies the radius of the circle, which, in this specific case, amounts to half of the element's width or height. Changing the dimensions of the element will influence the radius of the circle shape. This is a basic example of how CSS Shapes can be responsive.
Before going further, a quick aside: it is important to remember that CSS Shapes influence only the shape of the float area around an element. If the element has a background, that will not be clipped by the shape. To achieve that effect, you must use properties from CSS Masking - either clip-path or mask-image. The clip-path property comes in very handy because it follows the same notation as CSS Shapes, so you can reuse values.
Illustrations throughout this document use clipping to highlight the shape and help you understand the effects.
Back to the circle shape.
When using percentages for the circle radius, the value is actually computed with a slightly more complex formula: sqrt(width^2 + height^2) / sqrt(2). It's useful to understand this because it will help you imagine what the resulting circle shape will be if the element's dimensions are not equal.
All CSS unit types can be used in shape function coordinates - px, em, rem, vw, vh, and so forth. You can pick the one which is flexible or rigid enough for your needs.
You can adjust the circle's position by setting explicit values for the coordinates of its center.
.element{shape-outside:circle(50%at00);}
This positions the circle center at the origin of the coordinate system. What is the coordinate system? This is where we introduce reference boxes.
Reference boxes for CSS Shapes
The reference box is a virtual box around the element, which establishes the coordinate system used to draw and position the shape. The origin of the coordinate system is at its upper-left corner with the X-axis pointing to the right and the Y-axis pointing down.
Remember that shape-outside alters the shape of the float area around which content will wrap. The float area extends to the outer edges of the box defined by the margin property. This is called the margin-box and it is the default reference box for a shape if none is explicitly mentioned.
The following two CSS declarations have identical results:
.element{shape-outside:circle(50%at00);/* identical to: */shape-outside:circle(50%at00)margin-box;}
We have not yet set a margin on the element. At this point it is safe to assume that the origin of the coordinate system and the circle center are at the upper-left corner of the element's content area. This changes when you do set a margin:
The origin of the coordinate system now lies outside the element's content area (100px up and 100px left), as does the circle center. The computed value of the circle radius also grows to account for the increased surface of the coordinate system established by the margin-box reference box.
[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2014-09-16 UTC."],[],[]]