A Pen by Stan Williams on CodePen.
Created
February 25, 2020 01:35
-
-
Save stanwmusic/26a44d23f4d95bfc8f6342e21e242d84 to your computer and use it in GitHub Desktop.
Underline.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0" viewBox="0 0 100 100"> | |
<defs> | |
<linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="0%"> | |
<stop offset="0%" stop-color="#00bc9b" /> | |
<stop offset="100%" stop-color="#5eaefd" /> | |
</linearGradient> | |
<linearGradient id="gradient2" x1="0%" y1="0%" x2="100%" y2="0%"> | |
<stop offset="0%" stop-color="#5eaefd" /> | |
<stop offset="100%" stop-color="#00bc9b" /> | |
</linearGradient> | |
</defs> | |
</svg> | |
<div class="group"> | |
<ul class="c-nav underliner"> | |
<li class="c-nav__item"><a href="#">News & Politics</a></li> | |
<li class="c-nav__item"><a href="#">Culture</a></li> | |
<li class="c-nav__item"><a href="#">Technology</a></li> | |
<li class="c-nav__item"><a href="#">Business</a></li> | |
<li class="c-nav__item"><a href="#">Human Interest</a></li> | |
</ul> | |
<ul class="c-nav c-nav-2 underliner-small"> | |
<li class="c-nav__item"><a href="#">Works</a></li> | |
<li class="c-nav__item"><a href="#">Articles</a></li> | |
<li class="c-nav__item"><a href="#">About</a></li> | |
<li class="c-nav__item"><a href="#">Contact Me</a></li> | |
<li class="c-nav__item"><a href="#">My Books</a></li> | |
</ul> | |
</div> | |
<hr> | |
<p class="ishadeed">Read the article on <a href="https://ishadeed.com/article/custom-underline-svg/">ishadeed.com</a>. <a href="https://github.com/shadeed/underliner">Github</a></p> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Underliner { | |
constructor(selector, color1, color2, thickness1, thickness2, strokeLinecap, rtl) { | |
this.links = document.querySelectorAll(selector) | |
this.fill = 'transparent'; | |
this.color1 = color1; | |
this.color2 = color2; | |
this.thickness1 = thickness1; | |
this.thickness2 = thickness2; | |
this.strokeLinecap = strokeLinecap; | |
this.rtl = rtl; | |
this.init(); | |
} | |
init() { | |
let self = this; | |
self.links.forEach(function (link) { | |
let linkWidth = parseInt(link.offsetWidth); | |
let svg = self.createSVG(linkWidth); | |
self.insertAfter(svg, link); | |
}); | |
} | |
setPath(pathD, color, thickness, strokeLinecap) { | |
const path = document.createElementNS("http://www.w3.org/2000/svg", "path"); | |
path.setAttribute("d", pathD); | |
path.setAttribute("fill", this.fill); | |
path.setAttribute("stroke", color); | |
path.setAttribute("stroke-width", thickness); | |
path.setAttribute("stroke-linecap", strokeLinecap); | |
path.setAttribute("stroke-dasharray", path.getTotalLength() + 10); | |
path.setAttribute("stroke-dashoffset", path.getTotalLength() + 10); | |
return path; | |
} | |
randomizePath(linkWidth) { | |
let moveYMin = 5; | |
let moveYMax = 12; | |
let curveXMin = 15; | |
let curveXMax = linkWidth; /* Width of the link */ | |
let curveYMin = 7; | |
let curveYMax = linkWidth * 0.12; /* Making the quadratic propotional to the link width */ | |
//let curveYMax = 20 | |
let endYMin = 5; | |
let endYMax = 11; | |
let moveY = Math.floor(Math.random() * (moveYMax - moveYMin)) + moveYMin; | |
let curveX = Math.floor(Math.random() * (curveXMax - curveXMin)) + curveXMin; | |
let curveY = Math.floor(Math.random() * (curveYMax - curveYMin)) + curveYMin; | |
let endY = Math.floor(Math.random() * (endYMax - endYMin)) + endYMin; | |
return `M5 ${moveY} Q ${curveX} ${curveY} ${linkWidth - 7} ${endY}` | |
} | |
createSVG(linkWidth) { | |
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg"); | |
svg.setAttribute("width", linkWidth); | |
svg.setAttribute("height", "35"); | |
const path = document.createElementNS("http://www.w3.org/2000/svg", "path"); | |
const path2 = document.createElementNS("http://www.w3.org/2000/svg", "path"); | |
let pathD = this.randomizePath(linkWidth); | |
let pathD2 = this.randomizePath(linkWidth); | |
if(this.rtl === true) { | |
pathD = this.reverseMe(pathD); | |
pathD2 = this.reverseMe(pathD2); | |
} | |
svg.appendChild(this.setPath(pathD, this.color1, this.thickness1, this.strokeLinecap)); | |
svg.appendChild(this.setPath(pathD2, this.color2, this.thickness2, this.strokeLinecap)); | |
svg.setAttribute("focusable", false); | |
return svg; | |
} | |
reverseMe(path) { | |
/* Regex functions borrwed from | |
https://github.com/krispo/svg-path-utils/blob/master/src/svg-path-utils.js */ | |
let pathOperators = path.replace(/[\d,\-\s]+/g, '').split(''); | |
let pathNums = path.replace(/[A-Za-z,]+/g, ' ').trim().replace(/\s\s+/g, ' ').split(' '); | |
return `${pathOperators[0]} ${pathNums[4]} ${pathNums[5]} ${pathOperators[1]} ${pathNums[2]} ${pathNums[3]} ${pathNums[0]} ${pathNums[1]}`; | |
} | |
// https://plainjs.com/javascript/manipulation/insert-an-element-after-or-before-another-32/ | |
insertAfter(el, referenceNode) { | |
referenceNode.parentNode.insertBefore(el, referenceNode.nextSibling); | |
} | |
} | |
let test = new Underliner(".underliner a", "url(#gradient)", "url(#gradient2)", 7, 12, "round", false); | |
let test2 = new Underliner(".underliner-small a", "url(#gradient)", "url(#gradient2)", 3, 6, "round"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body { | |
padding: 1rem; | |
font-family: 'IBM Plex Sans', sans-serif; | |
} | |
svg { | |
display: block; | |
} | |
.group { | |
//outline: 1px solid lightgrey; | |
padding: 1rem; | |
margin-bottom: 2.5rem; | |
} | |
.c-nav { | |
&:not(:last-child) { | |
margin: 1rem 0 2rem; | |
} | |
@media (min-width: 900px) { | |
display: flex; | |
justify-content: center; | |
} | |
} | |
.c-nav__item { | |
margin-right: 1.5rem; | |
font-size: 1.5rem; | |
a { | |
display: inline-block; | |
text-decoration: none; | |
color: #000; | |
margin-bottom: 4px; | |
transition: 0.4s; | |
} | |
svg { | |
pointer-events: none; | |
transition: 0.5s; | |
//outline: solid 1px lightgrey; | |
} | |
path { | |
transition: stroke-dasharray 0.5s, stroke-dashoffset 0.5s, opacity 0.5s; | |
&:last-child { | |
opacity: 0.2; | |
} | |
} | |
a { | |
&:hover, | |
&:focus { | |
color: #00bc9b; | |
} | |
} | |
a:hover + svg, | |
a:focus + svg { | |
opacity: 1; | |
path { | |
stroke-dashoffset: 0; | |
} | |
} | |
} | |
#path1 { | |
opacity: 0.25; | |
} | |
.c-form { | |
max-width: 500px; | |
margin: 0 auto; | |
legend { | |
margin-bottom: 1rem; | |
font-weight: bold; | |
} | |
label { | |
user-select: none; | |
} | |
} | |
.c-form__item { | |
margin-bottom: 1rem; | |
} | |
.c-nav-2 { | |
.c-nav__item { | |
font-size: 1rem; | |
} | |
} | |
hr { | |
border: 0; | |
height: 1px; | |
background: lightgrey; | |
} | |
.ishadeed { | |
text-align: center; | |
a { | |
color: #3563D9; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Preview or Fork: https://codepen.io/Stanssongs/pen/wvagxJg