Using CSS Clip Path to Create Interactive Effects, Part II

This is a follow up to my previous post looking into clip paths. Last time around, we dug into the fundamentals of clipping and how to get started. We looked at some ideas to exemplify what we can do with clipping. We’re going to take things a step further in this post and look at different examples, discuss alternative techniques, and consider how to approach our work to be cross-browser compatible.

One of the biggest drawbacks of CSS clipping, at the time of writing, is browser support. Not having 100% browser coverage means different experiences for viewers in different browsers. We, as developers, can’t control what browsers support — browser vendors are the ones who implement the spec and different vendors will have different agendas.

One thing we can do to overcome inconsistencies is use alternative technologies. The feature set of CSS and SVG sometimes overlap. What works in one may work in the other and vice versa. As it happens, the concept of clipping exists in both CSS and SVG. The SVG clipping syntax is quite different, but it works the same. The good thing about SVG clipping compared to CSS is its maturity level. Support is good all the way back to old IE browsers. Most bugs are fixed by now (or at least one hope they are).

This is what the SVG clipping support looks like:

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.

Desktop

Chrome Opera Firefox IE Edge Safari
4 9 3 9 12 3.2

Mobile / Tablet

iOS Safari Opera Mobile Opera Mini Android Android Chrome Android Firefox
3.2 10 all 4.4 67 60

Clipping as a transition

A neat use case for clipping is transition effects. Take The Silhouette Slideshow demo on CodePen:

See the Pen Silhouette zoom slideshow by Mikael Ainalem (@ainalem) on CodePen.

A “regular” slideshow cycles though images. Here, to make it a bit more interesting, there’s a clipping effect when switching images. The next image enters the screen through a silhouette of of the previous image. This creates the illusion that the images are connected to one another, even if they are not.

The transitions follow this process:

  1. Identify the focal point (i.e., main subject) of the image
  2. Create a clipping path for that object
  3. Cut the next image with the path
  4. The cut image (silhouette) fades in
  5. Scale the clipping path until it’s bigger than the viewport
  6. Complete the transition to display the next image
  7. Repeat!

Let’s break down the sequence, starting with the first image. We’ll split this up into multiple pens so we can isolate each step.

<svg> ... <image class="..." xlink:href="..." /> ... </svg>

For this image, we then want to create a mask of the focal point — in this case, the person’s silhouette. If you’re unsure how to go about creating a clip, check out my previous article for more details because, generally speaking, making cuts in CSS and SVG is fundamentally the same:

  1. Import an image into the SVG editor
  2. Draw a path around the object
  3. Convert the path to the syntax for SVG clip path. This is what goes in the SVG’s <defs> block.
  4. Paste the SVG markup into the HTML

If you’re handy with the editor, you can do most of the above in the editor. Most editors have good support for masks and clip paths. I like to have more control over the markup, so I usually do at least some of the work by hand. I find there’s a balance between working with an SVG editor vs. working with markup. For example, I like to organize the code, rename the classes and clean up any cruft the editor may have dropped in there.

Mozilla Developer Network does a fine job of documenting SVG clip paths. Here’s a stripped-down version of the markup used by the original demo to give you an idea of how a clip path fits in:

<svg> <defs> <clipPath id="clip"> <!-- Clipping defined --> <path class="clipPath clipPath2" d="..." /> </clipPath> </defs> ... <path ... clip-path="url(#clip)"/> <!-- Clipping applied -->
</svg>

Let’s use a colored rectangle as a placeholder for the next image in the slideshow. This helps to clearly visualize the shape that part that’s cut out and will give a clearer idea of the shape and its movement.

.clipPath { transition: transform 1200ms 500ms; /* Delayed transform transition */ transform-origin: 50%; } .clipPath.active { transform: translateX(-30%) scale(15); /* Upscaling and centering mask */ } .image { transition: opacity 1000ms; /* Fade-in, starts immediately */ opacity: 0; } .image.active { opacity: 1; }

Here’s what we get — an image that transitions to the rectangle!

remove = (remove + 1) % images.length; current = (current + 1) % images.length

Note that this examples is not supported by Firefox at the time of writing because is lacks support for scaling clip paths. I hope this is something that will be addressed in the near future.

Clipping to emerge foreground objects into the background

Another interesting use for clipping is for revealing and hiding effects. We can create parts of the view where objects are either partly or completely hidden making for a fun way to make background images interact with foreground content. For instance, we could have objects disappear behind elements in the background image, say a building or a mountain. It becomes even more interesting when we pair that idea up with animation or scrolling effects.

See the Pen Parallax clip by Mikael Ainalem (@ainalem) on CodePen.

This example uses a clipping path to create an effect where text submerges into the photo — specifically, floating behind mountains as a user scrolls down the page. To make it even more interesting, the text moves with a parallax effect. In other words, the different layers move at different speeds to enhance the perspective.

We start with a simple div and define a background image for it in the CSS:

window.addEventListener('scroll', function() { logo.setAttribute('transform',`translate(0 ${html.scrollTop / 10 + 5})`); clip.setAttribute('transform',`translate(0 -${html.scrollTop / 10 + 5})`); });

Don’t pay too much attention to the + 5 used when calculating the distance. It’s only there as a sloppy way to offset the element. The important part is where things are divided by 10, which creates the parallax effect. Scrolling a certain amount will proportionally move the element and the clip path. Template literals convert the calculated value to a string which is used for the transform property value as an offset to the SVG nodes.

Combining clipping and masking

Clipping and masking are two interesting concepts. One lets you cut out pieces of content whereas the other let’s you do the opposite. Both techniques are useful by themselves but there is no reason why we can’t combine their powers!

When combining clipping and masking, you can split up objects to create different visual effects on different parts. For example:

See the Pen parallax logo blend by Mikael Ainalem (@ainalem) on CodePen.

I created this effect using both clipping and masking on a logo. The text, split into two parts, blends with the background image, which is a beautiful monochromatic image of the New York’s Statue of Liberty. I use different colors and opacities on different parts of the text to make it stand out. This creates an interesting visual effect where the text blends in with the background when it overlaps with the statue — a splash of color to an otherwise grey image. There is, besides clipping and masking, a parallax effect here as well. The text moves in a different speed relative to the image when the user hovers or moves (touch) over the image.

To illustrate the behavior, here is what we get when the masked part is stripped out:

See the Pen parallax logo blend by Mikael Ainalem (@ainalem) on CodePen.

Wrapping up

Clipping is a fun way to create interactions and visual effects. It can enhance slide-shows or make objects stand out of images, among other things. Both SVG and CSS provide the ability to apply clip paths and masks to elements, though with different syntaxes. We can pretty much cut any web content nowadays. It is only your imagination that sets the limit.

If you happen to create anything cool with the things we covered here, please share them with me in the comments!

The post Using CSS Clip Path to Create Interactive Effects, Part II appeared first on CSS-Tricks.

How to create a logo that responds to its own aspect ratio

One of the cool things about <svg> is that it’s literally its own document, so @media queries in CSS inside the SVG are based on its viewport rather than the HTML document that likely contains it.

This unique feature has let people play around for years. Tim Kadlec experimented with SVG formats and which ones respect the media queries most reliably. Sara Soueidan experimented with that a bunch more. Jake Archibald embedded a canvas inside and tested cross-browser compatibility that way. Estelle Weyl used that ability to do responsive images before responsive images.

Another thing that has really tripped people’s triggers is using that local media query stuff to make responsive logos. Most famously Joe Harrison’s site, but Tyler Sticka, Jeremy Frank, and Chris Austin all had a go as well.

Nils Binder has the latest take. Nils take is especially clever in how it uses <symbol>s referencing other <symbol>s for extra efficiency and min-aspect-ratio media queries rather than magic number widths.

For the record, we still very much need container queries for HTML elements. I get that it’s hard, but the difficulty of implementation and usefulness are different things. I much prefer interesting modern solutions over trying to be talked out of it.

