JavaScript Morphing Keyboard

A morphing keyboard made using javascript and CSS. The keyboard has morphing animation along with click effect.

Made by Lucas Bebber.

Related Posts

The Html Code

<!DOCTYPE html>
<html lang="en" >
<head>
  <title>Morphing Keyboard</title>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css">
</head>
<body>
  <h1>Morphing Keyboard Keys (test)</h1>
<h2>
  Press and hold the shift key <br />
  or tap the shift key below
</h2>
<div class="keyboard"></div>
<br />
<a href="https://codepen.io/lbebber" target="_blank" class="credit">by Lucas Bebber</a>
  <script src='//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
</body>
</html>

The CSS Code

body {
  text-align: center;
  margin-top: 30px;
  font-family: 'Helvetica Neue', 'Helvetica', Arial, sans-serif;
  color: #111;
  background: #fff;
}
h1 {
  margin-bottom: 0;
}
h2 {
  font-weight: normal;
  margin-top: 5px;
}
.keyboard {
  text-align: left;
  display: inline-block;
  font-size: 30px;
}
.key {
  background: #eee;
  display: inline-block;
  min-width: 40px;
  height: 50px;
  line-height: 50px;
  vertical-align: top;
  margin-left: 2px;
  margin-right: 2px;
  margin-bottom: 4px;
  position: relative;
}
.key-shift {
  width: 70px;
  text-align: center;
  line-height: 50px;
  font-size: 0.6em;
  cursor: pointer;
  border: none;
  padding: 0;
  outline: none;
}
.key-shift-neverpressed {
  outline: 4px solid #59f !important;
}
.key-pressed {
  box-shadow: inset 0 4px 2px -2px rgba(0,0,0,0.4);
  background: #666;
  color: #fff;
}
.letter {
  position: absolute;
  width: 100%;
  height: 100%;
  line-height: 50px;
  text-align: center;
  transform-origin: 50% 80%;
  transition: opacity 45ms ease-out, transform 90ms ease-out;
}
.credit {
  display: inline-block;
  font-size: 0.8em;
  margin-top: 1em;
}

The JavaScript Code

$(document).ready(function () {
  var keyboard = [
  {
    offset: 20,
    keys: ['q', 'w', 'e', { letter: 'r', x: 0.4, y: 0.2 }, 't', 'y', 'u', { letter: 'i', x: 0, y: 0 }, 'o', 'p'] },

  {
    offset: 40,
    keys: ['a', 's', { letter: 'd', x: 0.2, y: 0 }, { letter: 'f', y: 0, x: 0.4 }, 'g', { letter: 'h', x: 0.2, y: 0 }, { letter: 'j', x: 0.6, y: 0 }, 'k', { letter: 'l', y: 0, x: 0.6 }] },

  {
    offset: 0,
    shift: true,
    keys: ['z', 'x', 'c', 'v', 'b', 'n', { letter: 'm', x: 0, y: 0.2 }] }];


  function renderKeyboard() {
    keyboard.forEach(function (row) {
      var $row = $("<div/>").
      addClass("key-row").
      css({
        marginLeft: row.offset + "px" }).

      appendTo(".keyboard");

      if (row.shift) {
        var $shift = $("<button/>").
        addClass("key key-shift key-shift-neverpressed").
        text("shift").
        appendTo($row);
      }
      row.keys.forEach(function (keyLetter) {
        var letter = keyLetter;
        var sxd = 0.2;
        var syd = 0.2;
        if (typeof keyLetter == "object") {
          letter = keyLetter.letter;
          sxd = typeof keyLetter.x == "number" ? keyLetter.x : sxd;
          syd = typeof keyLetter.y == "number" ? keyLetter.y : sxd;
        }
        var $key = $("<div/>").
        addClass("key key-letter").
        data("scale-x-delta", sxd).
        data("scale-y-delta", syd).
        attr("data-letter", letter).
        appendTo($row);



        var $lower = $("<div/>").
        addClass("letter letter-lowercase").
        text(letter).
        appendTo($key);

        var $upper = $("<div/>").
        addClass("letter letter-uppercase").
        text(letter.toUpperCase()).
        appendTo($key);
      });
    });
  }
  renderKeyboard();


  var keys = [];
  $(".key-letter").each(function (i) {

    var $key = $(this);
    var $upper = $key.children(".letter-uppercase");
    var $lower = $key.children(".letter-lowercase");
    var scaleXD = $key.data("scale-x-delta");
    var scaleYD = $key.data("scale-y-delta");
    var upperSX = 1 - scaleXD;
    var upperSY = 1 - scaleYD;
    var lowerSX = 1 + scaleXD;
    var lowerSY = 1 + scaleYD;

    function setKeyUpperCase() {
      $upper.css({
        transform: "scale(1,1) rotateY(0)",
        opacity: 1 });

      $lower.css({
        transform: "scale(" + lowerSX + "," + lowerSY + ") rotateY(0)",
        opacity: 0 });

    }

    function setKeyLowerCase() {
      $lower.css({
        transform: "scale(1,1) rotateY(0)",
        opacity: 1 });

      $upper.css({
        transform: "scale(" + upperSX + "," + upperSY + ") rotateY(0)",
        opacity: 0 });

    }

    /*var duration=92;
    var delay=i*1.5;
    $key.children(".letter").css({
      transitionDuration:(duration/2)+"ms, "+duration+"ms",
      transitionDelay:delay+"ms"
    });*/

    setKeyLowerCase();

    keys.push({
      key: $key,
      setLowerCase: setKeyLowerCase,
      setUpperCase: setKeyUpperCase });

  });

  function callForAllKeys(fName) {
    keys.forEach(function (key) {
      key[fName]();
    });
  }
  function setLowerCase() {
    callForAllKeys("setLowerCase");
  }
  function setUpperCase() {
    callForAllKeys("setUpperCase");
  }
  var shiftPressed = false;
  function shift() {
    shiftPressed = true;
    setUpperCase();
    $(".key-shift").addClass("key-pressed");
    $(".key-shift-neverpressed").removeClass("key-shift-neverpressed");
  }
  function unshift() {
    shiftPressed = false;
    setLowerCase();
    $(".key-shift").removeClass("key-pressed");
  }
  function toggleShift() {
    shiftPressed ? unshift() : shift();
  }
  $(document).keydown(function (event) {
    if (event.keyCode == 16) {
      shift();
    } else {
      var char = String.fromCharCode(event.keyCode);
      if (char != "") {
        $(".key-letter[data-letter=" + char.toLowerCase() + "]").addClass("key-pressed");
      }
    }
  });
  $(document).keyup(function (event) {
    if (event.keyCode == 16) {
      unshift();
    } else {
      var char = String.fromCharCode(event.keyCode);
      if (char != "") {
        $(".key-letter[data-letter=" + char.toLowerCase() + "]").removeClass("key-pressed");
      }
    }
  });
  $(".key-shift").click(function () {
    toggleShift();
  });


});

