1. Qiita
  2. 投稿
  3. HTML

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

  • 259
    いいね
  • 1
    コメント

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

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

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

HTML5/CSS3の超教科書

実際に作成したWebサイト

こちらから実際に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

<p class="line">文章</p>
<p class="line">文章</p>
...
<p class="line">文章</p>
.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としています。

.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の部分が黒くなってしまった話

2.2. svgを使う

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

.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

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

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

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

html5-css3-guide-tech-3.png

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

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

3.1. まずは上下中央に

<div class="container">
  <div class="title">サイトタイトル</div>
  <div class="info">#1<br>2016.12.27</div>
</div>
.container {
  display: table;
  width: 100%;
}
.title, .info {
  display: table-cell;
}
.title {
  vertical-align: middle;  /* 上下中央 */
}

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

3.2. 最小幅にする

.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を使った横並びの際の隙間をなくす

<ul class="list">
  <li>...</li>
  <li>...</li>
</ul>
.list li {
  display: inline-block;
}

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

.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. 前提として

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

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

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

<div class="svg">
  <img src="image.svg">
</div>
.svg img {
  width: 100px;
}

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

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

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

参考文献
SVG with width/height doesn't scale on IE9/10/11 - Stack Overflow

6. 区切り文字を入れる

html5-css3-guide-tech-4.png

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

6.1. 日付を/で区切る

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

<div class="date">
  <span>2016</span>
  <span>12</span>
  <span>27</span>
</div>
.date {
  letter-spacing: -.5em;
}
.date span {
  display: inline-block;
  letter-spacing: normal;
}
.date span + span::before {
  content: '/';  /* /で区切る */
}

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

/*  2016 / 12 / 27  */

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

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

6.2. 日付を画像で区切る

.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-sizecovercontain など便利な機能が使えます。

7. 見出しの連番

7.1. counter()関数

<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   -->
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() 関数をつかえば簡単に連番見出しを作ることができます。

<h2>見出し</h2>  <!-- 01 -->
<h2>見出し</h2>  <!-- 02 -->
<h2>見出し</h2>  <!-- 03 -->
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

7.2. counters()関数

<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 して、と書く必要はありません。

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

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

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

<h2><span>複数行でも大丈夫。複数行でも大丈夫。複数行でも大丈夫。...</span></h2>
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

<div class="box">...</div>
.box {
  border: 1px solid #000;
  border-radius: 55px 12px 185px 12px / 8px 200px 8px 55px;
}

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

border-radius - CSS3リファレンス

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

html5-css3-guide-tech-7.png

<div class="box">
  エディタとは、データの編集などを...
</div>
.box::before {
  display: block;
  content: 'ひとことメモ';
}

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

<div class="box point">
  エディタとは、データの編集などを...
</div>
.box::before {
  display: block;
  content: 'ひとことメモ';
}
.box.point::before {
  display: block;
  content: 'ポイント!';
}

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

<div class="box" data-title="ポイント!">
  エディタとは、データの編集などを...
</div>
.box::before {
  display: block;
  content: 'ひとことメモ';
}
.box[data-title]::before {
  content: attr(data-title);
}

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

最後に

いかがだったでしょうか?実はまだまだ紹介したいCSSテクニックがいっぱいあるんです。でもそれは、HTML5/CSS3の超教科書に書いていくことにします。今年はフロントエンド・バックエンドともに大きく成長できた年でした。1年ってあっという間ですね。以上、@ithat_meでした。みなさん、よいお年を!!