您的当前位置:首页正文

互动河马按钮(interactive hippo button)

2024-11-25 来源:个人技术集锦

更多有趣示例 尽在

示例

HTML

<button>
  
<svg viewBox="0 0 242 109" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <g class="ears">
    <g class="ear-left">
      <ellipse class="ear-left-outer" transform="matrix(0.9391 -0.3436 0.3436 0.9391 -3.6062 17.8444)" cx="48.5" cy="19.1" rx="11.4" ry="13.8"/>
      <ellipse class="ear-left-inner" transform="matrix(0.9391 -0.3436 0.3436 0.9391 -3.8876 17.4659)" cx="47.3" cy="19.7" rx="7.3" ry="11.2"/>
    </g>
    <g class="ear-right">
      <ellipse class="ear-right-outer" transform="matrix(0.3436 -0.9391 0.9391 0.3436 106.5379 189.869)" cx="189.1" cy="18.7" rx="14.4" ry="11.9"/>
      <ellipse class="ear-right-inner" transform="matrix(0.3436 -0.9391 0.9391 0.3436 106.8522 191.5127)" cx="190.4" cy="19.3" rx="11.7" ry="7.7"/>
    </g>
  </g>
  <g class="eyes">
    <defs>
      <clipPath id="eyeRightClip">
        <path d="M175,25c0-11-7.8-20-17.5-20S140,14,140,25c0,0.7,0,1.3,0.1,2h34.8 C175,26.3,175,25.7,175,25z"/>
      </clipPath>
    </defs>
    <g class="eye-right">
      <path class="eye-right-outer" d="M174.9,27H186c0-0.3,0-0.7,0-1c0-14.4-11.6-26-26-26c-14.4,0-26,11.6-26,26 c0,0.3,0,0.7,0,1h6.1H174.9z"/>
      <path class="eye-right-inner" d="M175,25c0-11-7.8-20-17.5-20S140,14,140,25c0,0.7,0,1.3,0.1,2h34.8 C175,26.3,175,25.7,175,25z"/>
      <g clip-path="url(#eyeRightClip)">
        <circle class="eye-right-pupil" cx="158" cy="18" r="5"/>
      </g>
    </g>
    <defs>
      <clipPath id="eyeLeftClip">
        <path d="M97,25c0-11-7.8-20-17.5-20S62,14,62,25c0,0.7,0,1.3,0.1,2h34.8C97,26.3,97,25.7,97,25z" />
      </clipPath>
    </defs>
    <g class="eye-left">
      <path class="eye-left-outer" d="M96.9,27h6.1c0-0.3,0-0.7,0-1c0-14.4-11.6-26-26-26C62.6,0,51,11.6,51,26 c0,0.3,0,0.7,0,1h11.1H96.9z"/>
      <path class="eye-left-inner" d="M97,25c0-11-7.8-20-17.5-20S62,14,62,25c0,0.7,0,1.3,0.1,2h34.8C97,26.3,97,25.7,97,25z" />
      <g clip-path="url(#eyeLeftClip)">
        <circle class="eye-left-pupil" cx="80" cy="17.7" r="5"/>
      </g>
    </g>
  </g>
  <g class="nostrils">
    <g class="nostril-right">
      <ellipse class="nostril-right-outer" cx="130.5" cy="27.5" rx="6.5" ry="5.5"/>
      <circle class="nostril-right-inner" cx="130" cy="28" r="4"/>
    </g>
    <g class="nostril-left">
      <ellipse class="nostril-left-outer" cx="106.5" cy="27.5" rx="6.5" ry="5.5"/>
      <circle class="nostril-left-inner" cx="107" cy="28" r="4"/>
    </g>
  </g>
  <path class="body" d="M218,98H24C10.8,98,0,87.2,0,74V51c0-13.2,10.8-24,24-24h194c13.2,0,24,10.8,24,24v23 C242,87.2,231.2,98,218,98z"/>
  <g class="freckles">
    <circle class="freckle" cx="13.7" cy="41.4" r="1.6"/>
    <circle class="freckle" cx="20.1" cy="44.7" r="1.6"/>
    <circle class="freckle" cx="19.6" cy="37.8" r="1.6"/>
  </g>
  <defs>
    <clipPath id="mouthClip">
      <path d="M218,98H24C10.8,98,0,87.2,0,74V51c0-13.2,10.8-24,24-24h194c13.2,0,24,10.8,24,24v23 C242,87.2,231.2,98,218,98z"/>
    </clipPath>
  </defs>
  <g class="mouth" clip-path="url(#mouthClip)">
    <g class="mouth-pieces">
      <path class="mouth-back" d="M23.6,168.2l-3-56.1c0-7.8,6.4-14.1,14.1-14.1h172.4c7.8,0,14.1,6.4,14.1,14.1l-3,56.1"/>
      <path class="tongue" d="M174.9,168.2c-7.3-5-24.5-9.9-54.8-9.9s-48,5.1-54.8,9.9"/>
    </g>
  </g>
  <g class="teeth">
    <path class="tooth-left" d="M115,97.9v7.5c0,2-1.7,3.6-3.6,3.6H89.7c-2,0-3.6-1.7-3.6-3.6v-7.5H115z"/>
    <path class="tooth-right" d="M154,97.9v7.5c0,2-1.7,3.6-3.6,3.6h-21.7c-2,0-3.6-1.7-3.6-3.6v-7.5H154z"/>
  </g>
