20
How I Created These Generative Underline Pen Strokes
(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.
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
}
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;
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:
20