Direct Link to Article — Permalink

The post How to create a logo that responds to its own aspect ratio appeared first on CSS-Tricks.

Creating a Panning Effect for SVG

Earlier this month on the Animation at Work Slack, we had a discussion about finding a way to let users pan inside an SVG.

I made this demo below to show how I’d approach this question:

See the Pen Demo – SVG Panning by Louis Hoebregts (@Mamboleoo) on CodePen.

Here are the four steps to make the above demo work:

  1. Get mouse and touch events from the user
  2. Calculate the mouse offsets from its origin
  3. Save the new viewBox coordinates
  4. Handle dynamic viewport

Let’s check those steps one by one more thoroughly.

1. Mouse & Touch Events

To get the mouse or touch position, we first need to add event listeners on our SVG. We can use the Pointer Events to handle all kind of pointers (mouse/touch/stylus/…) but those events are not yet supported by all browsers. We will need to add some fallback to make sure all users will be able to drag the SVG.

// We select the SVG into the page
var svg = document.querySelector('svg'); // If browser supports pointer events
if (window.PointerEvent) { svg.addEventListener('pointerdown', onPointerDown); // Pointer is pressed svg.addEventListener('pointerup', onPointerUp); // Releasing the pointer svg.addEventListener('pointerleave', onPointerUp); // Pointer gets out of the SVG area svg.addEventListener('pointermove', onPointerMove); // Pointer is moving
} else { // Add all mouse events listeners fallback svg.addEventListener('mousedown', onPointerDown); // Pressing the mouse svg.addEventListener('mouseup', onPointerUp); // Releasing the mouse svg.addEventListener('mouseleave', onPointerUp); // Mouse gets out of the SVG area svg.addEventListener('mousemove', onPointerMove); // Mouse is moving // Add all touch events listeners fallback svg.addEventListener('touchstart', onPointerDown); // Finger is touching the screen svg.addEventListener('touchend', onPointerUp); // Finger is no longer touching the screen svg.addEventListener('touchmove', onPointerMove); // Finger is moving
}

Because we could have touch events and pointer events, we need to create a tiny function to returns to coordinates either from the first finger either from a pointer.

// This function returns an object with X & Y values from the pointer event
function getPointFromEvent (event) { var point = {x:0, y:0}; // If event is triggered by a touch event, we get the position of the first finger if (event.targetTouches) { point.x = event.targetTouches[0].clientX; point.y = event.targetTouches[0].clientY; } else { point.x = event.clientX; point.y = event.clientY; } return point;
}

Once the page is ready and waiting for any user interactions, we can start handling the mousedown/touchstart events to save the original coordinates of the pointer and create a variable to let us know if the pointer is down or not.

// This variable will be used later for move events to check if pointer is down or not
var isPointerDown = false; // This variable will contain the original coordinates when the user start pressing the mouse or touching the screen
var pointerOrigin = { x: 0, y: 0
}; // Function called by the event listeners when user start pressing/touching
function onPointerDown(event) { isPointerDown = true; // We set the pointer as down // We get the pointer position on click/touchdown so we can get the value once the user starts to drag var pointerPosition = getPointFromEvent(event); pointerOrigin.x = pointerPosition.x; pointerOrigin.y = pointerPosition.y;
}

2. Calculate Mouse Offsets

Now that we have the coordinates of the original position where the user started to drag inside the SVG, we can calculate the distance between the current pointer position and its origin. We do this for both the X and Y axis and we apply the calculated values on the viewBox.

