CSSとJavaScriptで作られた3 Dキーボード



このポストでは、キーボードを作成する例を共有します.
キーボードの作成中に、CSS変数、JSDOC記法、およびJavaScriptのビットを詳しく見ていきます.
CSS変数を使用すると、レイアウト定義内の値を定義、変更、および使用できます.
過去数年間、私は毎日TypeScriptを使用しています、そして、静的なタイプの安全なしでコードを開発するのは難しいです.しかし、JSDOCは代替として使用することができます.それはタイプではなくむしろヒントですが、純粋なJavaScriptプロジェクトでそれを試みる価値があります.
よくJavaScriptはJavaScriptです!では、始めましょう!

Demo files are available in this gist.


HTML


レイアウトは、できるだけ簡単です.
まず、CSS定義を含めましょう.
<!DOCTYPE html>
<html lang="en">
  <head>
    <link rel="stylesheet" type="text/css" href="keyboard.css" />
  </head>
</html>
次に、コンテナを定義し、スクリプト(抜粋)を含めましょう.
<!DOCTYPE html>
<html lang="en">
  <body>
    <div id="container"></div>
    <script src="keyboard.js"></script>
  </body>
</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>
    <link rel="stylesheet" type="text/css" href="keyboard.css" />
  </head>
  <body>
    <div id="container"></div>
    <script src="keyboard.js"></script>
  </body>
</html>

CSS


コア設定


キーボードを記述する基本的な設定は以下のように定義されています:
:root {
  /* keyboard width */
  --width: 1000px;
  /* keyboard height */
  --height: 420px;
  /* border radius */
  --radius: 5px;
  /* defines how high the button is raised */
  --depth: 5px;
  /* letter color */
  --color: yellow;
}
これらのパラメータのいずれかをtinkeringすることで、キーボード全体を構成することができますので、それは有用です.
たとえば、-カラー変数を再定義することにより、文字の色と輝くボタンのアクセント色を設定します.

見通し


それぞれの規則をコンテナに適用する必要があります.
#container {
  /* the perspective is equal to the initial keyboard width */
  perspective: var(--width);
}

Note that we have already started using the CSS variables.


キーボード


キーボードは、その目標は、JavascriptとCSSのスタイルでデータによって定義されるセクションを配布することです3 D回転平面です.
.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;
  /* 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.13turn) rotateY(0turn) rotateZ(0turn);
}
このクラスの幅と高さは、境界半径と同様にグローバル変数です.しかしパディングは計算されます.
calc(var(--radius) * 2)
また、フォントファミリーやグローバルマージンなどの基本要素のCSS規則を定義するのにも良い場所です.

オーバレイ


キーボードの外観を少しfancierするには、オーバーレイを追加しましょう.
.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);
}
オーバーレイは、キーボードの上部に輝く効果を追加します.これらのcss規則は効果を生んでいます.
/* adding a gradient background */
background-image: linear-gradient(to bottom, #ffffff33 0%, transparent 100%);
/* adding a noisy effect */
filter: blur(25px);

セクション


セクション要素の主な目的は、後でJavaScriptによって作成される均等な行を広げることです.
.section {
  /* spreading rows evenly */
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

This element is the weak point of the proposed solution, though you can adjust the width of the section by fiddle with CSS rules for the button. Another way is to change the number of buttons in each row.



行は均等にボタンを配布するように設計されます.
.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);
}

ボタン


最後に、ボタン.
魔法のほとんどはボタンで起こります.以下の規則のセットを見てください.
.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);
}
ここではCSS変数を再利用しています.まず、サイズ変数を計算します(ボタンの幅として設定されます).次に、我々は、次に、サイズ変数に依存する視点を計算している!
以下が抜粋です.
.button {
  /* setting the default dimensions of the button */
  --size: calc(var(--width) / 20);
  /* calculating the perspective from the width */
  perspective: calc(var(--size) * 3);
}
後で、Sizeの変数はボタンの特別なクラスの定義で変更されます.このように:
.button.space {
  --size: calc(var(--width) / 2.3);
}
デフォルトでは、すべてのボタンには左マージンがあります.
.button {
  /* adding the default margin */
  margin-left: calc(var(--width) / 200);
}
それで、キーボードをきれいにしておくために、我々は行の最初のボタンのためにマージンを無効にしなければなりません.
.button:first-child {
  /* reset margin for the leftmost button */
  margin-left: 0;
}
ボタンをボリュームの外観を確認するには、影を追加しましょう.
トリックは、ボタン要素がキーボードペインの上に上げられるということです.
.button {
  /* raising the button above the keyboard */
  transform: translate3d(0px, 0px, var(--depth));
}
それで、影は窓の上に直接置かれなければなりません.以下に定義を示します:
.button .shadow {
  /* centering the shadow */
  position: absolute;
  left: 50%;
  top: 50%;
  /* applying the transform */
  transform: translate3d(-50%, -50%, calc(var(--depth) * -1));
  background: #00000088;
}
したがって、キーボードは3 Dオブジェクトのように見えます.

Though this approach has drawbacks - from certain angles, it will be perfectly visible, that the buttons are just floating above the keyboard.


輝くボタン


あなたが気づくかもしれないが、私はMac/Windowsのロゴの代わりに個人的な輝くロゴを追加しました.
輝く効果は、テキストの影のルールによって作成されます.実装を見てみましょう.
/* 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);
}
色はグローバル変数セクション( Excerpt ):
:root {
  /* letter color */
  --color: yellow;
}
したがって、グローバルな色の変数を変更することにより、全体のキーボードの外観を変更することができます!

