Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ 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

Save Automatically?

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

              
                <!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <title>Keyboard</title>
</head>

<body>
  <div id="container"></div>
</body>

</html>
              
            
!

CSS

              
                :root {
  /* keyboard width */
  --width: 100vmin;
  /* keyboard height */
  --height: calc(var(--width) / 16 * 6.72);
  /* border radius */
  --radius: calc(var(--width) * 8 / 1600);
  /* defines how high the button is raised */
  --depth: 5px;
  /* letter color */
  --color: yellow;
  /* font size base */
  --fontSize: calc(var(--width)* 16 / 1000)
}
html,
body {
  width: 100%;
  height: 100%;
  margin: 0;
}
body {
  /* centering the content */
  display: flex;
  align-items: center;
  justify-content: center;
  /* adding a gradient background */
  background-image: linear-gradient(to bottom, hsl(225 25% 20%) 0%, hsl(225 40% 10%) 100%);
}
#container {
  /* the perspective is equal to the initial keyboard width */
  perspective: var(--width);
  outline: 1px solid white;
}
.keyboard {
  /* spreading sections evenly */
  display: flex;
  justify-content: space-between;
  /* setting the size */
  width: var(--width);
  height: var(--height);
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
  font-size: var(--fontSize);
  /* adding a gradient background */
  background-image: linear-gradient(to bottom, hsl(192 11% 53%) 0%, hsl(192 26% 43%) 100%);
  /* setting the border radius */
  border-radius: var(--radius);
  /* calculating paddings */
  padding: calc(var(--radius) * 2);
  box-sizing: border-box;
  /* enabling the 3d mode */
  transform-style: preserve-3d;
  /* applying the transform rule */
  transform: rotateX(0.08turn) rotateY(0.03turn) rotateZ(0turn);
}
.overlay {
  /* setting the size */
  width: var(--width);
  height: var(--height);
  /* centering the overlay */
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translateX(-50%) translateY(-50%) translateZ(10px);
  /* adding a gradient background */
  background-image: linear-gradient(to bottom, #ffffff33 0%, transparent 100%);
  /* adding a noisy effect */
  filter: blur(25px);
}
.section {
  /* spreading rows evenly */
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
.row {
  /* spreading buttons evenly */
  display: flex;
  justify-content: space-between;
}
.row.functions .button {
  /* calculating the height of the function button */
  height: calc(var(--height) / 10);
}
.row.actions .button,
.row.functions .button {
  /* calculating the width of the action and function buttons */
  --size: calc(var(--width) / 18);
}
.button {
  /* setting the default dimensions of the button */
  --size: calc(var(--width) / 20);
  height: calc(var(--height) / 7);
  width: var(--size);
  /* setting the border radius */
  border-radius: var(--radius);
  /* centering the content of the button */
  display: flex;
  justify-content: center;
  align-items: center;
  /* additional settings */
  box-sizing: border-box;
  background: #000000;
  /* applying the global color */
  color: var(--color);
  /* adding the default margin */
  margin-left: calc(var(--width) / 200);
  /* raising the button above the keyboard */
  transform: translate3d(0px, 0px, var(--depth));
  /* enabling the 3d mode */
  transform-style: preserve-3d;
  /* calculating the perspective from the width */
  perspective: calc(var(--size) * 3);
}
.button:first-child {
  /* reset margin for the leftmost button */
  margin-left: 0;
}
.button .shadow {
  /* centering the shadow */
  position: absolute;
  left: 50%;
  top: 50%;
  /* applying the transform */
  transform: translate3d(-50%, -50%, calc(var(--depth) * -1));
  background: #00000088;
}
.button.multi {
  /* placing labels under each other */
  flex-direction: column-reverse;
}
/* the next set of rules are buttons adjustments */
.button.backspace,
.button.tab {
  --size: calc(var(--width) / 13);
}
.button.backspace {
  font-size: calc(var(--fontSize) * 0.8)
}
.button.capslock,
.button.enter {
  --size: calc(var(--width) / 11);
}
.button.shift {
  --size: calc(var(--width) / 9);
}
.button.space {
  --size: calc(var(--width) / 2.3);
}
/* settings for the special button */
.button.dev {
  /* defining the accent color */
  --accent: #ffffff;
  color: var(--accent);
  /* adjusting letter spacing for the better readability */
  letter-spacing: 0.5px;
  /* adding the glow effect */
  text-shadow: 0 0 5px var(--accent), 0 0 10px var(--accent), 0 0 15px var(--accent), 0 0 20px var(--color), 0 0 30px var(--color),
    0 0 40px var(--color), 0 0 50px var(--color), 0 0 75px var(--color);
}
/* the empty button settings */
.button.empty {
  background: transparent;
}

              
            
!

JS

              
                /**
 * @typedef {Object} key
 * @property {string} [extra] extra class name
 * @property {string | string[]} value button label(s)
 */

/**
 * @typedef {Object} section
 * @property {string} [extra] extra class name
 * @property {key[]} keys set of keys in the row
 */

/**
 * the list of buttons of the main section
 * @type {section[]}
 */
const mainSection = [
  {
    extra: "functions",
    keys: [
      { value: "Esc" },
      { value: "F1" },
      { value: "F2" },
      { value: "F3" },
      { value: "F4" },
      { value: "F5" },
      { value: "F6" },
      { value: "F7" },
      { value: "F8" },
      { value: "F9" },
      { value: "F10" },
      { value: "F11" },
      { value: "F12" }
    ]
  },
  {
    keys: [
      { value: ["`", `~`] },
      { value: ["1", "!"] },
      { value: ["2", "@"] },
      { value: ["3", "#"] },
      { value: ["4", "$"] },
      { value: ["5", "%"] },
      { value: ["6", "^"] },
      { value: ["7", "&"] },
      { value: ["8", "*"] },
      { value: ["9", "("] },
      { value: ["0", ")"] },
      { value: ["-", "_"] },
      { value: ["=", "+"] },
      { value: "Backspace", extra: "backspace" }
    ]
  },
  {
    keys: [
      { value: "Tab", extra: "tab" },
      { value: "Q" },
      { value: "W" },
      { value: "E" },
      { value: "R" },
      { value: "T" },
      { value: "Y" },
      { value: "U" },
      { value: "I" },
      { value: "O" },
      { value: "P" },
      { value: ["[", "{"] },
      { value: ["]", "}"] },
      { value: ["\\", "|"] }
    ]
  },
  {
    keys: [
      { value: "Caps Lock", extra: "capslock" },
      { value: "A" },
      { value: "S" },
      { value: "D" },
      { value: "F" },
      { value: "G" },
      { value: "H" },
      { value: "J" },
      { value: "K" },
      { value: "L" },
      { value: [";", ":"] },
      { value: ["'", '"'] },
      { value: "Enter", extra: "enter" }
    ]
  },
  {
    keys: [
      { value: "Shift", extra: "shift" },
      { value: "Z" },
      { value: "X" },
      { value: "C" },
      { value: "V" },
      { value: "B" },
      { value: "N" },
      { value: "M" },
      { value: [",", "<"] },
      { value: [".", ">"] },
      { value: ["/", "?"] },
      { value: "Shift", extra: "shift" }
    ]
  },
  {
    keys: [
      { value: "Ctrl" },
      { value: "Fn" },
      { value: "[DEV]", extra: "dev" },
      { value: "Alt" },
      { value: "Space", extra: "space" },
      { value: "Alt" },
      { value: "Ctrl" }
    ]
  }
];

/**
 * the list of buttons of the additional section
 * @type {section[]}
 */
const additionalSection = [
  {
    extra: "functions",
    keys: [{ value: "PrtScr" }, { value: "ScrLk" }, { value: "Pause" }]
  },
  {
    extra: "actions",
    keys: [{ value: "Ins" }, { value: "Home" }, { value: "PgUp" }]
  },
  {
    extra: "actions",
    keys: [{ value: "Del" }, { value: "End" }, { value: "PgDn" }]
  },
  { extra: "actions", keys: [{ extra: "empty" }] },
  {
    extra: "actions",
    keys: [{ extra: "empty" }, { value: "\u2191" }, { extra: "empty" }]
  },
  {
    extra: "actions",
    keys: [{ value: "\u2190" }, { value: "\u2193" }, { value: "\u2192" }]
  }
];

/**
 * parse the array of strings and build a string from the values
 * @param {string[]} values values to be parsed
 * @returns {string}
 */
function toString(values) {
  return values.filter(value => !!value).join(" ");
}

/**
 * create new div element
 * @returns {HTMLDivElement}
 */
function div() {
  return document.createElement("div");
}

/**
 * draw a section
 * @param {section[][]} sections list of sections to be drawn
 */
function draw(sections) {
  // obtaining the container
  const container = document.getElementById("container");

  if (container) {
    // creating keyboard
    const keyboard = div();
    keyboard.className = "keyboard";
    sections.forEach(rows => {
      // creating section
      const section = div();
      section.className = "section";
      rows.forEach(data => {
        // creating row
        const row = div();
        row.className = toString(["row", data.extra]);
        if (data.keys instanceof Array) {
          data.keys.forEach(key => {
            // creating button
            const button = div();
            // creating shadow
            const shadow = div();
            const value = key.value instanceof Array ? key.value : [key.value];
            // setting classes
            button.className = toString([
              "button",
              key.extra,
              value.length > 1 ? "multi" : null
            ]);
            shadow.className = toString(["button", key.extra, "shadow"]);
            // appending the shadow
            button.appendChild(shadow);
            // rendering labels
            value.forEach(item => {
              const label = div();
              label.innerText = item || "";
              button.appendChild(label);
            });
            // appending the button to the row
            row.appendChild(button);
          });
        }
        // appending the row to the section
        section.appendChild(row);
      });
      // appending the section to the keyboard
      keyboard.appendChild(section);
    });

    // adding the overlay
    const overlay = div();
    overlay.className = "overlay";
    keyboard.appendChild(overlay);

    // appending the keyboard to the container
    container.appendChild(keyboard);
  }
}

/** draw the keyboard */
draw([mainSection, additionalSection]);

              
            
!
999px

Console