The Complete Code

<!DOCTYPE html>
<html lang="en" >
<head>
  <title>Morphing Keyboard</title>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css">
<style>
body {
  text-align: center;
  margin-top: 30px;
  font-family: 'Helvetica Neue', 'Helvetica', Arial, sans-serif;
  color: #111;
  background: #fff;
}
h1 {
  margin-bottom: 0;
}
h2 {
  font-weight: normal;
  margin-top: 5px;
}
.keyboard {
  text-align: left;
  display: inline-block;
  font-size: 30px;
}
.key {
  background: #eee;
  display: inline-block;
  min-width: 40px;
  height: 50px;
  line-height: 50px;
  vertical-align: top;
  margin-left: 2px;
  margin-right: 2px;
  margin-bottom: 4px;
  position: relative;
}
.key-shift {
  width: 70px;
  text-align: center;
  line-height: 50px;
  font-size: 0.6em;
  cursor: pointer;
  border: none;
  padding: 0;
  outline: none;
}
.key-shift-neverpressed {
  outline: 4px solid #59f !important;
}
.key-pressed {
  box-shadow: inset 0 4px 2px -2px rgba(0,0,0,0.4);
  background: #666;
  color: #fff;
}
.letter {
  position: absolute;
  width: 100%;
  height: 100%;
  line-height: 50px;
  text-align: center;
  transform-origin: 50% 80%;
  transition: opacity 45ms ease-out, transform 90ms ease-out;
}
.credit {
  display: inline-block;
  font-size: 0.8em;
  margin-top: 1em;
}
</style>
</head>
<body>
  <h1>Morphing Keyboard Keys (test)</h1>
<h2>
  Press and hold the shift key <br />
  or tap the shift key below
</h2>
<div class="keyboard"></div>
<br />
<a href="https://codepen.io/lbebber" target="_blank" class="credit">by Lucas Bebber</a>
  <script src='//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
      <script>