// We save the original values from the viewBox
var viewBox = { x: 0, y: 0, width: 500, height: 500
}; // The distances calculated from the pointer will be stored here
var newViewBox = { x: 0, y: 0
}; // Function called by the event listeners when user start moving/dragging
function onPointerMove (event) { // Only run this function if the pointer is down if (!isPointerDown) { return; } // This prevent user to do a selection on the page event.preventDefault(); // Get the pointer position var pointerPosition = getPointFromEvent(event); // We calculate the distance between the pointer origin and the current position // The viewBox x & y values must be calculated from the original values and the distances newViewBox.x = viewBox.x - (pointerPosition.x - pointerOrigin.x); newViewBox.y = viewBox.y - (pointerPosition.y - pointerOrigin.y); // We create a string with the new viewBox values // The X & Y values are equal to the current viewBox minus the calculated distances var viewBoxString = `${newViewBox.x} ${newViewBox.y} ${viewBox.width} ${viewBox.height}`; // We apply the new viewBox values onto the SVG svg.setAttribute('viewBox', viewBoxString); document.querySelector('.viewbox').innerHTML = viewBoxString;
}

If you don’t feel comfortable with the concept of viewBox, I would suggest you first read this great article by Sara Soueidan.

3. Save Updated viewBox

Now that the viewBox has been updated, we need to save its new values when the user stops dragging the SVG.

This step is important because otherwise we would always calculate the pointer offsets from the original viewBox values and the user will drag the SVG from the starting point every time.

function onPointerUp() { // The pointer is no longer considered as down isPointerDown = false; // We save the viewBox coordinates based on the last pointer offsets viewBox.x = newViewBox.x; viewBox.y = newViewBox.y;
}

4. Handle Dynamic Viewport

If we set a custom width on our SVG, you may notice while dragging on the demo below that the bird is moving either faster or slower than your pointer.

See the Pen Dynamic viewport – SVG Panning by Louis Hoebregts (@Mamboleoo) on CodePen.

On the original demo, the SVG’s width is exactly matching its viewBox width. The actual size of your SVG may also be called viewport. In a perfect situation, when the user is moving their pointer by 1px, we want the viewBox to translate by 1px.

But, most of the time, the SVG has a responsive size and the viewBox will most likely not match the SVG viewport. If the SVG’s width is twice as big than the viewBox, when the user moves their pointer by 1px, the image inside the SVG will translate by 2px.

To fix this, we need to calculate the ratio between the viewBox and the viewport and apply this ratio while calculating the new viewBox. This ratio must also be updated whenever the SVG size may change.

// Calculate the ratio based on the viewBox width and the SVG width
var ratio = viewBox.width / svg.getBoundingClientRect().width;
window.addEventListener('resize', function() { ratio = viewBox.width / svg.getBoundingClientRect().width;
});

Once we know the ratio, we need to multiply the mouse offsets by the ratio to proportionally increase or reduce the offsets.

function onMouseMove (e) { [...] newViewBox.x = viewBox.x - ((pointerPosition.x - pointerOrigin.x) * ratio); newViewBox.y = viewBox.y - ((pointerPosition.y - pointerOrigin.y) * ratio); [...]
}

Here’s how this works with a smaller viewport than the viewBox width:

See the Pen Smaller viewport – SVG Panning by Louis Hoebregts (@Mamboleoo) on CodePen.

And another demo with a viewport bigger than the viewBox width:

See the Pen Bigger viewport – SVG Panning by Louis Hoebregts (@Mamboleoo) on CodePen.

[Bonus] Optimizing the code

To make our code a bit shorter, there are two very useful concepts in SVG we could use.

SVG Points

The first concept is to use SVG Points instead of basic Javascript objects to save the pointer’s positions. After creating a new SVG Point variable, we can apply some Matrix Transformation on it to convert the position relative to the screen to a position relative to the current SVG user units.

Check the code below to see how the functions getPointFromEvent() and onPointerDown() have changed.

// Create an SVG point that contains x & y values
var point = svg.createSVGPoint(); function getPointFromEvent (event) { if (event.targetTouches) { point.x = event.targetTouches[0].clientX; point.y = event.targetTouches[0].clientY; } else { point.x = event.clientX; point.y = event.clientY; } // We get the current transformation matrix of the SVG and we inverse it var invertedSVGMatrix = svg.getScreenCTM().inverse(); return point.matrixTransform(invertedSVGMatrix);
} var pointerOrigin;
function onPointerDown(event) { isPointerDown = true; // We set the pointer as down // We get the pointer position on click/touchdown so we can get the value once the user starts to drag pointerOrigin = getPointFromEvent(event);
}

