Six Impossible Things with SVG

 

@dudleystorey

 

thenewcode.com

 

1. Responsive imagemaps

 

2. Adaptive logos & diagrams

 

6. Animated icons w/ accurate hits

 

3. Decorated visited links

 

4. Detailed tiled backgrounds

 

5. Cross-browser clip-path

 

Imagemaps were popular in the first years of the web, but quickly fell out of favor:

 
  1. Needed to be made from scratch every time
 

SVG can fix that!

 
  1. Not responsive (hit areas drift out of registration with underlying graphic)
1
  1. Large file size
 

Step 1: Link Paths / Polygons

 
<svg xmlns="http://www.w3.org/2000/svg" 
    viewBox="0 0 525 365" 
    xmlns:xlink="//www.w3.org/1999/xlink"
    preserveAspectRatio="xMinYMin meet">
    <a xlink:href="http://travelalberta.com/">
        <path id="ab" d="M351.371,342.397c-55 …" />
    </a>
…
</svg>

Step 2: Add UI

 
<style type="text/css">
    path { 
        transition: .6s fill;
        fill: #D3D3D3;
    }
    path:hover {
        fill: #22aa22;
    }
</style>

Result:

 

Taking this further, we can clip bitmap images within the SVG shapes:

 
<g id="Canada">
    <a xlink:href="http://travelalberta.com/"
            title="Alberta">
        <clipPath id="alberta-clipper">
            <path id="CA-AB" d="M1932…" />
        </clipPath>
        <image clip-path="url(#alberta-clipper)"
        width="1024" height="768" 
        xlink:href="lake-louise.jpg"
        role="image" title="Crowsnest Pass">
        </image>
     </a>
    …
  </g>
</svg>

And add some CSS:

 
svg a image { 
  opacity: 0.5;
  transition: 1s opacity;
}
svg a:hover image {
  opacity: 1;
}

The result:

 

Finally, we can place an image behind the SVG, and simply use the vector info for UI:

 
<div id="lynskey">
  <svg xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    viewBox="0 0 1000 586">
    <title>Lynskey 2015 Backroad Bike</title>
    <circle cx="770" cy="401" r="172" />
    <text x="320" y="570">DTSwiss TK540/X.9 wheelset</text>
    <polygon points="256,29 443,29 443,60 357,101 266,65" />
    <text x="0" y="120">Selle Italia X1 Flow Saddle</text>
    …
  </svg>
</div>

RWD isn’t about fitting content into smaller spaces…

 

…it's about delivering adaptive content at the appropriate level of detail.

 

SVG does that!

 

SVG is “drawing with data”: every component in a drawing can be identified and manipulated with @media queries, altered or eliminated.

 
@media screen and (max-width: 900px) {
    path#right { display: none; }
}

For security, browsers limit CSS to just four properties for :visited states.

 

…but the rules also allow SVG to alter fill and stroke of an element.

 

Using a tiny inline SVG:

 
<a href="/link.html">Link
<svg viewBox="0 0 50 50">
<polygon points="4,30 14,40 45,12 41,9 14,34 8,27"/>
</svg>
</a>

We can style it with:

 
a svg {
    width: 3rem;
    height: 3rem;
}
a svg polygon {
    fill: white;
}

a:visited svg polygon {
    fill: green;
}

More info:

 

CSS gradient backgrounds are neat, but limited:

 
  • tricky syntax
  • lots of "thinking outside the box" required for complex results
  • poor performance
  • can't do dashes, etc
  • not supported in IE9
 

SVG can fix that!

 

Given this SVG:

<svg viewBox="0 0 1 1" xmlns="http://www.w3.org/2000/svg">
    <rect width="0.5" height="1" fill="hsla(32, 42%, 50%, .5)" />
</svg>

We can place it in the background of an element using a URL, inline reference, or DataURI to produce simple stripes:

body {
    background-image: url(stripe.svg);
    background-size: 20px 20px;
    background-color: #669;
}

The same technique can be used to create plaids, tartans, etc. 

<pattern> is much more powerful  :

<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
    <defs>
        <pattern id="pinstripe" 
        patternUnits="userSpaceOnUse"
        patternTransform="rotate(-45)"
        width="50" height="50">
            <line x1="25" y="0" x2="25" y2="50"
            stroke="goldenrod" stroke-width="25" />
        </pattern>
    </defs>
    <rect width="100%" height="100%" fill="url(#pinstripe)" />
</svg>

References:

clip-path:

  • successor to clip, which had serious limitations
  • clips any element to any shape (polygon, circle, etc)
  • syntax derived from SVG clip
  • BUT… -webkit only at this time

Solution: use an SVG fallback…

 

The secret is dividing the clip-path points by 100 for the SVG:

img#penetrator {
    clip-path: url(#delta);
    -webkit-clip-path: polygon(50% 0%, 0% 100%, 100% 100%);   
}
svg#svgpath { width: 0; height: 0; }
<svg id="svgpath">
    <defs>
        <clipPath id="delta" clipPathUnits="objectBoundingBox">
            <polygon points=".5,0 0,1 1,1" />
        </clipPath>
    </defs>
</svg>

References:

Standard <img> icons:

  • have rectangular "hot spots", no matter what their shape
  • can't be internally animated
  • can't shift colors of components

(outside of the tricksiness of sprite sheets)

SVG can address all of those…

 

http://demosthenes.info/blog/859/Making-SVG-Animated-Icons

http://codepen.io/dudleystorey/pen/bLpuG

Thank you!

 

@dudleystorey

 

demosthenes.info

 

Six Impossible Things With SVG

By Dudley Storey

Six Impossible Things With SVG

Presented at the San Francisco SVG Meetup July 15, 2015.

  • 2,647