口コミコンポーネントをdom一つで実現する


## はじめに

domの数が多くなるとCoreWebVitalsのパフォーマンス、TTI, TBTの数値が著しく低下します。特に口コミの星の周りのdomの数が多くなってしまったので、dom一つで実装しCoreWebVitalsの数値が向上したので記載します。

### step1 webフォントをサイトからダウンロードする

https://webdesign-trends.net/entry/11656
↑
おすすめのwebフォントのサイトが記載されているのでお好みのサービスを選んでください。今回は、Line Awesomeを選びました。

まず、サイトにアクセスするとDownload ZIPボタンが表示されているので、ボタンを押しください。
![Screen Shot 2022-07-09 at 12.53.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396152/f0f21f19-1270-1d3d-33cc-1d36b924c694.png)

zipファイルを解凍すると、下記のようなフォルダ構成になっていることが確認できると思います。/fonts以下にwebフォントのファイルが格納されています。今回は、la-solid-900.ttfを使いたいと思います。
![Screen Shot 2022-07-09 at 12.54.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396152/fc66be9a-f0c2-57b0-ab76-8519742305a9.png)

適当に作業用のディレクトリに格納してください。
![Screen Shot 2022-07-09 at 15.33.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396152/91b7511f-96cc-e926-a7e3-46f102c31efb.png)

### step2 @font-faceでWebフォントを利用できるようにします。

```
@font-face {
  font-family: 'Line Awesome Icons';
  font-style: normal;
  font-weight: 400;
  src: local('Line Awesome Icons'),
    // 先ほど、ダウンロードした.ttfファイルを指定してください。
    url(../lineAwesome/la-solid-900.ttf) format('truetype');
}
```

@font-faceを定義することでwebフォントを利用することができます。

```
.example::before {
  ...略
  // @font-faceで定義したfont-familyを使用することでweb フォントが使えます。
  font-family: 'Line Awesome Icons';
  // F005というのは、webフォントのスターアイコンのunicodeで、beforeもしくはafterの擬似要素にcontentで指定すればスターアイコンが表示されるようになります。
  content: '\F005\F005\F005\F005\F005';
}
```

iconのunicodeは、サイト内のアイコンをクリックすることで確認できます。
![Screen Shot 2022-07-09 at 12.55.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396152/6dac0f27-cbcb-9fa5-4bca-643c2d20b732.png)

もしくは、vscode内で確認することができます。
![Screen Shot 2022-07-09 at 15.46.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396152/6d39a346-4dcf-39b4-fe9e-822ab34e5469.png)



### step3 実装

完成図
![Screen Shot 2022-07-09 at 15.51.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396152/03d01106-4a48-b928-0a25-5571deff11d4.png)

![Screen Shot 2022-07-09 at 15.53.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396152/c4dbade4-fea3-5a99-55cb-70bf3583c4bc.png)


口コミコンポーネント
```
import React from 'react'

const ReviewPage = () => {
  // 口コミの評価によってCSSのクラス名を出し分けるために、objectで管理
  const reviewClassNameMap = {
    0: 'reviewRating-zero',
    0.5: 'reviewRating-zeroHalf',
    1: 'reviewRating-one',
    1.5: 'reviewRating-oneHalf',
    2: 'reviewRating-two',
    2.5: 'reviewRating-twoHalf',
    3: 'reviewRating-three',
    3.5: 'reviewRating-threeHalf',
    4: 'reviewRating-four',
    4.5: 'reviewRating-fourHalf',
    5: 'reviewRating-five',
    // @ts-expect-error
    [undefined]: 'reviewRating-zero',
  } as const
  
  // 口コミの評価を計算するロジック。
  const calcReviewRating = (rating: number) => {
    if (rating <= 0 || rating > 5) return 0
    const interger = Math.floor(Math.abs(rating)) as Extract<
      keyof typeof reviewClassNameMap,
      0 | 1 | 2 | 3 | 4 | 5
    >
    const diff = rating - interger
    // ex1. 4.4 => 4
    // ex2. 4.6 => 4.5
    return (interger +
      (diff >= 0.5 ? 0.5 : 0)) as keyof typeof reviewClassNameMap
  }

  const createReviewClassName = (rating: number) => {
    const calcedReviewRating = calcReviewRating(rating)
    return reviewClassNameMap[calcedReviewRating]
  }

  // ここが口コミコンポーネント
  return <i className={`reviewRating ${createReviewClassName(4.4)}`}></i>
}

export default ReviewPag
```

