SVGs


Web Development

Updated May 24th, 2023

Scalable. Vector. Graphics:

<svg viewbox="0 0 100 100">
  <rect />
  <circle />
  <polygon />
  <line />
  <path />
</svg>

Cleaning up SVG’s: Strip down and compress as much as possible. Set bounding box / view box. Add if there is not one, (view box=”0 0 height width”). Remove fill to target with CSS? Flatten. No decimals? (may not be able to do this without distorting the path).

Use shape tools to reduce any overlay

Ctrl+alt+G makes a frame from a group. get rid of unnecessary groups

Use optimization tool like svgomg

Three modes of svg: object (embed, object, iframe), image (img tag, css background: url), and inline.

Object mode: standalone file, no control from outside.

Can display as an image tag (same as .png or .jpg) or directly in your html/markup. Setting an an image you can set width inline or via a class in CSS. Putting SVG Path right into markup/html gives you more control, saves an image request for browser, and comes with the added benefit of being able to animate with CSS and JS.

To help reduce/organize SVG code in your markup you can implement the “use” tag and href=”#” and put the code at the bottom. You also need xlink:href=”#” for safari (deprecated in all browsers but Safari)

If your logo has type and it’s only shown on the page a few times, use an svg as loading in a entire font would be silly.

Logo type: crazy drop shadow fill and stroke, can you accomplish in CSS?

Can create a handwrite effect by animating.

This was a good tutorial here and you can tell this guy really knows his shit.

Checkout GSAP (by greensock) for Advanced Animations that makes CSS Animations more like After Effects.

Circle tags (r stands for radius, cx where center is on x-axis and cy where center is on y-axis). rect tag (stands for rectangle). Don’t need to add px after numbers as it is assumed. Fill, stroke, and stroke-width are properties. preserveAspectRatio set to “none” distorts on resize.

Viewport versus Viewbox

Viewport: set dimensions of what you’re looking at whole space. viewbox usually starts with 0 0 followed by a height and width so it’s four numbers in a row similar to setting margin in CSS. The first two numbers of the viewbox control position and panning left and right. The last two numbers control the zoom so if 0 0 300 300 is the base-case then 0 0 150 150 zooms in and 0 0 600 600 would zoom out.

Random

WordPress Media Library Does Not Support SVG Uploads? This is because of security. svg is basically code. use within theme folder.

Integrating with CSS and JavaScript

The fireship video shows two cool examples. 1.) Reverse engineers from the stripe homepage a micro animation on hover for a triangle icon and 2.) An animated cell phone looping animation that runs in the background without the need for the user to interact with it, (keyframe animations).

pro-tip: In the browser console pull up control + p to search for animations to bring up the animations tab that records animations on page and gives you a breakdown of keyframes and which elements they effect.

Key takeaways from #1:

The two triangles are really four triangles with two hidden off cameras. Draw on the smallest artboard possible This frame is equivalent to the view box in the browser. Group elements in figma and you get a div in code with an id. When exporting as svg make sure you have “include id attributes” checkbox selected and uncheck the show fill fill color checkbox. He removes the fill colors from the path because they are hard to override and can be targeted with CSS. Later shows how we can also target events on the SVG using JavaScript. Change the color every time the SVG is clicked. He gets the element from the DOM, runs and “onclick” function to randomly select values from an array, and applies the colors with document.documentElement.style.cssText = `–darkColor: ${rando()}; –light-color: ${rando()};`. Super Cool.

#dark1, #light1, #dark2 {
  transition: all 1s ease;
}
#dark2 {
  transform: translateX(-100%);
}
svg:hover #light1 {
  transform: translateX(20%);
}
svg:hover #light2 {
  transform: translateX(40%);
  opacity: 0;
}
svg:hover #dark2 {
  transform: translateX(0%);
}

Key takeaways from #2:

Outline of a phone visible from start, some gray skeleton text fades up from the bottom, and some green bolt icons fade in from the top with a staggered motion. In figma there are separate groups for each of these three things.

#skeleton {
  animation: fadeInUp 1s;
}

@keyframes fadeInUp {
  from {
    opacity: 0;
    transform: translateY(20%);
  }
  to {
    opacity: 1;
    transform: tarnslateY(0%);
  }
}

Piece of cake. But the next part is the best, super powerful. Target each icon in the bolt group individually.

Note: “forwards” essentially uses the last value of the keyframe (holds) until the animation ends. Alternatively and/or additionally could use the “infinite” value to loop forever. Using “infinite” means you need to think carefully about starting and ending states, (because you essentially want to end at the starting point so there is no jump).

#bolt g {
  opacity: 0;
  animation: dropIn 8s ease forwards infinite;
}

@keyframes dropIn {
  20% {
    opacity: 0;
    transform: translateY(-20%);
  }
  30%, 100% {
    opacity: 1;
    transform: translateY(0);
  }
}

The above code says don’t show for the first 20% then between 20 and 30% they drop in from the top and then hold. And now for the best part, the stagger. Define inline css variables directly in the SVG itself. These have higher priority.

<g id="bolt5" style="--order: 5">

Note: this gets applied to the bolt group level because in his structure there is a circle and path that makes up the icon.

Then go back tot he main style sheet and add an animation-delay and use in combination with “calc” to dynamically calculate a value by the delay.

animation-delay: calc(var(--order)*200ms); // magic

And here it all is together:

#bolt g {
  opacity: 0;
  animation: dropIn 8s ease forwards infinite;
  animation-delay: calc(var(--order)*200ms); // magic
}

@keyframes dropIn {
  20% {
    opacity: 0;
    transform: translateY(-20%);
  }
  30%, 100% {
    opacity: 1;
    transform: translateY(0);
  }
}

Not about implementing the above solution in React/JSX. The syntax will be a little different:

style={{ "--order": 1 }}

Sources

This Fireship video is the best and was previously written up here