突然「スマイルください」と言われたときの対策 ～ CSS 編 ～

*「スマイルください」*

笑顔を求めるその脅威は、突然私たちに襲い掛かる。
次の脅威はいつ、だれを襲うのか。予告なしに襲い掛かるその脅威から身を守り、被害を最小限に抑えるために、日頃から正しいスマイルの出し方を見につけておくことが重要である。

## 今回のスマイル :smiley:
今回作るスマイルはこのようなスマイル :smiley: で、原材料は CSS を使う。
また、本家スマイル[^1]が極めて安価( 0 円)で、提供までの時間が短いことをリスペクトして、スマイルを作るにあたり、以下の規則を設け、遵守した。

- 使用する要素は 1 つまで
- 擬似要素は利用しないことが好ましい
- 所要時間は 1 時間以内

## スマイル :smiley: の作り方

### HTML を書く

HTML は、上記の規則から`nico-chan`クラスを付与した`div`要素 1 つとした。

```HTML
<div class="nico-chan"></div>
```

### CSS を書く

まず、スマイル :smiley: をパーツごとに分割すると、円と楕円のみで構成されていることがわかる。円や楕円は、[`radial-gradient`関数](https://developer.mozilla.org/ja/docs/Web/CSS/radial-gradient)を使えば、描くことができる。

#### 顔を描く

[`radial-gradient`関数](https://developer.mozilla.org/ja/docs/Web/CSS/radial-gradient)を使って、顔の輪郭を作っていく([動作例](https://codepen.io/anon/pen/VRYrjO))。良い感じ。

```CSS
:root {
  --canvas-size: 300px;

  --face-inside-color: #ffcc4d;
  --face-outline-color: #ffcc4d;
  --face: radial-gradient(
      circle,
      var(--face-inside-color) 140px,
      var(--face-outline-color) 141px,
      var(--face-outline-color) 149px,
      transparent 150px
    )
    no-repeat;
}

.nico-chan {
  width: var(--canvas-size);
  height: var(--canvas-size);

  background: var(--face);
}
```

#### 目を描く

次に、目を作っていく([動作例](https://codepen.io/anon/pen/pYvdeW))。

```CSS
:root {
  --canvas-size: 300px;

  --eye-size: 17px;
  --eye: radial-gradient(
    11px 15px,
    #664500 calc(var(--eye-size) - 2px),
    transparent var(--eye-size)
  );

  --left-eye-position: 50px -50px;
  --right-eye-position: -50px -50px;

  --left-eye: var(--eye) var(--left-eye-position) no-repeat;
  --right-eye: var(--eye) var(--right-eye-position) no-repeat;

  --eyes: var(--left-eye), var(--right-eye);
}

.nico-chan {
  width: var(--canvas-size);
  height: var(--canvas-size);

  background: var(--eyes);
}
```

#### 口を描く
次に、口を描く。これは、円の上に楕円を重ねれば良い感じに作れると思う([動作例](https://codepen.io/anon/pen/zbxRRz))。

```CSS
:root {
  --canvas-size: 300px;

  --face-inner-color: #ffcc4d;

  --mouth-size: 35px;
  --mouth-color: #664500;
  --mouth-overlay: radial-gradient(
      2px 1px,
      var(--face-inner-color) 111px,
      transparent 113px
    )
    0 -50px no-repeat;
  --mouth: radial-gradient(var(--mouth-color) 90px, transparent 91px) 0 10px
    no-repeat;

  --teeth-size: 35px;
  --teeth-color: #fff;
  --teeth-overlay: radial-gradient(
      350px 100px,
      var(--mouth-color) 85px,
      transparent 87px
    )
    0 -10px no-repeat;
  --teeth: var(--teeth-overlay),
    radial-gradient(80px 60px, var(--teeth-color) 80px, transparent 81px) 0 -15px
      no-repeat;
}

.nico-chan {
  width: var(--canvas-size);
  height: var(--canvas-size);

  background: var(--mouth-overlay), var(--teeth), var(--mouth);
}
```

#### 作ったパーツを組み合わせる

上で作ったパーツを適当に組み合わせる。すると、 CSS は全体でこんな感じになる。ごちゃごちゃしていて読みにくいが、やっていることは円、楕円の作成と配置だけなので、それほど難しいことはしていない。
また、[`background-image`プロパティ](https://developer.mozilla.org/ja/docs/Web/CSS/background-image)をコンマ区切りで適用するとき、**最初に適用した値の結果が常に最前面に表示される[^2]**、という動作に注意しなければならない。

```CSS
:root {
  --canvas-size: 300px;

  --face-inner-color: #ffcc4d;
  --face-outline-color: #ffcc4d;
  --face: radial-gradient(
      circle,
      var(--face-inner-color) 140px,
      var(--face-outline-color) 141px,
      var(--face-outline-color) 149px,
      transparent 150px
    )
    no-repeat;

  --eye-size: 17px;
  --circle-eye: radial-gradient(
    11px 15px,
    #664500 calc(var(--eye-size) - 2px),
    transparent var(--eye-size)
  );
  --left-eye-position: 50px -50px;
  --right-eye-position: -50px -50px;
  --left-eye: var(--circle-eye) var(--left-eye-position) no-repeat;
  --right-eye: var(--circle-eye) var(--right-eye-position) no-repeat;
  --eyes: var(--left-eye), var(--right-eye);

  --mouth-size: 35px;
  --mouth-color: #664500;
  --mouth-overlay: radial-gradient(
      2px 1px,
      var(--face-inner-color) 111px,
      transparent 113px
    )
    0 -50px no-repeat;
  --mouth: radial-gradient(var(--mouth-color) 90px, transparent 91px) 0 10px
    no-repeat;

  --teeth-size: 35px;
  --teeth-color: #fff;
  --teeth-overlay: radial-gradient(
      350px 100px,
      var(--mouth-color) 85px,
      transparent 87px
    )
    0 -10px no-repeat;
  --teeth: var(--teeth-overlay),
    radial-gradient(80px 60px, var(--teeth-color) 80px, transparent 81px) 0 -15px
      no-repeat;
}

.nico-chan {
  width: var(--canvas-size);
  height: var(--canvas-size);

  background: var(--eyes), var(--mouth-overlay), var(--teeth), var(--mouth),
    var(--face);
}
```

### 完成

というわけで、完成したスマイルがこちら！

<p class="codepen" data-height="408" data-theme-id="dark" data-default-tab="result" data-user="hakaato" data-slug-hash="rRadjv" style="height: 408px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid black; margin: 1em 0; padding: 1em;" data-pen-title="Pure CSS Smiley Face">
  <span>See the Pen <a href="https://codepen.io/hakaato/pen/rRadjv/">
  Pure CSS Smiley Face</a> by Hakaato (<a href="https://codepen.io/hakaato">@hakaato</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

## まとめ

このスマイルを作るうえで使用したプロパティは、**実質 3 つだけ**(カスタムプロパティを除く)になった。このことからも、**連続的な色の変化を様々な形状で表現できることは強力**で、スタイルをより柔軟に適用できることがわかる。
また、CSS グラデーションはブラウザによって生成されるので、**ズーム表示された場合も割りと綺麗に表示される**のも Good ポイント。

CSS の場合、グラデーションさえあれば、スマイルは作れるのだ。もし道端で、突然スマイルを求められても、慌てず冷静にグラデーションを駆使すれば良い。グッドラック。

[^1]: http://www.mcdonalds.co.jp/
[^2]: [CSS Backgrounds and Borders Module Level 3 - §3.1. Layering Multiple Background Images](https://drafts.csswg.org/css-backgrounds-3/#layering)