グラデーションを簡単に生成する Web サービスを作る（ための前準備）


久しぶりの投稿です。

今回はグラデーションについてのお話です。



## TL;DR



「[ぼくのかんがえたさいきょうの配色Webサービスを公開した話](https://qiita.com/azukisiromochi/items/4d07e1b247baed01f11b) 」はたくさんの方に見ていただき感謝です！

今回も **色** に関する Web サービスを作ろうと思い、その準備段階で行なったことをまとめています。

<p class="codepen" data-height="550" data-theme-id="0" data-default-tab="result" data-user="azukisiromochi" data-slug-hash="NJZzLm" style="height: 550px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1em 0; padding: 1em;" data-pen-title="Gradation to you (proto)">
  <span>See the Pen <a href="https://codepen.io/azukisiromochi/pen/NJZzLm/">
  Gradation to you (proto)</a> by あずきしろもち (<a href="https://codepen.io/azukisiromochi">@azukisiromochi</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

今回はグラデーションを簡単に生成できる Web サービスを作ろうと考えていまして、そのメインとなるグラデーション生成部分を作成するのに利用した技術を中心に説明していきます。



## 機能の説明 :memo:

今回作ったのは

1. グラデーションのプライマリーカラーを12色から選んでもらう
2. プライマリーカラー（色相、彩度、明度を微妙に変化させてランダム要素あり）と別の色とのグラデーションをモーダルで表示する
3. モーダルのグラデーション部分をタップするとプライマリーカラーはそのままにグラデーションを再生成する

といった感じです。

完全ランダムでも良かったのですが、 **赤色ベースのグラデーションといった要望もあると思い、最初に1色選ぶ方式にしました** 。

ちなみに css 値などを返す機能はここでは用意していませせん。

（ Web サービス化したら付ける予定）



## 作ろうと思ったきっかけ :thinking: :thought_balloon:

前回のサービスもそうでしたが、単純に自分が使いたいものを作っています（笑）

色が好きな自分にとって配色を決めたり、グラデーションを決めたりするツールはいくらあっても困らないもので、それなら自分が使いやすいものを作ってしまおう――がきっかけです。



## UI :bento:

プライマリーカラーを選択するための12色分のエリアや、モーダルなどを作成するために利用した技術の紹介です。



### [Bulma](https://bulma.io/)

前回サービスを作成した際にも利用して使いやすかったので（ ~~味をしめたとも言う~~ ）、今回も Bulma を利用しています。



#### Columns

Bulma は Flexbox ベースの CSS フレームワークで、 `Columns` という機能を利用しました。

:link: [Column sizes | Bulma](https://bulma.io/documentation/columns/sizes/)

このページをぱっと眺めてもらえれば分かると思いますが、列操作が簡単なクラス指定でできてしまいます。

**画面全体を列12等分していると考えて、** `is-6` **と指定すれば画面半分の幅の列になりますし、** `is-4` **と指定すれば 1/3 幅の列になります** 。

今回のツールでは 4 つの `Column` を持つ `Columns` を  3 行分用意して 12 色の選択エリアを作成しました。



#### Modal

モーダルも Bulma の機能をそのまま利用しています。

**ただモーダルを** `is-active` **クラスで表示させるための制御は JavaScript で自分でしてねスタイルなので公式にサンプルコードとかは用意されてない** です（笑）



## Color :art:

12 色のプライマリーカラーやグラデーションの配色は CSS で行なっています。



### hsl()

CSS による色の表現は 16 進数カラーコードや RGB などが有名ですが、その一つに `hsl()` 表記があります。

色相（ **H**ue ）、彩度（ **S**aturation ）、明度（ **L**ightness ）のそれぞれの頭文字から名付けられたこの定義方法は、それら 3 つの要素を引数に指定することで色を表現することができます。

```css
/* hsl(H, S, L [, A]) */
background: hsl(30, 90%, 50%);
```



####  **H**ue

第一引数で色相を設定することができます。

色相は `0` から `360` の数値で表され、12色に分割すると次のようになります。

| 値   | 色         |
| ---- | ---------- |
| 0    | red        |
| 30   | orange     |
| 60   | yellow     |
| 90   | lime green |
| 120  | green      |
| 150  | blue green |
| 180  | cyan       |
| 210  | sky blue   |
| 240  | blue       |
| 270  | purple     |
| 300  | magenta    |
| 330  | pink       |

勘が良い人なら分かるかもしれませんが、この値は角度です。

**色相環上での色相の位置を角度で表しています** 。

`360` を超える数値や `0` よりも小さい数値の場合も利用は可能で、例えば `-60deg = 300deg = 660deg` のように解釈されます。



#### Saturation

第二引数で彩度を設定することができます。

**彩度とは色の鮮やかさのことで** `0%` **から** `100%` **の値を設定します** 。

`100%` が純色を表していて、 `0%` が灰色（無彩色）を表します。



#### Lightness

第三引数で明度（輝度と表現することもある）を設定することができます。

**明度は色の明るさのことで** `0%` **から** `100%` **の値を設定します** 。

彩度の場合とは異なり、純色を表すのは `50%` で `100%` に近づくほど明るく、ぎゃくに `0%` に近づくほど暗くなります。

結果的に `100%` では白（無彩色）になり、 `0%` では黒（無彩色）になります。



#### Alpha

第四引数は任意で不透明性を設定することができます。

`0` から `1` の少数値を設定します。

`0` は不透明度ゼロなので透過なしの状態と同様、`1` は不透明度 100% なので透明になります。

`0.5` など設定すると半透明な状態ですね。

（今回のツールでは利用していませんが）



## 仕様 :keyboard:

主にグラデーションを生成する部分の仕様を説明します。



### プライマリーカラーの決定

最初に 12 色から選んでもらうわけですが、 2 色グラデーションの 1 色を純色に近い色で固定してしまうのも面白くないので乱数を使って幅をもたせています。



#### 色相

30° きざみで別の色相になるので、色相値を `±15` の幅でランダムに決定しています。

例えば赤（ `0` ）を選択した場合は色相の値は `-15` ～ `+14` の何れかの数値をプライマリカラーの色相として利用しています。

`+15` はどこにいったの？と思われるかもしれませんが、

```javascript
Math.floor(Math.random() * (end - start)) + start
```

`Math.floor` を利用しているので 範囲の最大値である `+15` は含めずに乱数生成しています。

（含めると次の色相とかぶる範囲が出てしまいますしね :innocent: ）



#### 彩度

`20%` ～ `100%` の幅でランダムに決定しています。

無彩色やそれに近い色（灰色っぽい色）はくすんだ印象になってしまいます。

セカンダリーカラーでも無彩色が選択された場合、色相を選んでもらった意味がなくなってしまいますので、 `20%` よりも小さい値は対象外にしました。



#### 明度

`10%` ～ `90%` の幅でランダムに決定しています。

彩度の場合と同様に、無彩色（ここでは白と黒っぽい色）が選択された場合に色相を選んでもらった意味がなくなってしまいますので、上下 `10%` より小さい値は対象外にしました。



### セカンダリーカラーの決定

グラデーションのもう一つの色相も乱数を用いてランダムに決定しています。

基本的にはプライマリーカラーと同じですが、色相は仕様を変えています。

（色相も同じだと同一色相のグラデーションしか作れませんしね :innocent: ）



#### 色相

セカンダリーカラーに関しては `0` から `360` の幅でランダムに決定しています。

（ただし `360` は含まれない）

プライマリーカラーと同一色相は対象外にする仕様も考えましたが、類似色相でトーン違いのグラデーションにも綺麗なものがあるので、あえて完全にランダムにしています。



### グラデーションの生成

2 色が決定したら CSS の `linear-gradient()` を利用してグラデーションを生成しています。

その際にグラデーションの傾きをランダムに決定しています。



#### グラデーションの傾き

作成したツールを利用してもらうとわかりますが、タップするたびに生成されるグラデーションの傾き（色が交わる部分の角度と言えばよいのか……）が変わります。

`linear-gradient()` の引数でこの傾きが設定できるので、色相を決定するときと同じように乱数を用いて角度をランダムに決定しています。



#### 色の割合

グラデーションを生成する際に 2 色の色の割合を設定することができます。

例えば「赤： 90% 、紫： 10% 」といった感じで。

ここもランダムに決定する仕様を検討しましたが、タップを繰り返して好みのグラデーションを決定するツールではこの仕様でタップ回数が増えてしまい使い勝手が悪くなる可能性があるので実装していません。

グラデーションの幅と使い勝手を天秤にかけて今回は使い勝手を優先さた、ということです。



## フレームワーク :gear:

フレームワークといってもオンクリックのイベント、乱数の計算程度しか実装していませんのでなんでもよかったのですが、 Web サービス化する上で前回と同じ `Vue.js` ベースにしたかったので Vue を採用しています。



#### CodePen で利用する方法

特筆するほどの実装をしておらず書くこともないので、 CodePen で `Vue.js` を利用する方法を書いておきます（笑）



##### インクルード

「 **Settings**」ボタンを押すと次のようなウインドウが出てくるので、そこで「 **JavaScript** 」タブの「 **Add External Scripts/Pens** 」欄の検索エリアに `vue` と入力すると候補が出てきます。

![codepen-settings.png](https://qiita-image-store.s3.amazonaws.com/0/317946/e598baad-ab21-1ed8-1ab2-a1ff54f29b29.png)


候補に表示されている「 **vue** 」を選択すればインクルードが完了です。



##### 利用

実際に利用する場合は CodePen の「 **JS** 」エリアで

```javascript
Vue.config.devtools = true;

new Vue({
  el: '#app',
});
```

のように記述すれば OK です ❗

（あ、もちろん「 **HTML** 」エリアに `id="app"` の要素は必要ですよ～）



## まとめ

作りたいものを作っただけで技術的要素も少なく役に立たない記事かもしれませんが、 Web サービスなど最終形を目指す前に CodePen などで気軽にプロトタイプを作ったりするのもいいかもしれませんよ～的なまとめで締めさせていただきます。



また Web サービスが完成したら何らかの形で発信しますので興味のある方はまたどーぞ :yum: