JSFiddle - React, Tailwind, and code Playground

by Kenneth Luplau-Brøgger

HTML

<div class="piano">
  <div class="octave">
    <div class="key"></div>
    <div class="key half"></div>
    <div class="key"></div>
    <div class="key half"></div>
    <div class="key"></div>
    <div class="key"></div>
    <div class="key half"></div>
    <div class="key"></div>
    <div class="key half"></div>
    <div class="key"></div>
    <div class="key half"></div>
    <div class="key"></div>
  </div>
  <div class="octave">
    <div class="key"></div>
    <div class="key half"></div>
    <div class="key"></div>
    <div class="key half"></div>
    <div class="key"></div>
    <div class="key"></div>
    <div class="key half"></div>
    <div class="key"></div>
    <div class="key half"></div>
    <div class="key"></div>
    <div class="key half"></div>
    <div class="key"></div>
  </div>
</div>

SCSS

:root {
  --keyWidth: 14.2857142857%;
  --halfNoteOffset: 33.3%;
}

.piano {
  font-size: 0;
  margin: 1rem auto 2rem auto;
  position: relative;
  white-space: nowrap;
}

.octave {
  position: relative;
  white-space: nowrap;
  width: 600px;
  height: 400px;
  display: inline-block;
  
  .key {
    font-size: 1rem;
    height: 100%;
    width: var(--keyWidth);
    display: inline-block;
    border-radius: 0 0 1rem 1rem;
    overflow: hidden;
    z-index: 2;
      box-shadow: 0 0.5rem 0.5rem rgba(0, 0, 0, 0.08), inset 0 0 2px rgba(0, 0, 0, 0.3), inset 0 -2rem 0 -0.5rem rgb(235, 235, 235);
    
    &:active {
      background: linear-gradient(180deg, rgba(250, 250, 250, 1) 0%, rgba(255, 255, 255, 1) 100%);
      transform-origin: 50% 0%;
      box-shadow: inset 0.1rem 0 1rem rgba(0, 0, 0, 0.1), inset 0 -1rem 0 -0.35rem rgb(230, 230, 230);
      z-index: 1;
    }
    
    &.half {
      position: absolute;
      background: black;
      height: 65%;
      vertical-align: top;
      width: calc(var(--keyWidth) * 0.6);
      box-shadow: 0.5rem 0.25rem 1rem rgba(0, 0, 0, 0.52), 0rem 0.25rem 0.15rem rgba(0, 0, 0, 0.2), inset 0 -1rem 0 0.3rem rgb(33, 33, 33);
      
      &::after {
        content: "";
        position: absolute;
        width: 80%;
        height: 1.3rem;
        left: 10%;
        bottom: 0;
        background: white;
        border-radius: 4rem;
        opacity: 0.08;
      }
      
      &:nth-of-type(2),
      &:nth-of-type(7){
        transform: translateX(calc(-100% + var(--halfNoteOffset)));
      }
      
      &:nth-of-type(4),
      &:nth-of-type(11) {
        transform: translateX(calc(var(--halfNoteOffset) * -1));
      }
      
      &:nth-of-type(9){
        transform: translateX(-50%);
      }
    
      &:active {
        background: linear-gradient(180deg, rgba(10, 10, 10, 1) 0%, rgba(0, 0, 0, 1) 100%);
        box-shadow: 0.5rem 0.25rem 0.5rem rgba(0, 0, 0, 0.2), 0rem 0.15rem 0.15rem rgba(0, 0, 0, 0.1), inset 0 -0.5rem 0 0.3rem...