エンジニアの副業は週1からでも可能?副業の例や探し方も解説
- ITエンジニア
- 副業
色は、デザインの印象を大きく左右する重要な要素です。
組み合わせに成功すれば、デザインを想定以上の出来栄えにできますが、色を間違ってしまうとデザインを台無しにしてしまう危険性もあります。だからこそ、色選びで悩んでいるデザイナーは多いでしょう。
今回は、テキストエディタとWebブラウザという、プログラマーにとって使い慣れたツールを使って、印象的なカラーパレットをプログラム的に作る方法をご紹介します。
この記事は、HTML、CSS、JavaScriptの知識があると、理解しやすい内容になっています。
くわえてHSL(色相/彩度/輝度)とRGB(レッド/グリーン/ブルー)の知識があると、なお理解しやすいはずです。
Web上での創作活動に取り組むのが好きで、あらかじめ用意されている色や自動生成ツールを活用しているなら、この記事を参考にしてみてください。
本記事では、厳密に定義されたひとつのプロジェクトに取り組むわけではありません。
そのかわりに、美しいカラーパレットを作るのに最適な、3つのJavaScript関数の作りかたをご紹介します。
今回ご紹介する関数は、一度書けばカラーツールの基礎になります。複数のプロジェクトで繰り返し使用したり、カスタマイズしたりできるでしょう。
JavaScriptでできることとは?おすすめの学習方法を徹底解説
Workship MAGAZINE
今回のチュートリアルでは、ほぼLCHカラーのみを使用します。LCHとは、Light(明度)/Chroma(彩度)/Hue(色相)の頭文字を取ったもの。RGBやHSLと同様、色を表現する方法のひとつです。
RGBやHSLとの違いは、知覚的均一性と明度にあります。すこし難しい概念に思えるかもしれないので、ここからは図を使って解説します。
まず、この上下2組のHSLカラーを見てみましょう。
上の2色と下の2色のペアにおける色相差は、20と40、230と250で、どちらも20です。しかし、上の2色よりも、下の2色のほうが色が似たように見えますよね。
この違いの原因になっているのが、さきほど述べた、知覚的均一性です。HSLでは知覚的均一性が低いため、色相差が同じでも、色に差が生じてしまいます。
では、つぎにLCHカラーを使って同じ実験をしてみましょう。
HSLカラーと同様に、色相差を20にしました。色相の値は、HSLとLCHで完全に一致するわけではありません。しかしHSLに比べると、上2色と下2色のペアは、同じように色が変化しています。
LCHは知覚的均一性が高いため、色相が変化してもバランスが取れるのです。
つぎに、2種類の異なるHSLカラーを見てみましょう。
この2色の明度は同じですが、左の黄色は、右の青より、はるかに明るく見えるはずです。
では、同じような設定のLCHカラーを見てみましょう。
LCHカラーでは、明度が同じだと、同程度の明るさに見えます。
このように、LCHの均一な色相分布は、調和のとれたカラーパレットを作るときに、役立ちます。
チュートリアルではライブラリを使用しますが、LCHのネイティブサポートはブラウザにも搭載される予定です。Safariにはすでに搭載されており、他のブラウザも現在搭載に向けて取り組んでいます。
コードを書くまえに、簡単に開発環境を整えておきましょう。
『CodePen』を立ち上げ、必要に応じてカスタムセットアップ/リポジトリへの移行をおすすめします。
必要なのはHTML/JavaScriptファイルだけで、ライブラリのインポートにはSkypackを使用します。特別なビルドプロセスは必要ありません。
まずは、色彩理論に基づいた色相環からはじめましょう。
上の色相環は、LCHの色相を12色で表現しています。
ベースカラーを選んだあと、特定の角度にある色を選ぶという流れを繰り返して、さまざまな組み合わせを作ってみましょう。
補色パレットを作る場合は、対極の位置にある色を選びます。
3色を組み合わせた「トライアド」のパレットを作る場合は、ベースカラーから120度の位置にある色を2色選びます。
組み合わせを変えれば、さまざまなカラーパレットを作ることができます。
5種類のカラーパレットができました。
ここからは、いよいよコードを見ていきましょう。まずコードを提示してから、内容を詳しく説明します。
function adjustHue(val) {
if (val < 0) val += Math.ceil(-val / 360) * 360;
return val % 360;
}
function createScientificPalettes(baseColor) {
const targetHueSteps = {
analogous: [0, 30, 60],
triadic: [0, 120, 240],
tetradic: [0, 90, 180, 270],
complementary: [0, 180],
splitComplementary: [0, 150, 210]
};
const palettes = {};
for (const type of Object.keys(targetHueSteps)) {
palettes[type] = targetHueSteps[type].map((step) => ({
l: baseColor.l,
c: baseColor.c,
h: adjustHue(baseColor.h + step),
mode: "lch"
}));
}
return palettes;
}
createScientificPalettes
を定義し、baseColor
を引数として受け取るchroma
とlightness
の値がベース色と一致することを確認adjustHue
関数を使って、すべての色相値が0から360の間にあることを確認createScientificPalettes
関数を以下のように呼び出しましょう。
const baseColor = {
l: 50,
c: 100,
h: 0,
mode: "lch"
};
const palettes = createScientificPalettes(baseColor);
上の例では、baseColor
オブジェクトを渡すと、それを中心としたさまざまなパレットが返されます。
LCHカラーを使っているため、パレットの明度と色彩強度が視覚的に一貫しています。他の色空間と違い、色の知覚コントラストが同じなので、アクセシビリティも高いのが特徴です。
あとは、LCHカラーをより使いやすい形式に変換するだけ。チュートリアルで使われているカラーユーティリティライブラリ『Culori』を使えば、LCHオブジェクトをHEXなどに変換できます。
import { formatHex } from "https://cdn.skypack.dev/culori@2.0.0";
const baseColor = {
l: 50,
c: 100,
h: 0,
mode: "lch"
};
const palettes = createScientificPalettes(baseColor);
const triadicHex = palettes.triadic.map((colorLCH) => formatHex(colorLCH));
// ["#ff007c", "#1f8a00", "#0091ff"]
Culoriは、すべてのカラーオブジェクトに明示mode
を要求します。このチュートリアルのコード例からもわかるはずです。
最初の関数は、これで完了です。では、実際の使用例を見てみましょう。
カラーパレットをコード(プログラム)で作ることのメリットは、ラピッドプロトタイピングや実験が非常に簡単になることです。
たとえばデザインに取り組んでいて、どのカラーパレットを使うべきか完全に行き詰まってしまったとします。createScientificPalettes
関数と簡単なCSSカスタムプロパティを使えば、ほぼ無限にパレットを作り、リアルタイムでUIをテストできるのです。
CodePenによるデモを見てみましょう。
See the Pen Coloring With Code — Rapid Color Prototyping by George Francis (@georgedoescode) on CodePen.
現在、createScientificPalettes
関数は、単色を除くすべてのパレットタイプに対応しています。さらに挑戦してみたい場合は、単色パレットをサポートするようにアップデートしてみましょう。
クラシックな色の組み合わせを作るところまでは前回と同様ですが、今回は科学的に計算して色を選ぶのではなく、「発見」してみましょう。
色の配列を受け取り、その中から類似色、3色を組み合わせるトライアド、4色を組み合わせるテトラッドなど、最適なパレットを見つけます。以下はその図解です。
この機能を使えば、画像やカラーデータセットなどの中から美しいパレットを発見できます。では、その仕組みを掘り下げてみましょう。
import {
nearest,
differenceEuclidean,
} from "https://cdn.skypack.dev/culori@2.0.0";
function isColorEqual(c1, c2) {
return c1.h === c2.h && c1.l === c2.l && c1.c === c2.c;
}
function discoverPalettes(colors) {
const palettes = {};
for (const color of colors) {
const targetPalettes = createScientificPalettes(color);
for (const paletteType of Object.keys(targetPalettes)) {
const palette = [];
let variance = 0;
for (const targetColor of targetPalettes[paletteType]) {
// filter out colors already in the palette
const availableColors = colors.filter(
(color1) => !palette.some((color2) => isColorEqual(color1, color2))
);
const match = nearest(
availableColors,
differenceEuclidean("lch")
)(targetColor)[0];
variance += differenceEuclidean("lch")(targetColor, match);
palette.push(match);
}
if (!palettes[paletteType] || variance < palettes[paletteType].variance) {
palettes[paletteType] = {
colors: palette,
variance
};
}
}
}
return palettes;
}
discoverPalettes
関数に渡すcreateScientificPalettes
関数でその色に基づいた最適なターゲットパレットを作成するこの方法は、人間が色の選択肢を見て、最適なパレットを見つけるのと同じように動きます。数学的な色彩理論を当てはめるのではなく、予測不可能な部分を残した刺激的な方法です。
参考までに、HEXカラーの配列でdiscoverPalettes
を使う方法をご紹介します。
import {
converter,
} from "https://cdn.skypack.dev/culori@2.0.0";
const toLCH = converter("lch");
const baseColors = [
"#FFB97A",
"#FF957C",
"#FF727F",
"#FF5083",
"#F02F87",
"#C70084",
"#9A007F",
"#6A0076",
"#33006B"
];
const baseColorsLCH = baseColors.map((color) => toLCH(color));
const palettes = discoverPalettes(baseColorsLCH);
// { analogous: [...], complementary: [...], ... }
discoverPalettes
が正しく機能するためには、最低4色が必要です。
discoverPalettes
のもっとも魅力的な点のひとつは、あらゆるソースから首尾一貫した色の組み合わせを引き出すことができる点です。以下の例では、Unsplashの画像をもとにパレットを発見しています。
See the Pen Coloring With Code — Image Palette Extraction by George Francis (@georgedoescode) on CodePen.
discoverPalettes
を使って写真からパレットを抽出するという方法は、アイデアに行き詰まってしまったとき、役立ちます。このようなアプローチは、以前は魔法のようなカラージェネレーターやアプリをとおしてのみ可能でしたが、いまでは自分の好みにあわせて調整/改良可能です。
現在、discoverPalettes
には「色の配列から、もっともマッチするものを見つける」という機能があります。さらにチャレンジしたい場合は、「明るい色を優先する」といったヒエラルキーをつけてみましょう。
最後にご紹介するのは、ピクセルアートにヒントを得た方法です。
スプライトにシェードやハイライトを追加するとき、ピクセルアーティストは色の明度や彩度を調整するだけでなく、色相も変化させることがあります。以下がその例をあらわした図です。
色が明るくなると色相が上がり、色が暗くなると色相が下がります。このテクニックをさりげなく使うことで、色の濃淡が鮮やかになり、インパクトのある仕上がりを演出できます。すこし強めに色相を調整すれば、スタンドアローンのカラーパレットを魅力的に演出できるはずです。
function adjustHue(val) {
if (val < 0) val += Math.ceil(-val / 360) * 360;
return val % 360;
}
function map(n, start1, end1, start2, end2) {
return ((n - start1) / (end1 - start1)) * (end2 - start2) + start2;
}
function createHueShiftPalette(opts) {
const { base, minLightness, maxLightness, hueStep } = opts;
const palette = [base];
for (let i = 1; i < 5; i++) {
const hueDark = adjustHue(base.h - hueStep * i);
const hueLight = adjustHue(base.h + hueStep * i);
const lightnessDark = map(i, 0, 4, base.l, minLightness);
const lightnessLight = map(i, 0, 4, base.l, maxLightness);
const chroma = base.c;
palette.push({
l: lightnessDark,
c: chroma,
h: hueDark,
mode: "lch"
});
palette.unshift({
l: lightnessLight,
c: chroma,
h: hueLight,
mode: "lch"
});
}
return palette;
}
createHueShiftPalette
関数に、ベースカラー、最小/最大明度、色相ステップのパラメータを渡す。明度の最小/最大値は、パレットがどの程度暗く/明るくなるかを決定する。ステップの値は、各色で色相がどの程度シフトするかを制御するmap
を使って明度の値を計算し、hueStep
変数を使って色相を増減させる。ここでもadjustHue
が使われ、すべての色相が0から360の間にあることを確認するcreateHueShiftPalette
関数が定義されたら、以下のように使いましょう。
import { formatHex } from "https://cdn.skypack.dev/culori@2.0.0";
const hueShiftPalette = createHueShiftPalette({
base: {
l: 55,
c: 75,
h: 0,
mode: "lch"
},
minLightness: 10,
maxLightness: 90,
hueStep: 12
});
const hueShiftPaletteHex = hueShiftPalette.map((color) => formatHex(color));
// ["#ffb97a", "#ff957c", "#ff727f", "#ff5083", "#f02f87", "#c70084", "#9a007f", "#6a0076", "#33006b"]
createHueShiftPalette
で生成したパレットは、パターンやグラフィックにぴったりです。レンダリングするたびにすこしずつ変化する、ランダム/ジェネレーティブパターンの作成に使用した例を見てみましょう。
See the Pen Coloring With Code — Generative Hue Shift Patterns by George Francis (@georgedoescode) on CodePen.
このアプローチを活用すれば、つねに新鮮でユニークなUI要素を提供できます。
現在、createHueShiftPalett
関数では、明度/色相の値がリニアにスケールしています。さらにチャレンジしたい場合、イージングを適用して、色相のシフトを大きく/小さくし、各ステップでそれを増減させてみましょう。
今回は、カラーパレットを作るための関数を3種類ご紹介しました。関数そのものだけでなく、適用方法や改善点についても触れたので、ぜひプロジェクトのニーズにあわせて調整してみてください。
(執筆:George Francis 翻訳:Asuka Nakajima 編集:mozuku 提供元:codrops)