</svg>

</button>

<a target="_blank" href="https://codepen.io/MarioD/post/c76a53d9652de6ec9bf1217c1bea47e4/interactive-hippo-button-tutorial" class="link">Read / watch the tutorial</a>

CSS

html,
body {
  height: 100%;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body {
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #1e313f;
}

button {
  width: 242px;
  border: 0;
  padding: 0;
  background: transparent;
  cursor: pointer;
}

.ear-left-outer, .ear-right-outer {fill:#919191;}
.ear-left-inner, .ear-right-inner {fill:#6D6D6D;}
.eye-right-outer, .eye-left-outer, .nostril-right-outer, .nostril-left-outer, .body {fill:#AAAAAA;}
.eye-right-inner, .eye-left-inner {fill:#FFFFFF;}
.nostril-right-inner, .nostril-left-inner{fill:#8C8C8C;}
.freckle {fill:#7C7C7C;}
.tongue {fill:#FF4848;}
.tooth-left, .tooth-right {fill:#FFFFE1;}

.link {
  font-family: 'Roboto', sans-serif;
  font-weight: 400;
  font-size: 13px;
  color: #ffffe3;
  text-decoration: none;
  position: absolute;
  bottom: 20px;
  right: 20px;
  border: 2px solid #335067;
  padding: 10px 14px;
  border-radius: 4px;
  transition: background 0.2s;
}

.link:hover {
  background: #243a4a;
}

JS

// --------------
// Hover animaton
// --------------

const mouthSpeed = 0.3;
const easeType = Power2.easeOut;
const mouthOpen = gsap.timeline({ paused: true });
mouthOpen.to('.mouth-back', {duration: mouthSpeed, ease: easeType, y: -70}, 0);
mouthOpen.to('.tongue', {duration: mouthSpeed * 1.5, ease: easeType, y: -70}, 0);
mouthOpen.to('.teeth', {duration: mouthSpeed, ease: easeType, y: -70, scaleY: 1.2}, 0);
mouthOpen.to('.body', {duration: mouthSpeed, ease: easeType, scaleY: 1.06, transformOrigin: 'center bottom'}, 0);
mouthOpen.to('.freckles', {duration: mouthSpeed, ease: easeType, y: -10}, 0);
mouthOpen.to('.ears', {duration: mouthSpeed, ease: easeType, y: 6}, 0);
mouthOpen.to('.eye-right', {duration: mouthSpeed, ease: easeType, x: -2}, 0);
mouthOpen.to('.eye-left', {duration: mouthSpeed, ease: easeType, x: 2}, 0);
mouthOpen.to('.eyes', {duration: mouthSpeed, ease: easeType, y: 2}, 0);
mouthOpen.to('.nostrils', {duration: mouthSpeed, ease: easeType, y: -6}, 0);

// ------------
// Mouse events
// ------------

const button = document.querySelector('button');

button.addEventListener('mouseenter', enterButton);
button.addEventListener('mouseleave', leaveButton);

function enterButton() { mouthOpen.play(); }
function leaveButton() { mouthOpen.reverse(); }

// ----------
// Ear wiggle
// ----------

const earWiggle = gsap.timeline({ paused: true, repeat: 2 });
earWiggle.set('.ear-right', { transformOrigin: "center center" });
earWiggle.to('.ear-right', { duration: 0.1, rotation: 45 });
earWiggle.to('.ear-right', { duration: 0.1, rotation: 0 });

window.setInterval(earWigglePlay, 2500);

function earWigglePlay() { earWiggle.play(0); }

// ------------
// Eye tracking
// ------------

const eyeRightPupil = document.querySelector('.eye-right-pupil');
const eyeLeftPupil = document.querySelector('.eye-left-pupil');
const eyeLeftInner = document.querySelector('.eye-left-inner');
const innerEyeWidth = eyeLeftInner.getBoundingClientRect().width;
const innerEyeHeight = eyeLeftInner.getBoundingClientRect().height;
const pupilWidth = eyeLeftPupil.getBoundingClientRect().width;
const pupilHeight = eyeLeftPupil.getBoundingClientRect().height;
const xMovement = (innerEyeWidth - pupilWidth)/2;
const yMovement = (innerEyeHeight - pupilHeight)/2;

window.addEventListener('mousemove', updateEyePosition);

function updateEyePosition(event) {
  const posX = ((event.clientX / document.body.clientWidth) * 2 - 1) * xMovement;
  const posY = ((event.clientY / document.body.clientHeight) * 2 - 1) * yMovement;
  
  eyeLeftPupil.style.transform = `translate(${posX}px, ${posY}px)`;
  eyeRightPupil.style.transform = `translate(${posX}px, ${posY}px)`;
}

// Last minute link to the tutorial
button.addEventListener('click', () => window.open('https://codepen.io/MarioD/post/interactive-hippo-button-tutorial'));
显示全文