Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URLs added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Auto Save

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                
<h1>The spinning hexagonal click-spot show</h1>

<p>A furtherance to a click animation I saw a while back over on codrops.<br>Rewritten to remove library dependencies, added spin, et voila&hellip;</p>


<div class=grd_parent>
  <div class=grd-2>

    <article class=grd_itm id=a1>
      <a class=grd_lnk-small data-spot href="#a1" onclick="return false">
        <div class=grd_copy>Click me (link)</div>
      </a>
    </article>

    <article class=grd_itm>
      <button class=grd_btn-small data-spot>
        <div class=grd_copy>Click me (button)</div>
      </button>
    </article>

    <article class=grd_itm id=a2>
      <a class=grd_lnk data-spot href="#a2" onclick="return false">
        <div class=grd_copy>Click me (link)</div>
      </a>
    </article>

    <article class=grd_itm>
      <button class=grd_btn data-spot>
        <div class=grd_copy>Click me (button)</div>
      </button>
    </article>

  </div>
</div>

<p>As used on on my latest <a class=lnk title="[new window]" target=_blank href="https://websemantics.uk/">homepage</a> update.</p>



<svg style=display:none>
  <defs>
    <!-- method and matrix lifted from codrops (lost reference to original) -->
    <symbol id="spot-hexagon">
      <path d="M9.6 76.5L4 29 42.6.5l44 19L91.8 67 53.4 95.5l-44-19z"/>
    </symbol>
    <symbol id="spot-hexagons" viewbox="0 0 96 96">
      <use xlink:href="#spot-hexagon" opacity=".3"/>
      <use xlink:href="#spot-hexagon" opacity=".4" transform="matrix(.5 0 0 .5 25 25)"/>
      <use xlink:href="#spot-hexagon" opacity=".5" transform="matrix(.3 0 0 .3 36.3 36.3)"/>
    </symbol>
  </defs>
</svg>


<p>Not finding the original reference bugs me.<br>I'm pretty certain it was on <a title="[new window]" target=_blank href="https://tympanus.net/codrops/">codrops</a>.<br>Apologies to the originator.<br>If you know where it came from please add a comment.</p>
<p>Update 29/10/2020: There's a similar version in the CSS Tricks article: <a title="[new window]" target=_blank href="https://css-tricks.com/how-to-recreate-the-ripple-effect-of-material-design-buttons/">Recreate the ripple effect of Material Design buttons</a> with a full description on how to build.</p>