By using SVG Points, you don’t even have to handle transformations applied on your SVG! Compare the following two examples where the first is broken when a rotation is applied on the SVG and the second example uses SVG Points.

See the Pen Demo + transformation – SVG Panning by Louis Hoebregts (@Mamboleoo) on CodePen.

See the Pen Demo Bonus + transform – SVG Panning by Louis Hoebregts (@Mamboleoo) on CodePen.

SVG Animated Rect

The second unknown concept in SVG we can use to shorten our code, is the usage of Animated Rect.

Because the viewBox is actually considered as an SVG Rectangle (x, y, width, height), we can create a variable from its base value that will automatically update the viewBox if we update this variable.

See how easier it is now to update the viewBox of our SVG!

// We save the original values from the viewBox
var viewBox = svg.viewBox.baseVal; function onPointerMove (event) { if (!isPointerDown) { return; } event.preventDefault(); // Get the pointer position as an SVG Point var pointerPosition = getPointFromEvent(event); // Update the viewBox variable with the distance from origin and current position // We don't need to take care of a ratio because this is handled in the getPointFromEvent function viewBox.x -= (pointerPosition.x - pointerOrigin.x); viewBox.y -= (pointerPosition.y - pointerOrigin.y);
}

And here is the final demo. See how much shorter the code is now? 😀

See the Pen Demo Bonus – SVG Panning by Louis Hoebregts (@Mamboleoo) on CodePen.

Conclusion

This solution is definitely not the only way to go to handle such behavior. If you are already using a library to deal with your SVGs, it may already have a built-in function to handle it.

I hope this article may help you to understand a bit more how powerful SVG can be! Feel free to contribute to the code by commenting with your ideas or alternatives to this solution.

Credits

  • Bird designed by Freepik
  • A big thanks to Blake for his precious help and all the nice folks from the AAW Slack for their feedback.

The post Creating a Panning Effect for SVG appeared first on CSS-Tricks.

Using SVG to Create a Duotone Effect on Images

Anything is possible with SVG, right?!

After a year of collaborating with some great designers and experimenting to achieve some pretty cool visual effects, it is beginning to feel like it is. A quick search of “SVG” on CodePen will attest to this. From lettering, shapes, sprites, animations, and image manipulation, everything is better with the aid of SVG. So when a new visual trend hit the web last year, it was no surprise that SVG came to the rescue to allow us to implement it.

The spark of a trend

Creatives everywhere welcomed the 2016 new year with the spark of a colorizing technique popularized by Spotify’s 2015 Year in Music website (here is last year’s) which introduced bold, duotone images to their brand identity.

The Spotify 2015 Year in Music site demonstrates the duotone image technique.

This technique is a halftone reproduction of an image by superimposing one color (traditionally black) with another. In other words, the darker tone will be mapped to the shadows of the image, and the lighter tone, mapped to the highlights.

We can achieve the duotone technique in Photoshop by applying a gradient map (Layer > New Adjustment Layer > Gradient Map) of two colors over an image.

Choose the desired color combination for the gradient map
A comparison of the original image (left) and when the gradient map is applied (right)

Right click (or alt + click) the adjustment layer and create a clipping mask to apply the gradient map to just the image layer directly below it instead of the applying to all layers.

It used to take finessing the <canvas> element to calculate the color mapping and paint the result to the DOM or utilize CSS blend-modes to come close to the desired color effect. Well, thanks to the potentially life-saving powers of SVG, we can create these Photoshop-like “adjustment layers” with SVG filters.

Let’s get SaVinG!

Breaking down the SVG

We are already familiar with the vectorful greatness of SVG. In addition to producing sharp, flexible, and small graphics, SVGs also support over 20 filter effects that allow us to blur, morph, and do so much more to our SVG files. For this duotone effect, we will use two filters to construct our gradient map.

feColorMatrix (optional)

