DEV Community is a community of 695,394 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

How I Created These Generative Underline Pen Strokes

Web developer, currently working for Amdocs. Founder of https://gra.dient.art, maintainer of https://github.com/open-amdocs/webrix

(Scroll down to see a live demo, or see it on CodePen)

I created a small React component that adds a randomly generated pen stroke underline to a given word.

The strokes are rendered using an SVG `<path/>` element. They vary in thickness and shape, and they take the width of the text that they underline.

Rendering The Strokes

I used an SVG element with a single `<path/>` to render the strokes. The `<path/>` has a `d` attribute specifying a series of commands and coordinates, defining the shape of the path. The `path` element is the most powerful SVG element, and I use it often when creating SVG graphics. You can learn more about it in this great MDN tutorial.

I'm using the `Q` command, which is a simple command for generating curves. I'm randomly generating a series of 2-4 curves alternating from left to right, each of which is angled a bit differently, and placed a bit lower that the previous one.

Here's the code:

``````// Draw the lines
while (line++ < lines) {
const y = line * (height / lines); // Draw every line lower than the previous one
d += ` Q \${random(30, 70)}` + // The x coordinate of the curve's center
` \${random(y - 5, y + 5)}` + // The y coordinate of the curve's center
` \${line % 2 === 0 ? random(-5, 15) : random(85, 105)}` + // The x coordinate of the curve's end, alternating between right to left based on the current line number
` \${random(y - 2, y + 2)}`; // The y coordinate of the curve's end
}
``````

Maintaining Stroke Width Consistency

SVG elements can scale up/down, but they maintain the ratio given by their `viewBox` attribute. That includes the stroke width.

For example, if our `viewBox` is defined to be a `100x100` square (i.e. `viewBox="0 0 100 100"`), and we set the `width` and `height` of the element to be `200x200`, everything inside the SVG will scale by a factor of 2. A `stroke-width` of `10px` will be rendered as `20px`.

Since the SVG element takes the width of the given word, the stroke width can scale up or down based on the word's length. To avoid that, i'm using the following CSS rule:

``````vector-effect: non-scaling-stroke;
``````

Maintaining Stroke Height Consistency

The issue described above can also affect the coordinates of the `<path/>` itself, not just the width of the stroke.

In my case, I wanted the SVG's height to remain consistent, and let the width change based on the word's length instead of maintaining the ratio given in `viewBox`.

To do that, I used the following attribute:

``````<svg preserveAspectRatio="none">
``````

See it live on CodePen: