C.S Weekly 1: Envelope SVG

My first hand crafted SVG, and how you can make one too

Gregory ‘Grey’ Barkans
6 min readJul 22, 2018

This is my first CS Weekly project. Read Code Something Weekly: How and Why for the inspiration and ideas behind the effort.

This week, I built from scratch an SVG envelope with animations. The deployed project is here and all of the code is on Github.

A snazzy GIF demo

The Idea

The idea is simple: create a material inspired envelope that can open and close.

I’m not entirely sure where this idea came from. For starters, I’ve used SVGs or exported them from Adobe PS and Inkscape, but I’ve never coded one.

And that just won’t do.

Furthermore, I’ve noticed GMail has some really nifty animations, including the new loading/splash screen. That envelope quite literally pops out right at you!

So perhaps I didn’t exactly have free will in this decision (I think Derren Brown and Sam Harris would agree).

The Prototype

Most ideas should start with a playground. Avoid the dreaded wait times of spinning up a new project filled with configurations and boilerplate, it will only get in the way.

I used CodePen to prototype both the paper and envelope. You can check them out and tinker. These do not have the Vue application bloat or anything fancy — 100% es6/babel JS:

Tutorial — Paper Icon

Let’s run through the simple Paper icon (available on codepen).

First, let’s get an idea of what an SVG is and why we use one. As the name implies, an SVG is a scalable vector graphic. But what’s that?

  • JPEG, PNG and related formats are raster graphics: a matrix of pixels. The data in the file defines how to paint those pixels on the screen.
  • By contrast, vector graphics define a coordinate system and relative paths.

The key difference is that scaling raster graphics leads to distortion because of pixel interpolation. Think about it this way: if you have a file that defines exactly how each pixel of a 500x500 grid looks like, then suddenly add or remove pixels or densities — how does the image cope?

Vector graphics define a logic that can render at any scale. SVG is just a standardized vector graphic protocol for the web.

<SVG>

We start by adding a simple <svg> tag to the HTML markup.

<svg
class="svg-paper"
id="paper"
preserveAspectRatio="xMidYMid meet"
viewbox="0 0 400 400"
width="100%"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
</svg>
  • I set a class and id in order to be able to resize etc. via CSS.
  • viewbox is the relative grid. Think of it like a telescope. It takes 4 arguments: min-x, min-y, width, height . Think of the first two arguments as the telescope pan and the latter two as the zoom. Thus 0 0 400 400 states: “make a 400x400 grid and set top left coordinate to (0, 0)”.
  • preserveAspectRatio defines how to scale the svg, and only does something if the viewbox is defined. The value xMidYMid meet is the default behaviour. To see various ways of scaling an SVG, checkout out the MDN docs.
  • width="100%" — denotes that the width of the paper will take up the entire width of its container (in the case of codepen, the body). Note how this is independent of the viewbox. The viewbox just sets a coordinate system!
  • The xml attributes are references to the w3 svg namespace.

A Simple Shape: <rect>

Now that we have the SVG boiler out of the way let’s make our first shape. The following is the paper background (the white sheet).

<rect
class="svg-paper__sheet"
fill="#FFF"
height="100%"
width="100%"
x="0"
y="0"/>
  • I set a class in order to use CSS should I wish to
  • fill="#FFF" gives it white color
  • height and width are set to 100% : the sheet should fill the entire SVG viewbox.
  • x and y denote where to place the shape: the upper left corner.

Grouping and Render Order

Like <div>s, group tags <g> are a container for children. If we want to apply a CSS class or an animation to multiple components (for example, multiple <rect> ), we should group them.

Before moving further, let’s add a group to our shape so far:

<svg ...>
<g class="svg-paper__group">
<rect ... />
</g>
</svg>

The class svg-paper__group can now be used to access all of its children — ie every shape in the SVG.

When we place multiple items in a SVG, we have to be cognizant of render order. As we work down in the code, we’re working up (towards us) in terms of layering. Thus if we place a <rect> underneath the existing one, it will appear on top.

Adding Lines

Let’s add a new group for the lines, as there will be multiple and they’re all related:

<svg ...>
<g class="svg-paper__group">
<rect .../>
<g class="svg-paper__lines">
</g>
</g>
</svg>

In that new group, let’s add a first line:

<rect
class="svg-paper__line"
fill="#BBDEFB"
height="1%"
width="90%"
x="5%"
y="20%"/>
  • class="svg-paper__line" gives each line a class so that we can define any CSS properties
  • I gave mine a blue fill, but feel free to change it up. Here’s a color picker tool.
  • height="1%" — this was a guess, but paper lines are fairly short relative to the entire height of the page. I liked how it came out. Notice that again, this is 1% so that if we change the height of the overall SVG, the lines will adjust accordingly to be 1% of the overall height.
  • I set width="90%" because lines don’t usually span the entire page width, there’s usually a margin
  • x="5%" positions the x-coordinate of the start of the line as 5% of the page width. Working on a 400x400 grid, that means starting out on 20.
  • Similarly, y="20%" positions the line 20% of the page height down the page. Thus, on a 400x400 grid, we’re starting on (20, 80).

At this point, adding more lines is as simple as copy-pasting and changing the y attribute. I set mine to 20%, 30%, 40%, 50%, 60%, 70%, 80%, though feel free to experiment.

This completes a simple paper icon — it really wasn’t too bad!

Animations

Let’s examine a simple animation using the concepts in the paper icon above. For a discussion on the more advanced animations seen in the envelope, read the documentation in the Github repository.

Add a new css property .red

.red {
fill: #f45c42;
}

We’re going to listen to mouseover and mouseout events on the <group> of lines, and toggle their colour (see, grouping is useful).

const lineGroup = document
.getElementsByClassName('svg-paper__lines')[0]

This is just vanilla JavaScript: query the document for the svg-paper__lines class, and take the first result of the HTML collection, [0] There should only be one anyways.

Next, setup an event listener for mouseover and mouseout:

lineGroup.addEventListener('mouseover', () => {
// do something on mouseover
})
lineGroup.addEventListener('mouseout', () => {
// do something on mouseout
})

Currently we’re detecting events when we hover over any one given line in the Paper icon (but not between the lines) with barely any lines of code. Neat.

In order to change the class of the lines themselves, let’s get a reference to a collection of each line:

// this is an array-like HTML collection [<rect>, <rect>]
const lines = document.getElementsByClassName('svg-paper__line')

Finally, add the class red in the mouseover event and remove it in the mouseout event:

lineGroup.addEventListener('mouseover', () => {
[...lines].forEach(line => {
line.classList.add('red')
})
})
lineGroup.addEventListener('mouseout', () => {
[...lines].forEach(line => {
line.classList.remove('red')
})
})

Note: The spread syntax [...lines] is essentially converting the lines HTML collection into an Array, so that I can access the forEach method using es6. If this is new to you or confusing, you can check out this thread on Stack Overflow.

--

--

Gregory ‘Grey’ Barkans

I’m a software engineer between Hamont ← → ATX that’s mainly interested in technology and philosophy. I used to spin DJ mixes as well. vapurrmaid.ca