サーバーサイドエンジニアも知っておくべきCSS

[SC（非公式）Advent Calendar 2017](https://qiita.com/advent-calendar/2017/syscon) の１２日目です。
普段サーバーサイドでC#を書いたり、SQLを書いたり、AzureのPOCとかをしています。
#はじめに
サーバーサイドエンジニアってデザイナさんが作ったHTML/CSSにロジックを足していくパターンが多いと思います。
.Netとかだと.Net MVCの場合はRazorなんかを使ってViewの表示を切り替えたりすると思います。
が、CSS3(CSS)を使用していると初見殺しのシンタックスが結構あるので、知っとくと便利なCSSを紹介したいと思います。

##レイアウト
下手にいじっちゃうと大惨事になるレイアウト周り。
サーバーサイドの人からすると、レイアウト関連のdivタグの使い方って神ですよね。
けど、ひと昔前までは職人(神)技だったけど、今はそれに近いことが、割と簡単にできるようになってきた（かも。。。）

###レイアウトサンプル
業務アプリでよく見るこんな感じのレイアウト
![image.png](https://qiita-image-store.s3.amazonaws.com/0/131619/07c75f8f-53d5-c47d-efd1-6f8a4fb50cc6.png)

###Flex Box　`display: flex`
[Can I Use](https://caniuse.com/#search=FlexBox)
主要ブラウザだと、IE11だけベンダープレフィックスを付ける必要があります。それ以外の主要ブラウザではサポートされています。
きっと普段みなさんが日常的にみているサイトのほとんどはFlexBoxを使用していると思います。
Flex Boxは**Flexコンテナー**という親要素と**Flexアイテム**で構成されます。
Flexコンテナーで囲った領域内のアイテムを縦に並べるのか、横に並べるのか、右からか、左からか、といったことを決めていきます。

さっきのサンプルをFlex Boxを使うとこんな感じ。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/131619/9dd7cb01-036a-714e-c040-2219fc5567c5.png)

```css:css
.container {
  display: flex;
  flex-direction: column;
}
.item {
  flex: 0 1 auto;
}
```
`flex-direction: column;`はアイテムを縦に
`flex-direction: row;`はアイテムを横(デフォルト左から右)に並べます。
`flex: 0 1 auto;`は`flex-grow:0`、`flex-shrink:1`、`flex-basis:auto`のショートハンド
さらに、Flexアイテム自体をFlexコンテナとして指定ができる。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/131619/7cd0aed2-4c48-f029-8199-82706b23bd78.png)

```css:css
.container {
  display: flex;
  flex-direction: column;
}
.item {
  display: flex;
  flex-direction: row;
  flex: 0 1 auto;
}
.side-menu {
  width: 30%;
  flex: 0 1 auto;
}
.main {
  width: 70%;
  flex: 0 1 auto;
}
```
![image.png](https://qiita-image-store.s3.amazonaws.com/0/131619/468edcd8-7669-2d25-fc80-5c29590ecb5c.png)

```css:css
.container {
  display: flex;
  flex-direction: column;
}
.item {
  display: flex;
  flex-direction: row;
  flex: 0 1 auto;
}
.side-menu {
  width: 30%;
  flex: 0 1 auto;
}
.main {
  display: flex;
  width: 70%;
  flex: 0 1 auto;
}
.search-area {
  height: 150px;
  flex: 0 1 auto;
}
.grid {
  height: 350px;
  flex: 0 1 auto;
}
```

こんな感じで**Flexコンテナ(display:flex)**と**Flexアイテム(flex:~)**をネストしてレイアウトを作っていきます。`float: left`みたいに、下に滑ることもないし、今は中身のコンテンツがないので、便宜上`width`や`height`を指定していますが、コンテンツがあれば、`width`や`height`指定なしでレイアウトを組むことができます。カッコいい:heart_eyes:

###Grid Layout
個人的にイチ押しのCSS Grid Layoutです。
[Can I Use](https://caniuse.com/#search=CSS%20Grid)
Edgeもベンダープレフィックスなしで使えるようになりました。IE11は相変わらずです。


`float: left`でレイアウトを作っていく場合も`display: flex`で作っていく場合も、並べたい`div`要素に対して、親要素でくくる必要がありましたが、GridLayoutは必要ありません。直観的(というかTableレイアウト的？)です。
とは言えContainerは必要です。
`display:grid`でContainerを定義して、`grid-template-columns`と`grid-template-rows`で列と行の境界を指定していきます。
まずは`display:grid`を指定してContainerを作ります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/131619/0d457bae-b487-7de1-d1f3-9b3d505bf662.png)

```html:html
<body>
  <div class="container">
    <div class="header"></div>
    <div class="side-menu"></div>
    <div class="search"></div>
    <div class="grid"></div>
  </div>
</body>
```

`grid-template-columns:～`で列の数・幅を
`grid-template-rows:～`で行の数・幅を決めていきます。

```css:css
.container {
  display: grid;
  grid-template-columns: 180px 1fr;
  grid-template-rows: 70px 70px 400px;
  background-color: #ddd
}
.header {
  grid-column: 1/3;
  grid-row: 1;
  border: 1px solid blue;
}
.side-menu {
  grid-column: 1;
  grid-row: 2/4;
  border: 1px solid orange;
}
.search {
  grid-column: 2;
  grid-row: 2/3;
  border: 1px solid red;
}
.grid {
  grid-column: 2;
  grid-row: 3/4;
  border: 1px solid red;
}
```
はい、これだけ。
HTMLを見ていただけるとわかりますが、余計なネストがないのがわかると思います。
なれるまでは、Gridテンプレートの指定の方法がいろいろあるので、苦戦するかもしれませんが、IE10以下の要件がなければ、かなり楽ができそうです。
React.jsやVue.jsのようなコンポーネントを配置する考え方と非常に相性がいいです。
ただ、Gridテンプレートの境界を超えるようなアニメーションとかは難しいです。

##Tips編
よくあるレイアウト修正のTipsの紹介

###line-height
よく見るけど、正確に仕様を把握している人が少なそうな`line-height`です。
`line-height`は行の高さを決めるプロパティですね。
基本的には`font-size`プロパティの大きさに対する比率で行の高さが決まります。
`line-height: 1`
`line-height: 16em`
`line-height: 100%`
のように色々な単位で指定できますが、子、孫のフォントサイズに対して、親要素の`line-height`が継承されてしまうため、単位をつけない方がいいとされています。

個人的には、超重要な属性だと思っていて、例えばよくある検索条件レイアウトで、ラベル、テキストボックス、ドロップダウンが並んでいる場合。

#####chrome
![image.png](https://qiita-image-store.s3.amazonaws.com/0/131619/b1165213-10b4-5bae-cdff-a77a4e0d4075.png)
#####IE11
![image.png](https://qiita-image-store.s3.amazonaws.com/0/131619/2220bfde-fc2e-f0ea-3b30-e7365b481716.png)
#####FireFox
![image.png](https://qiita-image-store.s3.amazonaws.com/0/131619/4be6c6f8-78d1-4740-ffe4-4e04bd88f12d.png)

```html:html
  <div class="container">
    <div class="item">
      <label for="name">名前：</label>  
    </div>
    <div class="item">
      <input type="text"></input>
    </div>
    <div class="item">
      <select name="aaa" id="">
        <option value="1">月曜</option>
        <option value="2">火曜</option>
        ・・・
      </select>
    </div>
  </div>
```

```css:css
.container {
  display: flex;
}
.item {
  flex: 0 1 auto;
}
```
すごく細かいですが、テキストボックスとドロップダウンの高さとか、Topの位置が違うのがわかると思います。
FlexBoxにはFlexアイテムを縦方向で中央寄せにする`align-items: center`プロパティがあるので、指定してみます。

#####chrome
![image.png](https://qiita-image-store.s3.amazonaws.com/0/131619/96f96f96-3e76-ab8b-31c3-d4945f33d52f.png)
#####IE11
![image.png](https://qiita-image-store.s3.amazonaws.com/0/131619/e9b11f9d-dbcc-5eab-0bbc-bbe432b7a8ef.png)
#####FireFox
![image.png](https://qiita-image-store.s3.amazonaws.com/0/131619/6670b9ff-bfcb-5b80-1246-21716055a968.png)

```css:css
.container {
  display: flex;
  align-items: center;
}
.item {
  flex: 0 1 auto;
}
```
FireFoxはいい感じになりました。
が、ブラウザ間で差異が出るので、`marrgin-top:○px`とかやりたくないですよね。
ここで、`line-height`の登場です。

```css:css
.container {
  display: flex;
  align-items: center;
  line-height: 1;
}
.item {
  flex: 0 1 auto;
}
```

親要素である、`.container`クラスに`line-height: 1`を追加してみます。

#####chrome
![image.png](https://qiita-image-store.s3.amazonaws.com/0/131619/a6b78261-d6ed-c30a-cee6-ac6a5c866fbf.png)
#####IE11
![image.png](https://qiita-image-store.s3.amazonaws.com/0/131619/7e2f9e4b-9ff2-fd2e-4a90-a2d19d8caf8c.png)
#####FireFox
![image.png](https://qiita-image-store.s3.amazonaws.com/0/131619/6758d9ba-22b8-0511-241f-97e9d2e340b4.png)

『ダイブいい感じー』になりました。
これは、ブラウザのuser-agent間の差異が原因で、reset.cssとか使ってればいいんですが、reset.cssでもほとんどのタグは`vertical-align:baseline;`に設定されていることが多いので、縦方向がうまくそろわないことがあります。
`vertical-align`、`margin`、`padding`あたりをいじりたくなる気持ちもわかりますが、`line-height`を試してみてください。

###text-overflow
`text-overflow`は指定した幅を超えてテキストが表示されるときに「・・・(3点リーダー)」に変換してくれるプロパティです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/131619/71834fb7-960f-acd0-9fc6-55f252aac0c4.png)
設計段階ではわからなかったけど、データをバインドしたら、予想以上にデータが長い。そういう時にgridの列幅を可変にする仕様追加や、ロジックで何文字以下とするのは**愚かな選択**です。その分テストの工数が増えるし、CSSで解決できることはCSSに任せちゃいましょう。(まぁデータの種類にもよりますが・・・)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/131619/4b4f4c68-77cb-c14c-dc4d-56b809133a9a.png)


```css:css
.text-overflow {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
```

#最後に
SPA（シングルページアプリケーション）の時代ですね。
サーバーサイドの役割も変わってきています。
MVCやMVVMが古いわけじゃないけど、ユーザーがもとめているものをより早くデリバリできる柔軟さが求められてきていると思います。
CSSやjavascriptで解決できるものはそちらに任せた方がいいものもあります。
ブラウザからDBまで、処理の重さや頻度、通信の速度、保守性、拡張性を加味して、最適なソリューションを実践していきたいです。
個人的には、プロジェクトでケースバイケースでClient/Server間の役割分担を決めていけばいいと思っていますが、最近は選択肢が多いのが逆に悩みのタネです。