You can play with the color in the developer tools.


日本学術振興会


私がタイプスクリプトに慣れた前に、私は重さJSDoc表記を使いました.

JSDoc can't be used instead of TypeScript because it only hints about type of expected data.


このプロジェクトでは、いくつかの種類、関数の引数の型、および戻り値の型を定義しました.

構文


構文への小さな導入.
JSDOC定義のすべては標準的なマルチラインコメントに追加されなければなりません.
/**
 */
jsdocはタグで動作します.いくつかのタグはシングルですが、他のパラメータのリストを受け取ることができます.
例で説明しましょう.@ typedefタグはMyTypeというオブジェクトタイプを定義します.
/**
 * @typedef {Object} myType
 */
JSDOCタグの一部は、別のタグの一部として扱うことができます.ここでは@ propertyというタグは@ typedefタグの一部です.
/**
 * @typedef {Object} myType
 * @property {string} value the value
 */
JSDOCに関するもう一つのクールなことは、フィールドを任意に定義できるということです.名前を四角括弧でラップすることで実現できます.
/**
 * @typedef {Object} myType
 * @property {Object} [data] an optional data
 */
もう一つの柔軟性は、混合タイプを使用することによって達成されます.パラメタがいくつかの型でありえるならば、構文は以下のようになります
/**
 * @typedef {Object} myType
 * @property {string | string[]} list the list of items
 */
さて、使用したタイプを見てみましょう.

種類


まず、ボタンの値を記述するカスタムタイプを定義できます.次のようになります.
/**
 * @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
 */
したがって、この例では、キーの種類を定義しました.あとで、type []型のパラメーターキーにキー[]型を設定します.

上記のスクリーンショットからわかるように、キーパラメーターは、そのタイプを保持するだけでなく、説明.

戻り値の型


JSDOCは、戻り値の型を定義することもできます.以下に例を示します.
/**
 * create new div element
 * @returns {HTMLDivElement}
 */
function div() {
  return document.createElement('div');
}
関数が返す型によって、変数は扱います.

型付きパラメータ


また、JSDocは、関数のパラメーターの型を定義できます.
/**
 * 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(' ');
}
したがって、予想されるデータについてヒントを得ることができます.

Despite easiness and overall improvement of the code development process, I highly recommend using TypeScript for strict static type checks.


ジャバスクリプト


さて、レイアウトを作成し、CSSルールを定義し、宣言された型を作成したので、データといくつかの関数を追加するときです.
キーボードは2つのセクションがあります:メインと追加.それぞれのデータセットは対応するjsdocタグでタグ付けされます.
/**
 * the list of buttons of the additional section
 * @type {section[]}
 */
const additionalSection = [
  /* the data goes here */
];

You can review full declaration in the gist I've created.


さて、関数.
最初の関数は、文字列の配列をフィルター処理したり、空白記号で値の残りを結合したりするために使用されます.
function toString(values) {
  return values.filter(value => !!value).join(' ');
}
次の関数はラッパで、適切な型を取得するために使用します.
/**
 * create new div element
 * @returns {HTMLDivElement}
 */
function div() {
  return document.createElement('div');
}
最後の関数は初期データを解析し、すべての要素を構築し、CSSスタイルを適用します.
まず第一に、コンテナを見つけましょう.
const container = document.getElementById('container');
コンテナが存在するならば、要素を構築し始めましょう.
プロセスは単純です-ビルド要素、親要素に追加します.
コードはこのようになります(抜粋).
/**
 * 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';

    /* the rest of the logic */

    // appending the keyboard to the container
    container.appendChild(keyboard);
  }
}
上記のルーチンは、各要素の作成レベルごとにネストされます.
以下にその概要を示します.
create keyboard
  create section
    create row
      create button
      append a button to the row
    append a row to the section
  append a section to the keyboard
append a keyboard to the container

One more thing to be explained thoroughly is the rendering of buttons labels.

Do you remember that the parameter value of the type key has a mixed type?

/**
 * @property {string | string[]} value button label(s)
 */
レンダリング中に型チェックをスキップするには、値を配列に変換します
// turn any value into an array
const value = key.value instanceof Array ? key.value : [key.value];
// rendering labels
value.forEach(item => {
  const label = div();
  label.innerText = item || '';
  button.appendChild(label);
});

結論


提案の解は軽量で,簡単で,かつ柔軟である.
この例のデザインには欠点があります.
  • ボタンの容積図がエミュレートされるので、特定の角度から、それは完全に見えます、ボタンがちょうどキーボードより上に浮いているということです.
  • セクションの幅は内容によって定義される.このように、セクションはキーボードコンテナをあふれることができます.だから、すべての実装では、各行のサイズとボタンの数で再生する必要があります.
  • 垂直ボタンを定義する機能はありません.はい、利用可能な唯一のオプションは、異なる幅を設定することです.
  • してください、私はあまりにも厳しい私を判断しないでください-私は20分以内にこの例を作成したので、私はこの記事のカバーイメージを必要とした原因.


    更新


    このコメントの後

    Herbert Verdida
    github

    いいね.あなたがCodePenにそれを置くならば、それは良い考えです.
    私はペンを追加しました!
    私は、このペンがあなたが物事がどのように働いているかについて理解するのを援助することを望みます.
    また、paramsを使うことは簡単です.
    ハッピーハッキング!