HTML + CSSでリアルなクッキーを作る

明日はホワイトデーということで、バレンタインのお返しにアイシングクッキーを作りました。クッキーといってもブラウザに保存するやつじゃないです。

<p class="codepen" data-height="455" data-theme-id="light" data-default-tab="result" data-user="Nishihara" data-slug-hash="yLNKaNw" style="height: 455px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Only HTML + CSS Cookie">
  <span>See the Pen <a href="https://codepen.io/Nishihara/pen/yLNKaNw">
  Only HTML + CSS Cookie</a> by Nishihara (<a href="https://codepen.io/Nishihara">@Nishihara</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

# 概要
丸が基本形なので、`border-radius: 50%`で円形を作り、`border`をつかって影やハイライトを作っています。目のハイライトには**クロソイド曲線を用いたグラデーション**を使っています。クッキーの複雑な表面を再現するのは難しかったのでアイシングクッキーにしました。

# 作り方
ここではスマイルのものを例に上げて説明していきます。

HTMLはクッキーの土台、アイシング部分、そして目、口、口角部分から構成されています。

```html
<div class="cookie smile">
  <div class="icing">
    <div class="eye eyeLeft"></div>
    <div class="eye eyeRight"></div>
    <div class="mouth">
      <div class="kokaku kokakuLeft"></div>
      <div class="kokaku kokakuRight"></div>
    </div>
  </div>
</div>
```

## クッキー部分
まずはクッキーの土台部分です。

```scss
.cookie {
  position: relative;
  width: 165px;
  height: 160px;
  margin: 12px;
  border-radius: 50%;
  border-right: 6px solid mix($cookieColor, #000, 75%);
  border-bottom: 6px solid mix($cookieColor, #000, 75%);
  box-shadow: 6px 5px 6px 3px mix(#000, mix($cookieColor, $bgColor, 50%), 10%),
    inset -5px -4px 3px 1px mix($cookieColor, #000, 80%);
  @include reverse-clothoid-radial-gradient(
    $color-start: $cookieColor,
    $color-end: mix($cookieColor, #000, 80%),
    $start-point: 0.85
  );
  &:after {
    content: "";
    display: block;
    width: 165px;
    height: 160px;
    position: absolute;
    top: 3px;
    left: 3px;
    border-radius: 50%;
    border-right: 1px solid mix($cookieColor, #000, 45%);
    border-bottom: 1px solid mix($cookieColor, #000, 45%);
    filter: blur(2px);
  }
}
```
![Screenshot_2020-03-12 Cookie(0).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463699/9d6aa794-f4ac-53ac-8530-aa8768163c82.png)
インクルードしている関数がありますが、これはグラデーションをつくるmixinです。本体はこうです。

```scss
/**
 * クロソイド曲線の放射状グラデーション
 */
@mixin reverse-clothoid-radial-gradient(
  $position: closest-side at center,
  $color-start: #000000,
  $color-end: #ffffff,
  $start-point: 0
) {
  background-image: radial-gradient(
    $position,
    $color-start 0 $start-point * 100%,
    mix($color-start, $color-end, 98.1%) $start-point * 100% +
      (1 - $start-point) * 12%,
    mix($color-start, $color-end, 96.3%) $start-point * 100% +
      (1 - $start-point) * 17.15%,
    mix($color-start, $color-end, 92.5%) $start-point * 100% +
      (1 - $start-point) * 24.5%,
    mix($color-start, $color-end, 85%) $start-point * 100% + (1 - $start-point) *
      35%,
    mix($color-start, $color-end, 70%) $start-point * 100% + (1 - $start-point) *
      50%,
    $color-end
  );
}
```
クロソイド曲線を使うとグラデーションの変化をいい感じに整えてくれます。このグラデーションについては拙筆[『1歩踏み込んでみる! CSSグラデーションのマニアックな世界』](https://ics.media/entry/200212/?utm_source=qiita&utm_medium=referral&utm_campaign=cookie)に詳しく書かれています。このmixinは`background-image`を出力しており、クッキーの色部分を担当しています。この部分だけ抜き出すとこんな感じです。
![Screenshot_2020-03-12 Cookie(1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463699/ba89671a-009a-f048-5903-e24f138f43d2.png)
いい感じに影がつきました。（`box-shadow`のinsetでも良かった気がする）
そこに`border-right`と`border-bottom`だけをつけることで右下側に厚みをもたせます。
![Screenshot_2020-03-12 Cookie(2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463699/5d3bb0b5-e6db-e608-5563-8655779cf3fe.png)
`box-shadow`や疑似要素で影を加えます。
![Screenshot_2020-03-12 Cookie(4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463699/f411b93b-c826-48d7-44fe-fdfc07206cb3.png)
これでクッキーの土台は完成

## アイシング
アイシング部分を作っていきます。

```scss
.icing {
  width: 153px;
  height: 150px;
  position: absolute;
  top: 5px;
  left: 5px;
  border-radius: 50%;
  @include reverse-clothoid-radial-gradient(
    $color-start: $icingColor,
    $color-end: mix($icingColor, #000, 80%),
    $start-point: 0.9
  );
}
```
クッキー部分と同じようにクロソイド曲線のグラデーションで色付けしています。
![Screenshot_2020-03-12 Cookie(5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463699/887ceef6-3359-d3ac-8b4e-627d388d88e5.png)
`after`疑似要素でハイライトをつけます。

```scss
&:after {
  content: "";
  width: 130px;
  height: 130px;
  border-radius: 50%;
  position: absolute;
  top: 5px;
  left: 10px;
  border-bottom: 6px solid mix($icingColor, #fff, 20%);
  transform: rotate(117deg);
  filter: blur(3px);
}
```
![Screenshot_2020-03-12 Cookie(6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463699/686fb5fd-4be9-5996-d10a-b53ec05b3584.png)
エッジ部分だけでなく、全体的な照り具合を加えます。

```scss
&:before {
  content: "";
  width: 140px;
  height: 140px;
  border-radius: 50%;
  position: absolute;
  top: 2px;
  left: 3px;
  @include clothoid-radial-gradient(
    $position: farthest-side at 65% 30%,
    $color-start: rgba(255, 255, 255, 0.6),
    $color-end: rgba(255, 255, 255, 0)
  );
  border-bottom: 6px solid mix($icingColor, #000, 80%);
  transform: rotate(-76deg);
  filter: blur(4px);
}
```
![Screenshot_2020-03-12 Cookie(7).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463699/19d73aba-efc3-41f3-3db7-7755d9db6366.png)
またここで先程のクロソイド曲線をグラデーションが役に立ちます。柔らかい変化を出せるのでほんのりと反射した表現ができます。

アイシング部分は完成です。

## おめめ
続いて目を作っていきます。

```scss
.eye {
  width: 12px;
  height: 24px;
  position: absolute;
  top: 40px;
  border-radius: 50%;
  background-color: $chocoColor;
  box-shadow: inset 0 0 2px 1px mix($chocoColor, #000, 80%),
    1px 0 2px 0 mix($icingColor, $chocoColor, 50%);
}
```
![Screenshot_2020-03-12 Cookie(8).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463699/a415a390-d5d5-dbf2-fdeb-b73d7e8c9ff7.png)
目の共通部分です。基本的には長方形を`border-radius: 50%`で楕円にし、わずかにシャドウ加えたものです。そこに擬似要素とクロソイド曲線グラデーションでハイライトをいれます。

```scss
&:after {
  content: "";
  display: block;
  width: 8px;
  height: 12px;
  position: absolute;
  top: 2px;
  left: 1px;
  @include clothoid-radial-gradient(
    $color-start: rgba(255, 255, 255, 0.8),
    $color-end: rgba(255, 255, 255, 0)
  );
}
```
![Screenshot_2020-03-12 Cookie(9).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463699/ec20f348-9529-3248-e7d9-2068d0657d88.png)
画竜点睛とは言いますが、目ができると、活きてきますね！

## 口
さいごに口の部分です。口は`border`を使って作り出しています。

```scss
.mouth {
  width: 80px;
  height: 80px;
  position: absolute;
  top: 32px;
  left: 30px;
  border-radius: 50%;
  border-left: 3px solid transparent;
  border-right: 3px solid transparent;
  border-bottom: 6px solid $chocoColor;
}
```
![Screenshot_2020-03-12 Cookie(10).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463699/90a70353-6e3e-b5a0-b819-ff888a5506c0.png)
`border`を左右下で設定していますが、左右の色は透明です。同じ色であれば4分の1の弧ができるはずですが、左右の`border`のカラーが透明なのでその中点、つまり45度の位置で終わります。こうすることで笑顔の口ができます。他のと同じように擬似要素でいい感じにシャドウとハイライトをつけます。

同様に口角部分も作ります。

```scss
.kokaku {
  width: 16px;
  height: 20px;
  border-radius: 50%;
  position: absolute;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-bottom: 4px solid $chocoColor;
  top: 51px;
  &Left {
    left: -12px;
    transform: rotate(-45deg);
    &:before {
      content: "";
      width: 16px;
      height: 20px;
      position: absolute;
      top: 4px;
      left: -2px;
      border-radius: 50%;
      border-left: 1px solid transparent;
      border-right: 1px solid transparent;
      border-bottom: 1px solid mix($chocoColor, $icingColor, 80%);
      filter: blur(1px);
    }
    &:after {
      content: "";
      width: 16px;
      height: 20px;
      position: absolute;
      top: 0;
      left: 1px;
      border-radius: 50%;
      border-left: 1px solid transparent;
      border-right: 1px solid transparent;
      border-bottom: 1px solid mix($chocoColor, #fff, 30%);
      filter: blur(1px);
    }
  }
  &Right {
    right: -12px;
    transform: rotate(45deg);
    &:before {
      content: "";
      width: 16px;
      height: 20px;
      position: absolute;
      top: -1px;
      left: 0;
      border-radius: 50%;
      border-left: 1px solid transparent;
      border-right: 1px solid transparent;
      border-bottom: 1px solid mix($chocoColor, $icingColor, 80%);
      filter: blur(1px);
    }
    &:after {
      content: "";
      width: 16px;
      height: 20px;
      position: absolute;
      top: 3px;
      left: -1px;
      border-radius: 50%;
      border-left: 1px solid transparent;
      border-right: 1px solid transparent;
      border-bottom: 1px solid mix($chocoColor, #fff, 30%);
      filter: blur(1px);
    }
  }
}
```
![Screenshot_2020-03-12 Cookie(11).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463699/fc272062-351b-602f-dd04-c8a179c6e7ff.png)

# 完成！
これでスマイルクッキーのできあがりです。サングラスやぴえんは似たような手法で展開しています。詳しくはCodePenのコードをご覧ください。
![Screenshot_2020-03-12 Cookie(12).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463699/9470c084-18fb-e46d-0c09-c2f428a22557.png)
**▼完成までGifアニメ**
![gif_anime.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/463699/7fb660f5-d9e9-99ed-4d7c-52fa84333f8c.gif)

# おわりに
あまり時間を掛けられなかった割にはキレイにできたのかなと思っています。やはり形がシンプルな方が作りやすいですね。