文本/链接

基于SVG的超链接鼠标悬停下划线动画特效

阿里云


Underliner 是一款基于 SVG 的超链接鼠标悬停下划线动画特效。Underliner 插件可以在鼠标 hover 或悬停在指定的超链接元素上面时,以动画的方式显示预定义的 SVG 元素。

HTML 结构

  1. <svg xmlns="http://www.w3.org/2000/svg" width="0" height="0" viewBox="0 0 100 100">
  2.   <defs>
  3.       <linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="0%">
  4.           <stop offset="0%" stop-color="#00bc9b" />
  5.           <stop offset="100%" stop-color="#5eaefd" />
  6.       </linearGradient>
  7.       <linearGradient id="gradient2" x1="0%" y1="0%" x2="100%" y2="0%">
  8.           <stop offset="0%" stop-color="#5eaefd" />
  9.           <stop offset="100%" stop-color="#00bc9b" />
  10.       </linearGradient>
  11.   </defs>
  12. </svg>
  13. <div class="group">
  14.     <ul class="c-nav underliner">
  15.         <li class="c-nav__item"><a href="#">News & Politics</a></li>
  16.         <li class="c-nav__item"><a href="#">Culture</a></li>
  17.         <li class="c-nav__item"><a href="#">Technology</a></li>
  18.         <li class="c-nav__item"><a href="#">Business</a></li>
  19.         <li class="c-nav__item"><a href="#">Human Interest</a></li>
  20.     </ul>
  21.     <ul class="c-nav c-nav-2 underliner-small">
  22.         <li class="c-nav__item"><a href="#">Works</a></li>
  23.         <li class="c-nav__item"><a href="#">Articles</a></li>
  24.         <li class="c-nav__item"><a href="#">About</a></li>
  25.         <li class="c-nav__item"><a href="#">Contact Me</a></li>
  26.         <li class="c-nav__item"><a href="#">My Books</a></li>
  27.     </ul>
  28. </div>
也想出现在这里?联系我们
创客主机

CSS 样式

  1. ul li {
  2.   list-style: none;
  3. }
  4.  
  5. svg {
  6.   display: block;
  7. }
  8.  
  9. .group {
  10.   padding: 1rem;
  11.   margin-bottom: 2.5rem;
  12. }
  13.  
  14. .c-nav:not(:last-child) {
  15.   margin: 1rem 0 2rem;
  16. }
  17. @media (min-width: 900px) {
  18.   .c-nav {
  19.     display: flex;
  20.     justify-content: center;
  21.   }
  22. }
  23.  
  24. .c-nav__item {
  25.   margin-right: 1.5rem;
  26.   font-size: 1.5rem;
  27. }
  28. .c-nav__item a {
  29.   display: inline-block;
  30.   text-decoration: none;
  31.   color: #000;
  32.   margin-bottom: 4px;
  33.   transition: 0.4s;
  34. }
  35. .c-nav__item svg {
  36.   pointer-events: none;
  37.   transition: 0.5s;
  38. }
  39. .c-nav__item path {
  40.   transition: stroke-dasharray 0.5s, stroke-dashoffset 0.5s, opacity 0.5s;
  41. }
  42. .c-nav__item path:last-child {
  43.   opacity: 0.2;
  44. }
  45. .c-nav__item a:hover, .c-nav__item a:focus {
  46.   color: #00bc9b;
  47. }
  48. .c-nav__item a:hover + svg,
  49. .c-nav__item a:focus + svg {
  50.   opacity: 1;
  51. }
  52. .c-nav__item a:hover + svg path,
  53. .c-nav__item a:focus + svg path {
  54.   stroke-dashoffset: 0;
  55. }
  56.  
  57. #path1 {
  58.   opacity: 0.25;
  59. }
  60.  
  61. .c-form {
  62.   max-width: 500px;
  63.   margin: 0 auto;
  64. }
  65. .c-form legend {
  66.   margin-bottom: 1rem;
  67.   font-weight: bold;
  68. }
  69. .c-form label {
  70.   -webkit-user-select: none;
  71.      -moz-user-select: none;
  72.       -ms-user-select: none;
  73.           user-select: none;
  74. }
  75.  
  76. .c-form__item {
  77.   margin-bottom: 1rem;
  78. }
  79.  
  80. .c-nav-2 .c-nav__item {
  81.   font-size: 1rem;
  82. }
  83.  
  84. hr {
  85.   border: 0;
  86.   height: 1px;
  87.   background: lightgrey;
  88. }
  89.  
  90. .ishadeed {
  91.   text-align: center;
  92. }
  93. .ishadeed a {
  94.   color: #3563D9;
  95. }

