In Pieces
I should start with pointing out the inspiration for this post. I was searching for CSS polygon transformation when I came across this beautiful website called In Pieces by Bryan James. In Smashing Magazine we can find his article on how he created these marvelous animations. I strongly suggest you read that article, as I used exactly the same methods described there. However, in this post you'll find a more full and basic example, without the use of SASS, so even a beginner will be able to create an animation. From the Smashing Magazine article, you should remember following things:
- Polygons are created by adding a
<div>
in HTML and applying CSSclip-path
to it. - Animations are done in CSS using the
Transition
tag - Simplify your work:
- Use CSS background properties to keep track of the various polygons
- Find or create some tools that will greatly simplify your work. You can find some references in the original article. I'll be using Python, Notepad++ and an online tool.
- You can overlap polygons. This will also improve the design, as it prevents vague lines between the polygons.
- Cross-browser support is limited. It does work on most mobile devices however.
In this article, a step-by-step guide is given to create the animation of this demo, in which we'll be using the following codes/tools:
- HTML & CSS to make the shapes and animations in the browsers
- InkScape to create a design
- Path to Polygon convert to transform my InkScape design to polygons
- Excel/Google Spreadsheet to simplify the process
A simple example
Let's show the coding approach with a simple example: a single triangle. For the HTML we'll just need two nested div
elements. The parent we call polygon-wrap and its first child is given the id polygon1:
<div id="polygon-wrap"> <div id="polygon1"></div> </div>
The parent element will define the size of our drawing. As you can suspect its children will form the differetn polygons in our drawing. As we want our polygons to move freely around the space available in polygon-wrap, they will be absolutely positioned inside it. In our CSS we add:
.polygon-wrap { position:relative; width: 500px; height: 500px; } .polygon-wrap div{ position:absolute; width:inherit;height:inherit; }
Our polygons will be created in CSS, using just one property: clip-path:polygon(x1, y1, x2 y2, x3, y3)
. This property is first given polygon , for the type of shape we're creating. Then we add three sets of (x,y)-coordinates for our triangle. For the coordinates we'll be using percentages. Note that the (0,0)-coordinate is located at the top-left corner of our polygon-wrap div. Our simple example will start with a triangle with one node in the bottom-left corner (x=0,y=100%), one in the very center (50%,50%) and the final node against the right edge (100%, 75%):
.polygon1{ clip-path:polygon(0% 100%, 50% 50%, 100% 75%); background-color:#fbb63e; }
Finally, let's make it do something on hover. We'll change the background color and move our triangle. As later we're adding more polygons to polygon-wrap, we want each of them to change when we hover over the parent div. Note that we can not add or remove any nodes to the polygon.
.polygon-wrap:hover .polygon1{ clip-path:polygon(50% 40%, 20% 30%, 20% 80%); background-color:#84b4c8; }
All that's left is to animate the transitions using CSS transition
. We'll add one for background-color, and one for the change in shape. Each transition takes four values: the property which is changed, the duration of the animation, the function it follows and the delay, the waiting time before the animation starts. As Bryan James showed in his article, differently timed animations for each polygon will give a nicer design and increase performance but for simplicity we'll apply the same animation to each polygon:
.polygon-wrap div{ ... transition: background-color 1s cubic-bezier(.52,.01,.16,1) 0.2s, clip-path 1s cubic-bezier(.52,.01,.16,1) 0.2s; }
That's it. You have created an animation. Check out the demo.
From InkScape to Polygons
For more complex drawings it's not feasible to calculate every corner of each triangle, so let's try and simplify this process. For starters a design is needed, which can be easily made in InkScape (or feel free to use Illustrator if you own it). I used the website's header logo, which already is made out of polygons. For Inkscape, I recommend to:
- Draw inside a 100x100 rectangle by reducing the page size (or use guides).
- Align the bottom left of your 100x100 grid to the bottom-left of your InkScape document.
- Take care to only draw the polygons you'll use in CSS and make sure they're all in the same layer.
- Of course each polygon has to be a unique entity in InkScape.
Using 100x100 and aligning the bottom-left corner with the Inkscape origin directly gives us percentages. As the origin in InkScape is the bottom-left corner and for our CSS-polygons it's the top-left corner, the y-axis is inverted. Therefor simply flip the final drawing around the horizontal axis in InkScape and reposition it in the 100x100 box.
We could now measure and calculate the percentages of each polygon in InkScape, however, let's use this online tool to convert our paths to polygons. After uploading our document we'll find at the bottom of the page the corresponding polygons (e.g.: polygon(48.650 271.011, 30.590 294.927, 21.498 234.066)). Count the amount, it should correspond to the amount of polygons you drew. For the logo of this website, there are 16 (with two polygons consisting of four x,y-sets). Save this output to a text file. Note that the polygons are outputted in the same order as they were drawn.
We can now repeat the process for the drawing after transition. Take into account the following:
- There should be an equal amount of polygons
- The amount of corners in a polygon can not change between the original and transformed drawing.
- The online tool outputs the polygon in the same order as they are drawn and we'll not change this order. This means that the first polygon drawn in the original drawing, will become the first polygon of the transformed drawing.
Polygons to CSS clip-path
All that is left now is to transform the outputted text to a CSS clip-path
, background-color
and :hover
state for each polygon. There are various approaches for this. If you know any coding language (e.g. Javascript, Python), it is recommended to write a function to do the repetitive work. Otherwise, it can also be done using a Google/Excel spreadsheet.
For this I pasted the text in the sheet, using Search & Replace to remove the ",", "polygon(" and ")" at the end of the strings. Next the rows can be split with space as divider. We now have a sheet with in each column a coordinate (because the online tool did not recognize my reduced 100x100 page and kept an A4, I also had to subtract 197 from my y-coordinates).
Finally, add a column with numbers 1 to 16 (for our case) , which allows us to use the Concatenate function to form the CSS for each polygon. Even adding background colors at the same moment.
= CONCATENATE('.polygon';A1;'{clip-path:polygon(';A2;'% ';A3;'%, '; .....
In order to form:
.polygon1{
clip-path:polygon(0% 100%, 50% 50%, 100% 75%);
background-color:#fbb63e;
}
Recall that the animation itself was added to .polygon-wrap div
, and is the same for each polygon. If wanted, a different animation can be added in this stage. Of course, we repeat the process to create the hover state for each .polygon-wrap:hover .polygon#{
.
At the same time, also make the various HTML div
's that are necessary for the various polygons as <div id="polygon#"></div>
All that is left now is to paste the HTML inside the <div id="polygon-wrap">
, put all the CSS together and watch the magic happen. The complete code can be found in the demo.