口コミのcss
```
@font-face {
  font-family: 'Line Awesome Icons';
  font-style: normal;
  font-weight: 400;
  src: local('Line Awesome Icons'),
    url(../lineAwesome/la-solid-900.ttf) format('truetype');
}
.reviewRating {
  display: block;
  position: relative;
}
// 口コミの星のグレー部分は、beforeに定義
.reviewRating::before {
  display: block;
  top: 0;
  left: 0;
  font-style: normal;
  position: absolute;
  color: #9e9e9e; // グレー色
  font-family: 'Line Awesome Icons';
  content: '\F005\F005\F005\F005\F005';
}
// 口コミの星のオレンジの部分は、afterに定義
.reviewRating::after {
  display: block;
  top: 0;
  left: 0;
  font-style: normal;
  position: absolute;
  color: #ffa000; // オレンジ色
  font-family: 'Line Awesome Icons';
}
// 口コミの評価が0の場合に表示するクラス
.reviewRating-zero::after {
  content: '';
}
// 口コミの評価が0.5の場合に表示するクラス
.reviewRating-zeroHalf::after {
  content: '\F089';
}
// 口コミの評価が1の場合に表示するクラス
.reviewRating-one::after {
  content: '\F005';
}
// 口コミの評価が1.5の場合に表示するクラス
.reviewRating-oneHalf::after {
  content: '\F005\F089';
}
// 口コミの評価が2の場合に表示するクラス
.reviewRating-two::after {
  content: '\F005\F005';
}
// 口コミの評価が2.5の場合に表示するクラス
.reviewRating-twoHalf::after {
  content: '\F005\F005\F089';
}
// 口コミの評価が3の場合に表示するクラス
.reviewRating-three::after {
  content: '\F005\F005\F005';
}
// 口コミの評価が3.5の場合に表示するクラス
.reviewRating-threeHalf::after {
  content: '\F005\F005\F005\F089';
}
// 口コミの評価が4の場合に表示するクラス
.reviewRating-four::after {
  content: '\F005\F005\F005\F005';
}
// 口コミの評価が4.5の場合に表示するクラス
.reviewRating-fourHalf::after {
  content: '\F005\F005\F005\F005\F089';
}
// 口コミの評価が5の場合に表示するクラス
.reviewRating-five::after {
  content: '\F005\F005\F005\F005\F005';
}

```

### おまけ サブセット化でwebフォントファイルのサイズを軽量化
226KBもあるので、ファイルの読み込みに時間がかかるので不要なフォントを削除するとよりパフォーマンスが向上します。
![Screen Shot 2022-07-09 at 16.03.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396152/7f147a0d-db5d-643b-2d88-6893c7276065.png)

ほんの一部しか表示していませんが、使ってないwebフォントまでよみこまれてしまっています。
![Screen Shot 2022-07-09 at 16.04.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396152/58055737-0463-eb79-217c-284d84d4d68c.png)

こちらからサブセットフォントメーカーをダウンロードしてください。
https://opentype.jp/subsetfontmk.htm

フォントに格納する文字に使用するwebフォントのunicodeを指定してください。
![Screen Shot 2022-07-09 at 16.10.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396152/85a23edd-ce68-965d-4f45-4d6c5735382a.png)


作成開始をしてみると...
不要なwebフォントは削除されていることが確認できると思います。
![Screen Shot 2022-07-09 at 16.10.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396152/e6b31834-6452-65fe-448e-83f35c448d68.png)


ファイルサイズも226KBから2KBに減っていることが確認できると思います。
![Screen Shot 2022-07-09 at 16.12.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396152/ef2c6b90-0e7a-86e8-87a4-e1d8ed2769f4.png)

## 最後に

今回は、Line Awesomeを使って説明しましたが、Font AwesomeでもGoogle Material Iconsでもできることを確認できたので他のwebサイトのwebフォントでも今回の記事の内容は実現できると思います。