javascript

  1. class Underliner {
  2.     constructor(selector, color1, color2, thickness1, thickness2, strokeLinecap, rtl) {
  3.         this.links = document.querySelectorAll(selector)
  4.         this.fill = 'transparent';
  5.         this.color1 = color1;
  6.         this.color2 = color2;
  7.         this.thickness1 = thickness1;
  8.         this.thickness2 = thickness2;
  9.         this.strokeLinecap = strokeLinecap;
  10.         this.rtl = rtl;
  11.         this.init();
  12.     }
  13.  
  14.     init() {
  15.         let self = this;
  16.  
  17.         self.links.forEach(function (link) {
  18.             let linkWidth = parseInt(link.offsetWidth);
  19.             let svg = self.createSVG(linkWidth);
  20.             self.insertAfter(svg, link);
  21.         });
  22.     }
  23.  
  24.     setPath(pathD, color, thickness, strokeLinecap) {
  25.         const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
  26.  
  27.         path.setAttribute("d", pathD);
  28.         path.setAttribute("fill", this.fill);
  29.         path.setAttribute("stroke", color);
  30.         path.setAttribute("stroke-width", thickness);
  31.         path.setAttribute("stroke-linecap", strokeLinecap);
  32.         path.setAttribute("stroke-dasharray", path.getTotalLength() + 10);
  33.         path.setAttribute("stroke-dashoffset", path.getTotalLength() + 10);
  34.  
  35.         return path;
  36.     }
  37.  
  38.     randomizePath(linkWidth) {
  39.         let moveYMin = 5;
  40.         let moveYMax = 12;
  41.  
  42.         let curveXMin = 15;
  43.         let curveXMax = linkWidth; /* Width of the link */
  44.         let curveYMin = 7;
  45.         let curveYMax = linkWidth * 0.12; /* Making the quadratic propotional to the link width */
  46.         //let curveYMax = 20
  47.  
  48.         let endYMin = 5;
  49.         let endYMax = 11;
  50.  
  51.         let moveY = Math.floor(Math.random() * (moveYMax - moveYMin)) + moveYMin;
  52.         let curveX = Math.floor(Math.random() * (curveXMax - curveXMin)) + curveXMin;
  53.         let curveY = Math.floor(Math.random() * (curveYMax - curveYMin)) + curveYMin;
  54.         let endY = Math.floor(Math.random() * (endYMax - endYMin)) + endYMin;
  55.  
  56.         return `M5 ${moveY} Q ${curveX} ${curveY} ${linkWidth - 7} ${endY}`
  57.     }
  58.  
  59.     createSVG(linkWidth) {
  60.         const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
  61.  
  62.         svg.setAttribute("width", linkWidth);
  63.         svg.setAttribute("height", "35");
  64.  
  65.         const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
  66.         const path2 = document.createElementNS("http://www.w3.org/2000/svg", "path");
  67.  
  68.         let pathD = this.randomizePath(linkWidth);
  69.         let pathD2 = this.randomizePath(linkWidth);
  70.  
  71.         if(this.rtl === true) {
  72.             pathD = this.reverseMe(pathD);
  73.             pathD2 = this.reverseMe(pathD2);
  74.         }
  75.  
  76.         svg.appendChild(this.setPath(pathD, this.color1, this.thickness1, this.strokeLinecap));
  77.         svg.appendChild(this.setPath(pathD2, this.color2, this.thickness2, this.strokeLinecap));
  78.  
  79.         svg.setAttribute("focusable", false);
  80.  
  81.         return svg;
  82.     }
  83.  
  84.     reverseMe(path) {
  85.         /* Regex functions borrwed from 
  86.         https://github.com/krispo/svg-path-utils/blob/master/src/svg-path-utils.js */
  87.         let pathOperators = path.replace(/[\d,\-\s]+/g, '').split('');
  88.         let pathNums = path.replace(/[A-Za-z,]+/g, ' ').trim().replace(/\s\s+/g, ' ').split(' ');
  89.  
  90.         return `${pathOperators[0]} ${pathNums[4]} ${pathNums[5]} ${pathOperators[1]} ${pathNums[2]} ${pathNums[3]} ${pathNums[0]} ${pathNums[1]}`;
  91.     }
  92.  
  93.     // https://plainjs.com/javascript/manipulation/insert-an-element-after-or-before-another-32/
  94.     insertAfter(el, referenceNode) {
  95.         referenceNode.parentNode.insertBefore(el, referenceNode.nextSibling);
  96.     }
  97. }
  98.  
  99. let test = new Underliner(".underliner a", "url(#gradient)", "url(#gradient2)", 7, 12, "round", false);
  100.  
  101. let test2 = new Underliner(".underliner-small a", "url(#gradient)", "url(#gradient2)", 3, 6, "round");

Codepen 网址:https://codepen.io/shadeed/pen/OeNbMO

基于 SVG 的超链接鼠标悬停下划线动画特效

已有 535 人购买
  • yk8f
查看演示升级 VIP立刻购买

演示地址 下载地址
收藏
(1)

发表回复

热销模板

Ashade - 作品展示摄影相册WordPress汉化主题
LensNews

本站承接 WordPress / PbootCMS / DedeCMS 等
系统建站、仿站、开发、定制等业务!