The feColorMatrix effect allows us to manipulate the colors of an image based on a matrix of rbga channels. Una Kravets details color manipulation with feColorMatrix in this deep dive and it’s a highly recommended read.

Depending on your image, it may be worth balancing the colors in the image by setting it to grayscale with the color matrix. You can adjust the rbga channels as you’d like for the desired grayscale effect.

<feColorMatrix type="matrix" result="grayscale" values="1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0" >
</feColorMatrix>

feComponentTransfer

Next is to map the two colors over the highlights and shadows of our grayscale image with the feComponentTransfer filter effect. There are specific element attributes to keep in mind for this filter.

Attribute What it Does Value to Use
color-interpolation-filters (required) Specifies the color space for gradient interpolations, color animations, and alpha compositing. sRGB
result (optional) Assigns a name to this filter effect and can be used/referenced by another filter primitive with the in attribute. duotone

While the result attribute is optional, I like to include it to give additional context to each filter (and as a handy note for future reference).

The feComponent filter handles the color mapping based on transfer functions of each rbga component specified as child elements of the parent feComponentTransfer: feFuncR feFuncG feFuncB feFuncA. We use these rbga functions to calculate the values of the two colors in the gradient map.

Here’s an example:

The Peachy Pink gradient map in the screenshots above uses a magenta color (#bd0b91) , with values of R(189) G(11) B(145).

Divide each RGB value by 255 to get the values of the first color in the matrix. The RGB values of the second column result in #fcbb0d (gold). Similar to in our Photoshop gradient map, the first color (left to right) gets mapped to the shadows, and the second to the highlights.

<feComponentTransfer color-interpolation-filters="sRGB" result="duotone"> <feFuncR type="table" tableValues="(189/255) 0.9882352941"></feFuncR> <feFuncG type="table" tableValues="(11/255) 0.7333333333"></feFuncG> <feFuncB type="table" tableValues="(145/255) 0.05098039216"></feFuncB> <feFuncA type="table" tableValues="0 1"></feFuncA>
</feComponentTransfer>

Step 3: Apply the Effect with a CSS Filter

With the SVG filter complete, we can now apply it to an image by using the CSS filter property and setting the url() filter function to the ID of the SVG filter.

It’s worth noting that the SVG containing the filter can just be a hidden element sitting right in your HTML. That way it loads and is availble for use, but does not render on the screen.

background-image: url('path/to/img');
filter: url(/path/to/svg/duotone-filters.svg#duotone_peachypink);
filter: url(#duotone_peachypink);

Browser Support

You’re probably interested in how well supported this technique is, right? Well, SVG filters have good browser support.

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.

Desktop

Chrome Opera Firefox IE Edge Safari
8 9 3 10 12 6

Mobile / Tablet

iOS Safari Opera Mobile Opera Mini Android Android Chrome Android Firefox
6.0-6.1 10 all 4.4 62 57

That said, CSS filters are not as widely supported. That means some graceful degradation considerations will be needed.

This browser support data is from Caniuse, which has more detail. A number indicates that browser supports the feature at that version and up.

Desktop

Chrome Opera Firefox IE Edge Safari
18* 15* 35 No 17 6*

Mobile / Tablet

iOS Safari Opera Mobile Opera Mini Android Android Chrome Android Firefox
6.0-6.1* 37* No 4.4* 62 57

For example, Internet Explorer (IE) does not support the CSS Filter url() function, nor does it support CSS background-blend-modes, the next best route to achieving the duotone effect. As a result, a fallback for IE can be an absolutely positioned CSS gradient overlay on the image to mimic the filter.

In addition, I did have issues in Firefox when accessing the filter itself based on the path for the SVG filter when I initially implemented this approach on a project. Firefox seemed to work only if the filter was referenced with the full path to the SVG file instead of the filter ID alone. This does not seem to be the case anymore but is worth keeping in mind.

Bringing it All Together

Here’s a full example of the filter in use:

<svg xmlns="http://www.w3.org/2000/svg"> <filter id="duotone_peachypink"> <feColorMatrix type="matrix" result="grayscale" values="1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 1 0" > </feColorMatrix> <feComponentTransfer color-interpolation-filters="sRGB" result="duotone"> <feFuncR type="table" tableValues="0.7411764706 0.9882352941"></feFuncR> <feFuncG type="table" tableValues="0.0431372549 0.7333333333"></feFuncG> <feFuncB type="table" tableValues="0.568627451 0.05098039216"></feFuncB> <feFuncA type="table" tableValues="0 1"></feFuncA> </feComponentTransfer> </filter> </svg>

Here’s the impact that has when applied to an image:

A comparison of the original image (left) with the filtered effect (right) using SVG!

See the Pen Duotone Demo by Lentie Ward (@lentilz) on CodePen.

For more examples, you can play around with more duotone filters in this pen.

Resources

The following resources are great points of reference for the techniques used in this post.

  • SVG Filter primitive elements – MDN documentation
  • Finessing feColorMatrix – Una Kravets’ detailed post on A List Apart

Using SVG to Create a Duotone Effect on Images is a post from CSS-Tricks

Simple Patterns for Separation (Better Than Color Alone)

Color is pretty good for separating things. That’s what your basic pie chart is, isn’t it? You tell the slices apart by color. With enough color contrast, you might be OK, but you might be even better off (particularly where accessibility is concerned) using patterns, or a combination.

Patrick Dillon tackled the Pie Chart thing

Enhancing Charts With SVG Patterns:

When one of the slices is filled with something more than color, it’s easier to figure out [who the Independents are]:

See the Pen Political Party Affiliation – #2 by Patrick Dillon (@pdillon) on CodePen.

Filling a pie slice with a pattern is not a common charting library feature (yet), but if your library of choice is SVG-based, you are free to implement SVG patterns.

As in, literally a <pattern /> in SVG!

Here’s a simple one for horizontal lines:

<pattern id="horzLines" width="8" height="4" patternUnits="userSpaceOnUse"> <line x1="0" y1="0" x2="8" y2="0" style="stroke:#999;stroke-width:1.5" />
</pattern>

Now any SVG element can use that pattern as a fill. Even strokes. Here’s an example of mixed usage of two simple patterns:

See the Pen Simple Line Patterns by Chris Coyier (@chriscoyier) on CodePen.

That’s nice for filling SVG elements, but what about HTML elements?

Irene Ros created Pattern Fills that are SVG based, but usable in CSS also.

Using SVG Patterns as Fills:

There are several ways to use Pattern Fills:

  • You can use the patterns.css file that contains all the current patterns. That will only work for non-SVG elements.

  • You can use individual patterns, but copying them from the sample pages. CSS class definitions can be found here and SVG pattern defs can be found here

  • You can add your own patterns or modify mine! The conversion process from SVG document to pattern is very tedious. The purpose of the pattern fills toolchain is to simplify this process. You can clone the repo, run npm install and grunt dev to get a local server going. After that, any changes or additions to the src/patterns/**/* files will be automatically picked up and will re-render the CSS file and the sample pages. If you make new patterns, send them over in a pull request!

Here’s me applying them to SVG elements (but could just as easily be applied to HTML elements):

See the Pen Practical Patterns by Chris Coyier (@chriscoyier) on CodePen.

The CSS usage is as base64 data URLs though, so once they are there they aren’t super duper manageable/changeable.

Here’s Irene with an old timey chart, using d3:

Managing an SVG pattern in CSS

If your URL encode the SVG just right, you and plop it right into CSS and have it remain fairly managable.

See the Pen Simple Line Patterns by Chris Coyier (@chriscoyier) on CodePen.

Other Examples Combining Color

Here’s one by John Schulz:

See the Pen SVG Colored Patterns by Chris Coyier (@chriscoyier) on CodePen.

Ricardo Marimón has an example creating the pattern in d3. The pattern looks largely the same on the slices, but perhaps it’s a start to modify.

Other Pattern Sources

We rounded a bunch of them up recently!


Simple Patterns for Separation (Better Than Color Alone) is a post from CSS-Tricks