大学ノート（ルーズリーフ）をモチーフとした手書きまとめノート風Webサイトを制作したときに使用したCSSテクニック

# **まとめノート風Webサイトを作ろうとしたきっかけ**

本当はWeb制作本を執筆してみたかったのですが、資金等の関係もあり、Web上でブログ形式で書いていこうと考えました。そこで困ったのがWebサイトのデザインでした。最近では、ほとんどのブログで**フラットデザイン**が使われていますね。Qiitaもその１つだと思います。フラットデザインとは、色に関していえば基本は白地や薄いグレー色で、その他1,2色をアクセント色としてデザインしているもののことですね。**比較的簡単に作れて、かつ見やすい**デザインなので重宝されていると思われます。

しかし、それではどこも同じような感じなので訪問者の頭に残りづらいと思うんです。そこで、思い出したのが今でもよく使っている**大学ノート(ルーズリーフ)**です。中学・高校時代はよく要点をまとめたまとめノートを作ったものです。ルーズリーフを使ったことがない人はいないと思うくらい、馴染み深いものだと思っています。そこで、ルーズリーフをモチーフにすることを決めました。

## **HTML5/CSS3の超教科書**

[実際に作成したWebサイト](http://prog.guide/html5-css3/2016/12/27/get-started-html5/)

こちらから実際にWebサイトを見ることができます。内容はHTML5/CSS3についての詳しい教科書のようなものを目指していますが、2016/12/27現在、上記リンクの記事は作成途中となっています(とりあえずデモ用)。2017年から本格的に執筆に入ります。

前置きが少し長くなってしまいましたが、本題のCSSテクニックについて紹介していきます。

# **重宝したCSSテクニックまとめ**

今回制作したWebサイトは**Internet Explorer 9**以上を対象としているため `flexbox` などは一切使っていません。その環境において使用したテクニックの紹介です。

## **1. Data URI スキーム**

Data URI スキームとは、詳しくは説明しませんが、

```
data:image/svg+xml;base64,.................
```

こんな感じで始まるもののことを言います。

### **1.1. メリット**

- HTTPリクエスト数を減らせる

### **1.2. デメリット**

- ファイルサイズが1.3倍程度に増える
- キャッシュが効かない

### **1.3. 使い分け**

**小さいサイズ**のパーツや、よく**使い回す**画像などに使用するとよいです。また、あとから変更のない画像に使うこともポイントですね。

## **2. ノートの罫線**

### **2.1. CSSグラデーションを使う**

![html5-css3-guide-tech-1.png](https://qiita-image-store.s3.amazonaws.com/0/151220/c647414b-01e1-0c12-b25b-e2f8c4d7cb8d.png)


```html
<p class="line">文章</p>
<p class="line">文章</p>
...
<p class="line">文章</p>
```

```css
.line {
  line-height: 35px;
  background: -webkit-linear-gradient(bottom, #000 1px, rgba(255, 255, 255, 0) 1px) left top / 1px 35px;
  background: linear-gradient(to top, #000 1px, rgba(255, 255, 255, 0) 1px) left top / 1px 35px;
}
```

**IE10以上**ならCSSグラデーションが使えるのでこのように書けます。行間は35pxとしています。

```css
.line {
  line-height: 35px;
  background: -webkit-linear-gradient(bottom, #000 1px, rgba(255, 255, 255, 0) 1px);
  background: linear-gradient(to top, #000 1px, rgba(255, 255, 255, 0) 1px);
  background-position: left top;
  background-size: 1px 35px;
}
```

**ショートハンド**を使わずに書くとこうですね。わざわざ `transparent` と書かずに `rgba(255, 255, 255, 0)` と書いているのは古いバージョンの**iOS Safari**でバグがあるからですね。

> 参考文献
[CSSで蛍光ペン風マーカーを指定したらiPhone上でtransparentの部分が黒くなってしまった話](https://nj-clucker.com/css-linear-gradient-not-use-transparent/)

### **2.2. svgを使う**

今回は**IE9**にも対応させたいので、svgを使いました。

```CSS
.line {
  line-height: 35px;
  background: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxIiBoZWlnaHQ9IjM1Ij48ZGVmcz48c3R5bGU+LmNscy0xe2ZpbGw6bm9uZTt9PC9zdHlsZT48L2RlZnM+PGcgaWQ9IuODrOOCpOODpOODvF8yIiBkYXRhLW5hbWU9IuODrOOCpOODpOODvCAyIj48ZyBpZD0i44Os44Kk44Ok44O8XzEtMiIgZGF0YS1uYW1lPSLjg6zjgqTjg6Tjg7wgMSI+PHBhdGggZD0iTTAgMzRoMXYxSDB6Ii8+PHBhdGggZD0iTTAgMGgxdjM0SDB6IiBjbGFzcz0iY2xzLTEiLz48L2c+PC9nPjwvc3ZnPg==);
}
```

1x35のsvg画像を**Data URI スキーム(Base64形式)**を使って設定しました。

### **2.3. 位置をずらす**

![html5-css3-guide-tech-2.png](https://qiita-image-store.s3.amazonaws.com/0/151220/d7b2d811-b43f-d917-3d19-f6fff9e2ef2f.png)

```css
.line {
  margin-top: -5px;
  padding-top: 5px;
  line-height: 35px;
  background: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxIiBoZWlnaHQ9IjM1Ij48ZGVmcz48c3R5bGU+LmNscy0xe2ZpbGw6bm9uZTt9PC9zdHlsZT48L2RlZnM+PGcgaWQ9IuODrOOCpOODpOODvF8yIiBkYXRhLW5hbWU9IuODrOOCpOODpOODvCAyIj48ZyBpZD0i44Os44Kk44Ok44O8XzEtMiIgZGF0YS1uYW1lPSLjg6zjgqTjg6Tjg7wgMSI+PHBhdGggZD0iTTAgMzRoMXYxSDB6Ii8+PHBhdGggZD0iTTAgMGgxdjM0SDB6IiBjbGFzcz0iY2xzLTEiLz48L2c+PC9nPjwvc3ZnPg==);
}
```

上に**5px**の `padding` をとることで文章を下よりに配置できます。そして、**ネガティブマージン**を設定することで、**5px分**戻しています。


## **3. table-cellを使った少し複雑なレイアウト**

![html5-css3-guide-tech-3.png](https://qiita-image-store.s3.amazonaws.com/0/151220/2533fdbb-31d5-6fb4-838c-cc4764c76161.png)

デモサイトのヘッダー部分です。サイトタイトル部分は**上下中央**に配置しつつ、日付のある部分は文字数に応じて**最小幅**で表示させたいというような場合にどうすればよいか。**上下中央**と**最小幅**というキーワードが来たら、`display: table-cell` を使います。

もしかすると勘違いしている方もいるかもしれませんが、`<table>` タグをレイアウト目的で使用するのがいけないのであって、CSSで `<table>` の機能をレイアウト目的で利用するのは全く問題ありません。

### **3.1. まずは上下中央に**

```html
<div class="container">
  <div class="title">サイトタイトル</div>
  <div class="info">#1<br>2016.12.27</div>
</div>
```

```css
.container {
  display: table;
  width: 100%;
}
.title, .info {
  display: table-cell;
}
.title {
  vertical-align: middle;  /* 上下中央 */
}
```

`table-cell` を使えばあっという間に**上下中央**ができてしまいます。これで、`.title` 部分の上下中央は実現できましたが、`.info` 部分の最小幅表示ができていません。

### **3.2. 最小幅にする**

```css
.container {
  display: table;
  width: 100%;
}
.title, .info {
  display: table-cell;
}
.title {
  vertical-align: middle;  /* 上下中央 */
}
.info {
  width: 1%;            /* 最小幅 */
  white-space: nowrap;  /* 改行させない */
}
```

少しCSSを加えてあげます。これで、`.info` は**最小幅**表示になります。ただし、注意しなければならないことがあって、`.info` 内で `float` を使って要素を**横並び**にさせると、`white-space: nowrap;` が効かないので、**最小幅になりません**。そんなときは、次項で説明する `inline-block` を用いた横並びを使用するといいでしょう。

## **4. inline-blockを使った横並びの際の隙間をなくす**

```html
<ul class="list">
  <li>...</li>
  <li>...</li>
</ul>
```

```css
.list li {
  display: inline-block;
}
```

こんな感じに書けば確かに横並びになりますが、`<li></li>` と `<li></li>` の間に僅かな隙間が空いてしまいます。

```css
.list {
  letter-spacing: -.5em;
}
.list li {
  display: inline-block;
  letter-spacing: normal;
}
```

そこで、`letter-spacing` を使った手法があります。`letter-spacing: normal;` を忘れないようにしましょう。

## **5. imgタグでsvg画像を表示させるとき**

今まであまりsvg画像を使ってこなかったので見事にハマりました。以下のことをしていないと**Internet Explorer**で思うようにサイズ調整ができなかったりします。

### **5.1. 前提として**

```html
<svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 90 32" width="90" height="32">
   ...
</svg>
```

`<svg>` タグに `viewbox` と `width/height` を指定することが必要です。**Adobe illustrator CC**では書き出した時に `width/height` が出力されないので注意が必要です。

### **5.2. IEだけサイズがフィットしない**

```html
<div class="svg">
  <img src="image.svg">
</div>
```

```CSS
.svg img {
  width: 100px;
}
```
このように書けば普通は横幅100pxとなりますが、**IEだけ**サイズが正しく表示されません。**前提として**で書いた `width/height` の大きさのまま表示されてしまうのです。

```CSS
.svg {
  width: 100px;
}
.svg img {
  width: 100%;
}
```

少しCSSを書き換えてあげます。親要素の `.svg` に幅を指定し、子要素の `<img>` には `100%` を指定します。これで正しく表示されます。**親要素に固定幅を指定**することを覚えておけば問題ないでしょう。

> 参考文献
[SVG with width/height doesn't scale on IE9/10/11 - Stack Overflow](http://stackoverflow.com/questions/27970520/svg-with-width-height-doesnt-scale-on-ie9-10-11)

## **6. 区切り文字を入れる**

![html5-css3-guide-tech-4.png](https://qiita-image-store.s3.amazonaws.com/0/151220/a81d5db0-4486-2c2f-0cef-5979230ed9bd.png)

日付部分の間の点です。**Bootstrap**では、パンくずリストなどで使われている手法ですね。

### **6.1. 日付を/で区切る**

```html
<!-- 2016/12/27 -->

<div class="date">
  <span>2016</span>
  <span>12</span>
  <span>27</span>
</div>
```

```css
.date {
  letter-spacing: -.5em;
}
.date span {
  display: inline-block;
  letter-spacing: normal;
}
.date span + span::before {
  content: '/';  /* /で区切る */
}
```

**4項**で説明した横並びを使っています。`+` は**隣接セレクタ**といって、1つ隣のタグを指定するときに使います。**1つ隣**なので、最初の `<span>` タグ以外が選択されます。

```css
/*  2016 / 12 / 27  */

.date span + span::before {
  padding: 0 2em;
  content: '/';
}
```

もちろん `padding` を指定すれば `/` の左右の間隔を調整できます。


### **6.2. 日付を画像で区切る**

```css
.date {
  letter-spacing: -.5em;
}
.date span {
  display: inline-block;
  letter-spacing: normal;
}
.date span + span::before {
  padding-left: 1em;
  content: '';
  background: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzIiBoZWlnaHQ9IjMiPjxkZWZzPjxzdHlsZT4uY2xzLTF7ZmlsbDojOTRhZmQ3O308L3N0eWxlPjwvZGVmcz48ZyBpZD0i44Os44Kk44Ok44O8XzIiIGRhdGEtbmFtZT0i44Os44Kk44Ok44O8IDIiPjxjaXJjbGUgaWQ9IuODrOOCpOODpOODvF8xLTIiIGN4PSIxLjUiIGN5PSIxLjUiIHI9IjEuNSIgY2xhc3M9ImNscy0xIiBkYXRhLW5hbWU9IuODrOOCpOODpOODvCAxIi8+PC9nPjwvc3ZnPg==) center no-repeat;
}
```

例のごとく**Data URI スキーム**を使っています。`padding-left` の値が横幅となるので状況に応じて調整します。また、背景画像なので、`background-size` の `cover` や `contain` など便利な機能が使えます。

## **7. 見出しの連番**

### **7.1. counter()関数**

```html
<h2>見出し</h2>      <!-- 1     -->
  <h3>見出し</h3>    <!-- 1.1   -->
    <h4>見出し</h4>  <!-- 1.1.1 -->
    <h4>見出し</h4>  <!-- 1.1.2 -->
<h2>見出し</h2>      <!-- 2     -->
  <h3>見出し</h3>    <!-- 2.1   -->
    <h4>見出し</h4>  <!-- 2.1.1 -->
  <h3>見出し</h3>    <!-- 2.2   -->
    <h4>見出し</h4>  <!-- 2.2.1 -->
    <h4>見出し</h4>  <!-- 2.2.2 -->
<h2>見出し</h2>      <!-- 3     -->
  <h3>見出し</h3>    <!-- 3.1   -->
```

```css
h2 {
  counter-increment: count-h2;
  counter-reset: count-h3;
}
h2::before {
  content: counter(count-h2);
}
h3 {
  counter-increment: count-h3;
  counter-reset: count-h4;
}
h3::before {
  content: counter(count-h2)'.'counter(count-h3);
}
h4 {
  counter-increment: count-h4;
}
h4::before {
  content: counter(count-h2)'.'counter(count-h3)'.'counter(count-h4);
}
```

```counter()``` 関数をつかえば簡単に連番見出しを作ることができます。

```html
<h2>見出し</h2>  <!-- 01 -->
<h2>見出し</h2>  <!-- 02 -->
<h2>見出し</h2>  <!-- 03 -->
```

```css
h2 {
  counter-increment: count-h2;
}
h2::before {
  content: counter(count-h2, decimal-leading-zero);
}
```

意外と知られていませんが、`counter()` 関数には**第2引数**もあり、`list-style-type` を指定できます。例えば、`decimal-leading-zero` を指定すると**ゼロパディング**できます。

> list-style-type一覧
[https://developer.mozilla.org/ja/docs/Web/CSS/list-style-type](https://developer.mozilla.org/ja/docs/Web/CSS/list-style-type)

### **7.2. counters()関数**

```html
<ol>
  <li>item</li>          <!-- 1     -->
  <li>item               <!-- 2     -->
    <ol>
      <li>item</li>      <!-- 2.1   -->
      <li>item</li>      <!-- 2.2   -->
      <li>item           <!-- 2.3   -->
        <ol>
          <li>item</li>  <!-- 2.3.1 -->
        </ol>
        <ol>
          <li>item</li>  <!-- 2.3.1 -->
          <li>item</li>  <!-- 2.3.2 -->
        </ol>
      </li>
      <li>item</li>      <!-- 2.4   -->
    </ol>
  </li>
  <li>item</li>          <!-- 3     -->
  <li>item</li>          <!-- 4     -->
</ol>
<ol>
  <li>item</li>          <!-- 1     -->
  <li>item</li>          <!-- 2     -->
</ol>
```

HTMLがこんな感じで**規則的にネストされている**場合、いちいち `counter-increment` して `counter-reset` して、と書く必要はありません。

```css
ol {
  counter-reset: count-li;
}
li:before {
  counter-increment: count-li;
  content: counters(count-li, '.');
}
```

たったこれだけで済みます。また、`counter()` 関数と同じように `list-style-type` を指定できます。

```css
ol {
  counter-reset: count-li;
}
li:before {
  counter-increment: count-li;
  content: counters(count-li, '.', decimal-leading-zero);
}
```

## **8. 見出しの複数行のときの字下げ**

![html5-css3-guide-tech-5.png](https://qiita-image-store.s3.amazonaws.com/0/151220/1be13956-9742-64ff-cdac-f7921cd7e8c7.png)

```html
<h2><span>複数行でも大丈夫。複数行でも大丈夫。複数行でも大丈夫。...</span></h2>
```

```css
h2 {
  display: table;
  width: 100%;
}
h2 span {
  display: table-row;
}
h2 span::before {
  display: table-cell;
  width: 1%;
  content: '01';  /* ここは本来ならcounter()を使うがわかりやすいように書いている */
  white-space: nowrap;
}
```

**3.2項**の最小幅で表示するテクニックも使っています。`table-cell` ほんと便利すぎ！


## **9. 手書き風のボックス**

![html5-css3-guide-tech-6.png](https://qiita-image-store.s3.amazonaws.com/0/151220/6026ab4d-05e6-0245-036a-a876dbfc7dc6.png)

```html
<div class="box">...</div>
```

```css
.box {
  border: 1px solid #000;
  border-radius: 55px 12px 185px 12px / 8px 200px 8px 55px;
}
```

**水平方向と垂直方向を別々に指定**することで、手書き風の少しゆがんだボックスができます。詳しくは以下のページを見ると視覚的にもわかるかと思います。

> [border-radius - CSS3リファレンス](http://www.htmq.com/css3/border-radius.shtml)

## **10. 擬似要素のcontentのデフォルト値を設定**

![html5-css3-guide-tech-7.png](https://qiita-image-store.s3.amazonaws.com/0/151220/0de6d0c6-3087-f78d-c239-ae49c6ba8d32.png)

```html
<div class="box">
  エディタとは、データの編集などを...
</div>
```

```css
.box::before {
  display: block;
  content: 'ひとことメモ';
}
```

こんな風にCSSを記述すれば常に**ひとことメモ**という単語が挿入されますよね。でも、違う言葉にしたいときどうするの？となりますよね。

```html
<div class="box point">
  エディタとは、データの編集などを...
</div>
```

```css
.box::before {
  display: block;
  content: 'ひとことメモ';
}
.box.point::before {
  display: block;
  content: 'ポイント！';
}
```

こんな感じでCSSを増やせばいくらでも対応できる...。確かにそうかもしれませんが、これでは**汎用性**がありません。そこで、**data-属性**の登場です。

```html
<div class="box" data-title="ポイント！">
  エディタとは、データの編集などを...
</div>
```

```css
.box::before {
  display: block;
  content: 'ひとことメモ';
}
.box[data-title]::before {
  content: attr(data-title);
}
```

こうすれば、`data-title` 属性があるときはその値を、ないときはデフォルトとして**ひとことメモ**が使われます。


# **最後に**

いかがだったでしょうか？実はまだまだ紹介したいCSSテクニックがいっぱいあるんです。でもそれは、[HTML5/CSS3の超教科書](http://prog.guide/html5-css3/)に書いていくことにします。今年はフロントエンド・バックエンドともに大きく成長できた年でした。1年ってあっという間ですね。以上、[@ithat_me](https://twitter.com/ithat_me)でした。みなさん、よいお年を！！