[[[https://codepen.io/2kool2/pen/mKeeGM]]]
              
            
!

CSS

              
                * {box-sizing: border-box;}
html {

  --textColor: hsl(269, 25%, 23%);
  --titleColor: hsl(269, 19%, 30%);

  --spacing-xlarge:   2.618rem;
  --spacing-large:    1.618rem;
  --spacing-medium:   1rem;
  --spacing-small:    0.618rem;
  --spacing-xsmall:   0.382rem;

  --fs1: 1.618rem; /* h1 */
  --fs2: 1.382rem; /* h2 */
  --fs3: 1.115rem; /* h3 */
  --fs4: 1rem; /* p */
  --fs5: .854rem; /* smaller */

  --lh1: 1.236; /* h1 */
  --lh2: 1.3; /* h2 */
  --lh3: 1.3; /* h3 */
  --lh4: 1.45; /* p */
  --lh5: 1.5; /* smaller */

  font-family: sans-serif;
  line-height: var(--lh4);
  color: #5a5a5a;
  background-color: #E9F0FB;
}
body {
  margin: 0;
  text-align: center;
}
h1 {
  font-size: var(--fs1);
  line-height: var(--lh1);
  font-weight: 100;
}
p {
  padding: var(--spacing-medium);
}
.lnk {text-decoration: none; border-bottom: 1px solid currentColor;}

/* The layout grid */

.grd_parent {
  --spacing: var(--spacing-medium);
  padding: var(--spacing);
}
[class^="grd-"] {
  --columns: 1fr;
  display: grid;
  grid-gap: var(--spacing);
  grid-template-columns: var(--columns);
}
@media (min-width: 40em) { /* 640px */
  [class^="grd-2"] {
    --columns: 1fr 1fr;
  }
}
[class^="grd_itm"] {
  border: 1px solid hsla(214, 71%, 47%, .15);
  padding: 0;
  min-width: 300px;
}


/* The link and button */
[class^="grd_btn"] {
  cursor: pointer;
  width: 100%;
  font-size: inherit;
}
[class^="grd_lnk"],
[class^="grd_btn"] {
  display: block;
  min-height: 15rem;
  position: relative;
  text-decoration: none;
  padding: 0.5rem;
  color: var(--textColor);
  border: 1px solid rgba(255,255,255,.7);
  background-color: rgba(225,255,235,.3);
  transition:
    box-shadow .3s ease,
    background-color .3s ease,
    transform .7s ease-in;
}
[class^="grd_lnk"]:hover,
[class^="grd_lnk"]:focus,
[class^="grd_btn"]:hover,
[class^="grd_btn"]:focus {
  color: inherit;
  outline: 0 solid;
  will-change: background-color, box-shadow, border-color;
  background-color: rgba(225,255,235,.6);
  box-shadow: 0 4px 4px hsla(269, 19%, 30%, .5);
  border-color: hsl(0, 0%, 99.8%);
}
[class^="grd_"][class*="-small"] {
  background-color: rgba(255,255,235,.4);
  min-height: 4rem;
}
[class^="grd_"][class*="-small"]:hover,
[class^="grd_"][class*="-small"]:focus {
  background-color: rgba(255,255,235,.6);
}



.grd_copy {
  text-transform: uppercase;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate3d(-50%, -50%, 0);
  color: hsl(214, 71%, 45%);
}



/* Hexagonal activation spot */

[data-spot] {
  position: relative;
  overflow: hidden;
}
[data-spot] * {
  pointer-events: none;
}
.spot-hex {
  display: block;
  position: absolute;
  overflow: hidden;
  transform: rotatez(0deg) scale(0);
  opacity: 1;
}
.spot-hex use {
  fill: hsl(214, 100%, 70%);
}
.spot_parent-clicked {
  box-shadow: 0 0 0 rgba(0,0,0,0) !important;
}
.spot-hex-on {
  will-change: opacity, transform;
  animation: spot-hex-open 1s linear;
}

@keyframes spot-hex-open {
  0% {
    opacity: 1;
    transform: rotatez(0deg) scale(.1);
  }
  100% {
    opacity: 0;
    transform: rotatez(60deg) scale(3);
  }
}
              
            
!

JS

              
                var supportsES6=function(){try{return new Function('(a = 0) => a'),!0}catch(n){return!1}}();


// Hexagonal spot click animation applied to objects with the attribute data-spot
// SVG hexagonal symbol (#spot-hexagons) needs to be defined in the HTML
// All children require pointer-events: none; to activate
// Updated 11/10/2019 to fall inline with my current coding style:
// - Recalculated the centre for keyboard users
(function () {

  'use strict';
  if (!supportsES6) return false;

  const cfg = {
    boxSelect : '[data-spot]',
    spotClass : 'spot-hex',
    spotOnClass : 'spot-hex-on',
    parentClickedClass : 'spot_parent-clicked',
    symbolId : '#spot-hexagons'
  };

  const _addSpotSvg = box => {
    const NS = 'http://www.w3.org/2000/svg';
    const svg = document.createElementNS(NS, 'svg');
    const use = document.createElementNS(NS, 'use');
    use.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', cfg.symbolId);
    svg.appendChild(use);
    svg.classList.add(cfg.spotClass);
    box.insertBefore(svg, box.firstChild);
  };

  const _setSpotStyle = (e, box, spot) => {

    const dia = Math.max(box.clientWidth, box.clientHeight);

    let offX = e.offsetX;
    let offY = e.offsetY;

    // Trying to remove the pointer-events:none requirement, but this offset calc is too inaccurate
    // if (e.currentTarget !== e.target) {
    //   offX += e.target.offsetLeft / 2;
    //   offY += e.target.offsetTop / 2;
    // }

    // Also aligns click point to the box centre when activated via keyboard
    let X = (offX === 0 ? (box.clientWidth / 2) : offX) - (dia / 2);
    let Y = (offY === 0 ? (box.clientHeight / 2) : offY) - (dia / 2);

    spot.setAttribute('style', `top: ${Y}px; left: ${X}px; height: ${dia}px; width: ${dia}px`);
  };

  const _setSpotClasses = spot => {
    requestAnimationFrame(_ => {
      spot.classList.add(cfg.spotOnClass);
      spot.parentElement.classList.add(cfg.parentClickedClass);
      spot.addEventListener('animationend', function(e){
        spot.classList.remove(cfg.spotOnClass);
        spot.parentElement.classList.remove(cfg.parentClickedClass);
      }, {once: true});
    });
  };

  const _activateSpot = (e, box) => {

    const spot = e.currentTarget.querySelector('.' + cfg.spotClass);
    if (!spot) return false;

    // Handle multiple activations
    spot.classList.remove(cfg.spotOnClass);

    _setSpotStyle(e, box, spot);
    _setSpotClasses(spot);

  };

  const _boxClicked = (e) => {

    // REQUIRES: all (box) children must have pointer-events:none
    const activationObj = e.target.querySelector('a') ||  e.target.querySelector('button');

    _activateSpot(e, e.target);

    if (activationObj) activationObj.click();

  };

  (_ => {
    const boxes = document.querySelectorAll(cfg.boxSelect);
    for (const box of boxes) {
      _addSpotSvg(box);
      box.addEventListener('click', _boxClicked);
    }
  })();

 }());

              
            
!
999px

Console