Animating my SVG Logo

Dec 17, 2023, 13:23 GMT+04min

Bring versatility and crispness to your static SVG(Scalable Vector Graphics). Adding animation to these logos can further enhance the user experience and bring a touch of interactivity to your website. Here's how I did it.

The Figma Vector

Minimalism. Take a moment to consider what sets your website apart—Whether it's a focus on sustainability, a commitment to craftsmanship, or a passion for innovation, let these guiding principles inform the design of your logo. I personality opted for a signature logo, a simple combination of the letters S & M.

  • Open Figma > Create your canvas (Frame)
  • Select the Pencil Tool (Shift+P)
  • Draw a simple logo with your mouse - I used a Wacom Intuos Pro S with a pressure sensitive pen in my case. Fortunately Figma smoothens pen lines so drawing with a mouse shouldn't be hard either.

Steve-martin-logo-path

SVG stroke width is uniform here and Figma does not support pen pressure but that's negligible in my case since the logo will be small anyway.

Prepare your Vector Path

We need to define a vector path for us to be able to animate its various properties with CSS; stroke-dashoffset(hides the path initially) and stroke-dasharray(defines the length of the path) in our case.

  • in Figma, choose the Pen Tool (P)
  • Draw along your SVG vector following your handwriting path. It takes some getting used to but the path is basically an invisible line that connects two or more points.
  • For curves, create anchor points with direction lines by clicking and dragging. Direction lines go in two directions. The direction that you drag the direction line will be the direction the curve will go through this point.
  • Export your logo as SVG
adding-vector-path-to-svg-in-figma

Configuring SVG in Next.js

There are many ways to import icons or SVG files in your project but keeping things clean, organized and error-free is always the way to go.

If it's only the logo you're working on, you can skip this step and add your css styles instead. But if like me, you're working with many SVG files (e.g. custom icons) and want to have as much control over them then keep on.

Create an icons.tsx component in your components folder to hold all your needed SVGs like so:

import * as React from "react";
import { SVGProps } from "react";

type IconSvgProps = SVGProps<SVGSVGElement> & {
  size?: number;
  color?: string;
};

export const Logo: React.FC<IconSvgProps> = ({
  size = 50,
  color,
  width,
  height,
  ...props
}) => (
  <svg
    className="stroke-foreground logo-path"
    height={height || size}
    width={width || size}
    viewBox="0 0 700 700"
    fill="none"
    xmlns="http://www.w3.org/2000/svg"
    {...props}
  >
    <filter id="noise1">
      <feTurbulence baseFrequency="0.035" />
      <feDisplacementMap in="SourceGraphic" scale="10" />
    </filter>
    <path
      className="path-1"
      d="M262.452 77.3215C262.452 77.3215 21.9485 274.455 69.0258 263.296C110.781 246.559 143.394 243.149 154.481 243.537C218.445 240.05 339.004 261.785 309.529 376.625C272.686 520.174 82.842 630.016 50.0926 591.077C21.64 557.248 196.612 383.599 283.944 305.141C390.891 207.891 583.703 28.6193 507.561 38.383C412.383 50.5876 217.422 586.428 295.713 496.927C358.653 388.248 500.397 186.001 477.37 295.261C454.343 404.521 332.556 550.976 429.781 459.732C527.006 368.488 549.78 353.94 544.404 386.505C539.798 414.401 537.752 500.996 636 398.128"
      strokeWidth="5"
      strokeLinecap="round"
      pathLength={198}
      filter="url(#noise1)"
      opacity={0.7}
    />
    <path
      className="path-2"
      d="M262.452 77.3215C262.452 77.3215 21.9485 274.455 69.0258 263.296C110.781 246.559 143.394 243.149 154.481 243.537C218.445 240.05 339.004 261.785 309.529 376.625C272.686 520.174 82.842 630.016 50.0926 591.077C21.64 557.248 196.612 383.599 283.944 305.141C390.891 207.891 583.703 28.6193 507.561 38.383C412.383 50.5876 217.422 586.428 295.713 496.927C358.653 388.248 500.397 186.001 477.37 295.261C454.343 404.521 332.556 550.976 429.781 459.732C527.006 368.488 549.78 353.94 544.404 386.505C539.798 414.401 537.752 500.996 636 398.128"
      strokeWidth="10"
      strokeLinecap="round"
      pathLength={198}
    />
  </svg>
);

// Add your other SVGs exports

Notice that I have custom props like size, width, height and color for my SVG renders and this gives me much control depending on what I'm working on. The size prop defines both the height and width if these are not set or are equal. And the color prop sets a custom color to SVG strokes.

I have two paths in my logo with different stroke-widths, opacities and a custom noise filter. This is preferential, yours may differ and you may not need a filter.

Adding Some Style

Adding the styles to your imported SVG,

@media (prefers-reduced-motion) {
  path {
    animation: none !important;
    stroke-dasharray: unset !important;
  }
}
@keyframes grow {
  0% {
    stroke-dashoffset: 1px;
    stroke-dasharray: 0 200px;
    opacity: 0;
  }
  10% {
    opacity: 1;
  }
  40% {
    stroke-dasharray: 200px 0;
  }
  85% {
    stroke-dasharray: 200px 0;
  }
  95%,
  to {
    stroke-dasharray: 0 200px;
  }
}
.logo-path .path-1 {
  stroke-dashoffset: 1px;
  stroke-dasharray: 200px;
  animation: grow 5s ease forwards infinite;
  transform-origin: center;
  stroke: hsl(var(--foreground));
  animation-delay: 0s;
}
.logo-path .path-2 {
  stroke-dashoffset: 1px;
  stroke-dasharray: 200px;
  animation: grow 10s ease forwards infinite;
  transform-origin: center;
  stroke: hsl(var(--foreground));
  animation-delay: 0s;
}
  • This media query targets users who have enabled the reduce motion setting in their operating system or browser preferences. We ensure that users who prefer reduced motion won't experience any animated effects.
  • The we stroke-dashoffset and stroke-dasharray to control the appearance of the dashed stroke by determining the starting position of the dash pattern and defining the length and gap of the dashes.
  • Since I have two paths at different opacities, I set a different animation-duration time for each (5s & 10s). Yours may differ.

Final Result

Two SVG paths with noise filter:

steve-martin-logo-svg-two-paths

Single SVG path:

steve-martin-logo-svg-single-paths