One design element that I enjoy from Google’s Material Design is small, brightly colored headers on the slide out sidebars (drawers).
In the example above, you can see that the header is comprised of semi-random geometric shapes, all of very similar colors to the primary accent color of the app. I decided to implement something for Kepler. The usual way to accomplish this is to create a set of PNG images, one to match each accent color. However, I want to improve on this method.
Goals
- Create a Single File, which adapts to Accent Color
- File should be resolution independent (vector)
Method
The solution here is to use SVG. A single SVG file with all of the shapes having fill values that are semi-transparent. Call it as a background-image
, on top of the accent color as a background-color
. This will create the effect we are going for, with only a single file to load.
I did cheat a little and use Adobe Illustrator to create the file, rather than hand code it. I drew in a number of triangles, and gave each one a color, either black of white. I then turned the opacity down mostly to 20%. I then started tweaking. I gave different tints to different triangles, rather than just light or dark. I ended up with this:
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 4712 2400" preserveAspectRatio="none">
<polygon opacity="0.2" fill="#4E1800" points="1040.2,1912.9 1040.2,1711.2 0,1369.8 0,2400 3138.7,2400 1382.7,1823.7" />
<polygon opacity="0.2" fill="#646464" points="2690,418.4 3286.8,2161.9 4350.1,1388.4 "/>
<polygon opacity="0.5" fill="url(#SVGID_1_)" points="2618.4,373.3 3262.2,2254 3286.8,2161.9 2690,418.4 "/>
<polygon opacity="0.5" fill="url(#SVGID_2_)" points="3286.8,2161.9 3262.2,2254 4406.8,1421.3 4350.1,1388.4 "/>
<polygon opacity="0.2" fill="#C5FF9D" points="0,0 0,838.8 1980.5,0 "/>
<polygon opacity="0.5" fill="#583A30" points="2690,418.4 1980.5,0 1040.2,398.2 1040.2,1912.9 3024.6,1396 "/>
<polygon opacity="0.5" fill="url(#SVGID_3_)" points="1040.2,398.2 974.7,426 974.7,1976 1040.2,1912.9 "/>
<polygon opacity="0.5" fill="url(#SVGID_4_)" points="3024.6,1396 1040.2,1912.9 974.7,1976 3039.1,1438.3 "/>
<polygon opacity="0.5" fill="url(#SVGID_5_)" points="0,894 2032.4,34.8 1980.5,0 0,838.8 "/>
<polygon opacity="0.5" fill="url(#SVGID_6_)" points="1980.5,0 1897.1,35.3 4712,1695.1 4712,1598.4 "/>
<polygon opacity="0.2" fill="#999999" points="4712,0 1980.5,0 4712,1598.4 "/>
<path fill="#999999" d="M4350.1,170.1"/>
<polygon opacity="0.5" fill="url(#SVGID_7_)" points="1227.8,1864 2856.6,2400 3138.7,2400 1382.7,1823.7 "/>
<polygon opacity="0.5" fill="url(#SVGID_8_)" points="0,1460 1040.2,1802.3 1040.2,1711.2 0,1369.8 "/>
</svg>
If you notice, there is no shadow though. Illustrator has a way to give things a box shadow (it refers to them as drop shadow). That doesn’t translate well into SVG though. The method that I found that works is to create additional shapes, and give them linear gradients, changing from black at 80% opacity to black at 0% opacity. This simulates a shadow.
Adding these pseudo shadows gives us a much better look:
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 4712 2400" preserveAspectRatio="none">
<polygon opacity="0.2" fill="#4E1800" points="1040.2,1912.9 1040.2,1711.2 0,1369.8 0,2400 3138.7,2400 1382.7,1823.7" />
<polygon opacity="0.2" fill="#646464" points="2690,418.4 3286.8,2161.9 4350.1,1388.4 "/>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="2994.686" y1="1295.1405" x2="2947.686" y2="1311.1405">
<stop offset="0" style="stop-color:#000000"/>
<stop offset="1" style="stop-color:#000000;stop-opacity:0"/>
</linearGradient>
<polygon opacity="0.5" fill="url(#SVGID_1_)" points="2618.4,373.3 3262.2,2254 3286.8,2161.9 2690,418.4 "/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="3796.0203" y1="1785.3143" x2="3831.187" y2="1833.1477">
<stop offset="0" style="stop-color:#000000"/>
<stop offset="1" style="stop-color:#000000;stop-opacity:0"/>
</linearGradient>
<polygon opacity="0.5" fill="url(#SVGID_2_)" points="3286.8,2161.9 3262.2,2254 4406.8,1421.3 4350.1,1388.4 "/>
<polygon opacity="0.2" fill="#C5FF9D" points="0,0 0,838.8 1980.5,0 "/>
<polygon opacity="0.5" fill="#583A30" points="2690,418.4 1980.5,0 1040.2,398.2 1040.2,1912.9 3024.6,1396 "/>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="1038.7261" y1="1187.1169" x2="979.2026" y2="1187.1169">
<stop offset="0" style="stop-color:#000000"/>
<stop offset="1" style="stop-color:#231F20;stop-opacity:0"/>
</linearGradient>
<polygon opacity="0.5" fill="url(#SVGID_3_)" points="1040.2,398.2 974.7,426 974.7,1976 1040.2,1912.9 "/>
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="1995.4419" y1="1662.8521" x2="2005.6919" y2="1702.3521">
<stop offset="0" style="stop-color:#000000"/>
<stop offset="1" style="stop-color:#000000;stop-opacity:0"/>
</linearGradient>
<polygon opacity="0.5" fill="url(#SVGID_4_)" points="3024.6,1396 1040.2,1912.9 974.7,1976 3039.1,1438.3 "/>
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="996.2665" y1="416.9094" x2="1014.2665" y2="459.7427">
<stop offset="0" style="stop-color:#000000"/>
<stop offset="1" style="stop-color:#231F20;stop-opacity:0"/>
</linearGradient>
<polygon opacity="0.5" fill="url(#SVGID_5_)" points="0,894 2032.4,34.8 1980.5,0 0,838.8 "/>
<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="3344.2688" y1="795.9683" x2="3307.9355" y2="859.3016">
<stop offset="0" style="stop-color:#000000"/>
<stop offset="1" style="stop-color:#231F20;stop-opacity:0"/>
</linearGradient>
<polygon opacity="0.5" fill="url(#SVGID_6_)" points="1980.5,0 1897.1,35.3 4712,1695.1 4712,1598.4 "/>
<polygon opacity="0.2" fill="#999999" points="4712,0 1980.5,0 4712,1598.4 "/>
<path fill="#999999" d="M4350.1,170.1"/>
<linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="2197.5562" y1="2088.9697" x2="2174.2229" y2="2159.303">
<stop offset="0" style="stop-color:#000000"/>
<stop offset="1" style="stop-color:#000000;stop-opacity:0"/>
</linearGradient>
<polygon opacity="0.5" fill="url(#SVGID_7_)" points="1227.8,1864 2856.6,2400 3138.7,2400 1382.7,1823.7 "/>
<linearGradient id="SVGID_8_" gradientUnits="userSpaceOnUse" x1="534.8533" y1="1541.2555" x2="508.8533" y2="1620.2555">
<stop offset="0" style="stop-color:#000000"/>
<stop offset="1" style="stop-color:#000000;stop-opacity:0"/>
</linearGradient>
<polygon opacity="0.5" fill="url(#SVGID_8_)" points="0,1460 1040.2,1802.3 1040.2,1711.2 0,1369.8 "/>
</svg>
The code is obviously much longer, but the size is a whopping 3.4KB. (To put that into perspective, exporting that to a 600px wide PNG is just over 40KB. And we’d need one for each color scheme.)
We can now place this as a background-image
. However, one thing to note here is that we want it to stretch and to not maintain aspect ratio. To do this, you may have noticed in my code that I’ve added an attribute to the svg
element. By default, browsers preserve the aspect ratio of SVG files. To turn this off, we add: preserveAspectRatio="none"
. This will allow the SVG to stretch.
If we place it over the 5 accent colors, we get these:
Leave a Reply