🍣

clip-pathを応用しよう

2023/03/03に公開

以前、「clip-Pathを使って簡単なバナーを作る」
https://zenn.dev/ckoshien/articles/9cdf17bf142a89
という記事を書きましたが、それの第2弾です。

デザインを考える

何か良いデザインのものを作りたい

野球型競技のポータルサイトを作っているのですが、選手の成績が表組み(table)になっており、
グラデーションはかけているものの、やっぱりデザインに古さを感じてしまうので刷新したいと思っていました。

要素

これまでの構成要素は以下の通りでした。

  • 成績の数値(もしくは標準偏差などから求めた偏差値)
  • クラス帯を表現した色(若干のグラデーション)
  • クラス帯(S,A,B....)の文字列
  • 成績の項目名

まず目指すデザインをイメージする

当初イメージしていたのは、いにしえのアンテナピクト(3本)のようなデザインですが、
”階段 デザイン”、”ステータス デザイン”、”カード ゲーム ステータス デザイン”などのググり方をして最終的にたどり着いたのが”インジケーター デザイン”です。

グラデーションのあるインジケータ

このあたりでグラデーションを使ったアロー状のインジケータというイメージが固まりました。

コンポーネントを作る

今回作るコンポーネントでは

  • baseColor:基本色
  • value: 成績の値
  • title
  • borderNum: valueの境界値
  • deviation: 偏差値
  • classString: S, A, B, C...
  • fontColor

をPropにします。

5つアロー状の図形をclip-pathで実装し、marginを負にして間隔を詰めます。
アローの背景のグラデーションは1つ1つ割合を変えています。
基本色はクラス分けによって与える色を分けています。
deviationの値によってアローの背景を塗る数を変えています。

 <div
      style={{
        position: "relative",
        height: 50,
        width: 88,
        backgroundColor: '#4a4a4a',
        margin:1,
        padding:2
      }}
    >
      <div
        style={{
          display: "flex",
          position: "absolute",
          top: 10,
        }}
      >
        {[0, 1, 2, 3, 4].map((elm, idx) => (
          <div
            style={{
              width: 20,
              height: 30,
              marginLeft: idx !== 0 ? -5 : 0,
              background: 
              colorNum >= idx ? `linear-gradient(to bottom, ${baseColor} ${
                idx * 15
              }%, ${rotateColor(baseColor)})`: 'gray',
              clipPath:
                "polygon(50% 0%, 100% 50%, 50% 100%, 0% 100%, 50% 50%, 0 0)",
            }}
          ></div>
        ))}
      </div>
      <div
        style={{
          position: "absolute",
          top: 0,
          fontFamily: "Bebas Neue",
          color: 'white',
          textShadow: 'black 2px 2px 2px'
        }}
      >
        {title}
      </div>
      <div
        style={{
          position: "absolute",
          top: 23,
          right: 3,
          fontFamily: "corner stone",
          fontSize: 20,
          color: fontColor ?? 'white',
          textShadow: 'black 2px 2px 2px'
        }}
      >
        {value}
      </div>
      <div
        style={{
          position: "absolute",
          top: 25,
          left: 5,
          fontFamily: "corner stone",
          fontSize: 18,
          color: 'white',
          textShadow: 'black 2px 2px 2px'
        }}
      >
        {classString}
      </div>
    </div>

色相環を使う

今回、工夫した(挑戦した)ことはグラデーションを色相環を使って実装したことです。
基本色(baseColor)のみコンポーネントに与え、色相を30°ずらすことによって自然なグラデーションを表現できています。

chroma.js

色を操作する上で便利なのがchroma.jsです。
chromajsにはdarken(n) brighten(n)などの与えた色を暗くしたり明るくしたりするメソッドもあるのですが、今回の用途には向かなかったのでHSLの値を取り出して30度ずらす処理を実装します。

const rotateColor = useCallback((color) => {
    const angle = chroma(color).hsl()[0];
    return chroma.hsl(angle - 30, 1, 0.6).hex();
  }, []);
 const colorNum = useMemo(() => {
    return Math.floor(deviation - borderNum) + 1;
  }, []);

Discussion