SPB Git

Repository Public

slider-emoji-mood.html 4.3 KB 107 lines html

1<!--2  ============================================================3  SVGarden — https://www.svgarden.dev4  Author : Simon-Pierre Boucher5  Contact: contact@spboucher.ai6  File   : snippets/interactive/slider-emoji-mood.html7  Desc   : Range slider morphing a face from sad to happy via one custom property8  ============================================================9-->10<!--svgarden11title: Emoji mood slider12slug: slider-emoji-mood13category: interactive14tags: [interactive, slider, emoji, custom-properties, js]15difficulty: advanced16techniques: ["calc()", "clamp()", custom-property-data-flow, scaleY-mouth-flip, "hsl()"]17how_it_works: >18  The script is a courier, not an animator: on input it copies the slider's19  value into one --sg-mood custom property on the root, and every visual20  response is derived from that number in CSS. The face tint is21  hsl(calc(mood × 1.2) …), sweeping the classic mood scale from cross red22  through neutral yellow to content green; the23  brows tilt through calc() wrapped in clamp() so they can't over-rotate. The24  mouth is the clever bit — one smile path scaled by25  scaleY(calc((mood − 50) / 50)), so 100 is a full smile, 0 is the same curve26  flipped into a frown, and 50 collapses it into a perfectly flat line —27  vector-effect="non-scaling-stroke" keeps that line visible, since transforms28  would otherwise squash the stroke to nothing along with the geometry.29  Transitions on transform and fill smooth every step.30customizable:31  - { var: "--sg-size",     label: "Size",       type: range, min: 90, max: 220, default: 140, unit: px }32  - { var: "--sg-duration", label: "Smoothness", type: range, min: 0.05, max: 0.8, step: 0.05, default: 0.25, unit: s }33created: 2026-08-1034-->35<div class="sg-slider-emoji-mood" style="--sg-size:140px; --sg-duration:0.25s; --sg-mood:50;">36  <svg viewBox="0 0 64 64" role="img" aria-label="Mood face">37    <title>Mood face</title>38    <circle class="sg-slider-emoji-mood-face" cx="32" cy="32" r="26" />39    <circle class="sg-slider-emoji-mood-pupil" cx="23" cy="27" r="2.8" />40    <circle class="sg-slider-emoji-mood-pupil" cx="41" cy="27" r="2.8" />41    <line class="sg-slider-emoji-mood-brow" x1="19" y1="19.5" x2="27" y2="19.5" />42    <line class="sg-slider-emoji-mood-brow" x1="37" y1="19.5" x2="45" y2="19.5" />43    <g class="sg-slider-emoji-mood-mouth">44      <path d="M22 41 Q 32 51 42 41" vector-effect="non-scaling-stroke" />45    </g>46  </svg>47  <input class="sg-slider-emoji-mood-slider" type="range" min="0" max="100" value="50" aria-label="Mood, 0 sad to 100 happy" />48</div>49<script>50  document.querySelectorAll('.sg-slider-emoji-mood:not([data-sg-init])').forEach(function (root) {51    root.setAttribute('data-sg-init', '');52    var slider = root.querySelector('.sg-slider-emoji-mood-slider');53    slider.addEventListener('input', function () {54      root.style.setProperty('--sg-mood', slider.value);55    });56  });57</script>58<style>59  .sg-slider-emoji-mood {60    width: var(--sg-size);61    display: flex;62    flex-direction: column;63    align-items: center;64    gap: 0.7rem;65  }66  .sg-slider-emoji-mood svg {67    display: block;68    width: 100%;69  }70  .sg-slider-emoji-mood-face {71    fill: hsl(calc(var(--sg-mood) * 1.2) 72% 62%);72    transition: fill var(--sg-duration) ease;73  }74  .sg-slider-emoji-mood-pupil {75    fill: rgba(25, 25, 35, 0.85);76  }77  .sg-slider-emoji-mood-brow {78    stroke: rgba(25, 25, 35, 0.85);79    stroke-width: 2.2;80    stroke-linecap: round;81    transform-box: fill-box;82    transform-origin: center;83    transition: transform var(--sg-duration) ease;84    transform: rotate(clamp(-14deg, calc((50 - var(--sg-mood)) * 0.28deg), 14deg));85  }86  .sg-slider-emoji-mood-brow:nth-of-type(2) {87    transform: rotate(clamp(-14deg, calc((var(--sg-mood) - 50) * 0.28deg), 14deg));88  }89  .sg-slider-emoji-mood-mouth {90    transform-box: fill-box;91    transform-origin: center;92    transition: transform var(--sg-duration) ease;93    /* +0.04 epsilon: a true scaleY(0) is a singular matrix and vanishes */94    transform: scaleY(calc((var(--sg-mood) - 50) / 50 + 0.04));95  }96  .sg-slider-emoji-mood-mouth path {97    fill: none;98    stroke: rgba(25, 25, 35, 0.85);99    stroke-width: 2.6;100    stroke-linecap: round;101  }102  .sg-slider-emoji-mood-slider {103    width: 90%;104    accent-color: hsl(calc(var(--sg-mood) * 1.2) 65% 48%);105  }106</style>107
Files main
Menu

Theme