$(document).ready(function () {
  var keyboard = [
  {
    offset: 20,
    keys: ['q', 'w', 'e', { letter: 'r', x: 0.4, y: 0.2 }, 't', 'y', 'u', { letter: 'i', x: 0, y: 0 }, 'o', 'p'] },

  {
    offset: 40,
    keys: ['a', 's', { letter: 'd', x: 0.2, y: 0 }, { letter: 'f', y: 0, x: 0.4 }, 'g', { letter: 'h', x: 0.2, y: 0 }, { letter: 'j', x: 0.6, y: 0 }, 'k', { letter: 'l', y: 0, x: 0.6 }] },

  {
    offset: 0,
    shift: true,
    keys: ['z', 'x', 'c', 'v', 'b', 'n', { letter: 'm', x: 0, y: 0.2 }] }];


  function renderKeyboard() {
    keyboard.forEach(function (row) {
      var $row = $("<div/>").
      addClass("key-row").
      css({
        marginLeft: row.offset + "px" }).

      appendTo(".keyboard");

      if (row.shift) {
        var $shift = $("<button/>").
        addClass("key key-shift key-shift-neverpressed").
        text("shift").
        appendTo($row);
      }
      row.keys.forEach(function (keyLetter) {
        var letter = keyLetter;
        var sxd = 0.2;
        var syd = 0.2;
        if (typeof keyLetter == "object") {
          letter = keyLetter.letter;
          sxd = typeof keyLetter.x == "number" ? keyLetter.x : sxd;
          syd = typeof keyLetter.y == "number" ? keyLetter.y : sxd;
        }
        var $key = $("<div/>").
        addClass("key key-letter").
        data("scale-x-delta", sxd).
        data("scale-y-delta", syd).
        attr("data-letter", letter).
        appendTo($row);



        var $lower = $("<div/>").
        addClass("letter letter-lowercase").
        text(letter).
        appendTo($key);

        var $upper = $("<div/>").
        addClass("letter letter-uppercase").
        text(letter.toUpperCase()).
        appendTo($key);
      });
    });
  }
  renderKeyboard();


  var keys = [];
  $(".key-letter").each(function (i) {

    var $key = $(this);
    var $upper = $key.children(".letter-uppercase");
    var $lower = $key.children(".letter-lowercase");
    var scaleXD = $key.data("scale-x-delta");
    var scaleYD = $key.data("scale-y-delta");
    var upperSX = 1 - scaleXD;
    var upperSY = 1 - scaleYD;
    var lowerSX = 1 + scaleXD;
    var lowerSY = 1 + scaleYD;

    function setKeyUpperCase() {
      $upper.css({
        transform: "scale(1,1) rotateY(0)",
        opacity: 1 });

      $lower.css({
        transform: "scale(" + lowerSX + "," + lowerSY + ") rotateY(0)",
        opacity: 0 });

    }

    function setKeyLowerCase() {
      $lower.css({
        transform: "scale(1,1) rotateY(0)",
        opacity: 1 });

      $upper.css({
        transform: "scale(" + upperSX + "," + upperSY + ") rotateY(0)",
        opacity: 0 });

    }

    /*var duration=92;
    var delay=i*1.5;
    $key.children(".letter").css({
      transitionDuration:(duration/2)+"ms, "+duration+"ms",
      transitionDelay:delay+"ms"
    });*/

    setKeyLowerCase();

    keys.push({
      key: $key,
      setLowerCase: setKeyLowerCase,
      setUpperCase: setKeyUpperCase });

  });

  function callForAllKeys(fName) {
    keys.forEach(function (key) {
      key[fName]();
    });
  }
  function setLowerCase() {
    callForAllKeys("setLowerCase");
  }
  function setUpperCase() {
    callForAllKeys("setUpperCase");
  }
  var shiftPressed = false;
  function shift() {
    shiftPressed = true;
    setUpperCase();
    $(".key-shift").addClass("key-pressed");
    $(".key-shift-neverpressed").removeClass("key-shift-neverpressed");
  }
  function unshift() {
    shiftPressed = false;
    setLowerCase();
    $(".key-shift").removeClass("key-pressed");
  }
  function toggleShift() {
    shiftPressed ? unshift() : shift();
  }
  $(document).keydown(function (event) {
    if (event.keyCode == 16) {
      shift();
    } else {
      var char = String.fromCharCode(event.keyCode);
      if (char != "") {
        $(".key-letter[data-letter=" + char.toLowerCase() + "]").addClass("key-pressed");
      }
    }
  });
  $(document).keyup(function (event) {
    if (event.keyCode == 16) {
      unshift();
    } else {
      var char = String.fromCharCode(event.keyCode);
      if (char != "") {
        $(".key-letter[data-letter=" + char.toLowerCase() + "]").removeClass("key-pressed");
      }
    }
  });
  $(".key-shift").click(function () {
    toggleShift();
  });


});
    </script>
</body>
</html>