デザイナーにもエンジニアにも取っつきづらいHTML/CSS
結構嫌われ者ですよね。HTMLとCSS。
デザイナーからは「え、コードじゃん。やだわ。」とシンプルに言われたり、エンジニアからは「CSSの書き方が独特すぎてちょっと。。。」なんて言われたりします。悲しい。
「ではHTMLとCSSを極めてマークアップエンジニアになるかー」とそれらを極めた人は、現状のWebの進化に置いてけぼりにされて飯が食えなさそうな雰囲気がプンプンします。(私のことですね!)
デザインリサーチをしこたま学んでUXデザイナーの道に進むか、オブジェクト指向をしこたま学んでフロントエンドエンジニア(以下FE)になるか、はたまた全然違う職種になるか、という選択を迫られることになるはずです。
しかし、今のマークアップエンジニアがUXデザイナーやFEに振り切ったとしても、結局HTML/CSSを書く人がより減っていくことになります。
最終的に「Web上のデザイン」が決まるのは「CSS」になるので、だれかしらがCSSを書かないとUXに貢献できるUIは作成できないわけです。
「デザインやFEのスキルがあって、アドオンでHTML/CSSが書けると良い」という形で、アドオン扱いされてしまうようになってしまったマークアップエンジニアのスキルを、デザイナーもエンジニアも、それ以外の人も書けるようになるために記事を書いていこうと思います。
たかがHTML/CSSです。大したことはないのです。
ただ、実際初めてみると、されどHTML/CSSというのも事実なのです。困りました。。。
厄介なのは「なんとなくできてしまう」こと
HTMLやCSSを使えばページが作れること自体は、ググれば一発でわかります。
テキストエディタも、Sublime Text、Atom、VSCodeあたりを使えばオシャにコードが書けます。(私はVSCodeを使っています。)
ただ、ページを作っていくと、なんか闇の中に放り込まれた感覚がありませんか?
世の初心者向けのページを見ながらなんとなくページを作っていくと、自分がどこにどのCSSを書いたのか全くわからなくなり、ある部分のデザインを変えたつもりが他の箇所のデザインが変わっていることなんかもあります。
ただ、結局なんだかんだ言っても、
なんとなーーーーくごちゃっと書いてみたら、なんかできちゃった!!
となるのが、HTML/CSSの怖いところです。
なんかできちゃうんですよね。
ただ、その作ったサイトを運用していきたいと思って、どこか修正をしようとしたときには
もう何がなんだかわからないよー!えーん!
なんてことになるわけです。
なので今回は、初心者でもちゃんと保守性高く、品質の高いコードを書けるように以下の3つを説明をしていきます!
- まずは「小さいもの」から作るべし!
- 「レスポンシブ」に作るべし!
-
px
と%
を使い分けるべし!
まずは「小さいもの」から作るべし!
初心者向けのサイトを見ていると、だいたい「大きいもの」から作るようになっています。
それもそのはずで、<html>
の中に<body>
を書いて、その後に全体を囲う<div id="wrapper">
を作って…となっていくので正しいといえば正しいです。
しかし、この「大きいものから作る」というのが、後々「一部のデザインを変えたつもりが他の箇所のデザインも変わっちゃっていた」につながるわけです。
これを解消するために**「小さいもの」**から作るようにすると良いです。
デザインの統一を考える
例えば、ポートフォリオサイトを作っていて「お問い合わせ」というようなボタンがあったとしましょう。
この「お問い合わせ」というボタンの見た目は、ページ内で統一されていたほうが良いですよね。
基本的なページデザインをするときのざっくりとした流れは、ワイヤーフレームを作って情報設計を明確にしてから色を乗せて…というような「大枠からデザインしていく」のがベーシックかと思います。
もちろんデザインの仕方としては正しいのですが、デザインレビューを通したつもりでもどうしてもデザインに統一性がない状態に気づず、結局そのままコーディングに入ってしまって、リリースしてから気づいてもう手遅れ…みたいなことが起こりかねます。
ページの上部と下部に「お問い合わせ」というボタンがあるUIだとして、その「お問い合わせ」のボタンが上部は赤いボタンで下部が青いボタンになってしまっていたらユーザビリティに問題が出てしまいます。(極端な例ではありますが…)
しかし、保守性の高いHTML/CSSを書こうと「小さいもの」からコーディングすれば、自然とパーツのデザインの統一を見直す機会も得ることができます。
若干ページ内でボタンのデザインが違ったとしても、コーディングの段階で「共通化」しようとするので、デザインもきれいになっていきます。
当然、「ボタン」という単位でCSSを書くようなるので、「お問い合わせ」ボタンのデザインを変えようとしたときにページ全体のボタンのデザインを一気に変えることができます。
BEMを知る
では、そのお問い合わせのボタンのデザインを決めるためにCSSをあてたいわけですが、そのためには「class名」を決めなければなりません。
そのclassは自由に名前をつけられるわけですが、この名前をちゃんとつけないと「あー!こっちのボタンとあっちのボタンほとんど一緒なのにまたイチからCSS書かないとだめだー!」となりがちです。
そんなことが起きないようにするためには**「class名の設計」を行う必要があり、それの基礎となるのが「BEM」**という考え方です。
BEMと言ってもいろいろあるのですが、ざっくりとした概要は以下の通りです。
- 一つの塊を、要素の大小に関わらず「block」とする
- blockに依存する中身の要素を「element」とする
- blockやelementがいろいろな状態を持つとき、その状態のことを「modifier」とする
- block、element、modifierは「block__element--modifier」と表現する
だいたいこんな感じです。
block名やelement名が一つの英単語で収まらない場合は、様々なやり方がありますが、私はlowerCamelCaseを使うのが好きです。
(記事を読み進めていくと命名の仕方が掴めると思うので、よくわからないなーという方はそのまま読み進めてください〜)
BEMで書く
上記のルールを基にボタンを作っていきます!
ただ、その前に、reset用cssの説明をします。
この記事ではEric MeyerのCSSを使っています。
また、追加で以下のコードを入れてコーディングしていますのでご承知おきください。
*, ::before, ::after {
box-sizing: border-box;
}
:root {
font-size: 13px;
line-height: 1.2;
color: #333;
}
上記の準備が出来たら本番です。button
のコーディングをしていきます。
<button class="button button--level1">お問い合わせ</button>
.button {
display: inline-block;
border: none;
border-radius: 5px;
border: 1px solid;
padding: 9px 14px;
text-align: center;
font-size: inherit;
line-height: inherit;
cursor: pointer;
-webkit-appearance: none;
appearance: none;
}
.button.button--level1 {
border-color: #f35;
background-color: #f35;
color: #fff;
}
今回、button--level1
という記述をしていますが、これが**「modifier」**と呼ばれるものです。
これは、ボタンというUIに複数の表示パターンがあることを想定しているために入れました。
命名するときは、色名(redなど)や機能名(inquiryなど)で命名するよりか、
レベルで分けたほうがデザインの情報設計とすり合わせがしやすくなります。
そのページ上で、一番強調したいボタンなのか、それともリンクよりも少し目立たせたいためにボタンのUIにしているのか、という「情報設計上でのコンテキスト」で命名したほうが使いやすいと私は思います。
このようなボタンができた場合に、button--red2
というのも微妙ですし」、button--inquiry2
というのも微妙ですし、ボタンの中の文言が「もっと見る」とかだったら、同じデザインなのにbutton--more
というmodifierを作らなければならなくなります。
なので、上記のbuttonにはbutton--level2
というmodifierをつけてあげることで、スッキリとCSSを書けてデザインも統一できます。
全体のコードは以下のようになります。
<button class="button button--level1">お問い合わせ</button>
<button class="button button--level2">お問い合わせ</button>
.button {
display: inline-block;
border: none;
border-radius: 5px;
border: 1px solid;
padding: 9px 14px;
text-align: center;
font-size: inherit;
line-height: inherit;
cursor: pointer;
-webkit-appearance: none;
appearance: none;
}
.button.button--level1 {
border-color: #f35;
background-color: #f35;
color: #fff;
}
.button.button--level2 {
border-color: #f35;
background-color: #fff;
color: #f35;
}
modifierには差分の色だけを当てて上げればいいので、修正もしやすくなります。
便利!
「デザインの共通化」を意識してみる
今回はボタンを例に挙げましたが、その他にも見出しとか、ラジオボタン、チェックボックス、テキストボックス、アイコンなどなどの「小さいもの」からコーディングをしていくと「パーツ集」を作ることができます。
パーツ集が作れてしまえば、あとはそれの組み合わせでコーディングすることができます。
一旦、<body>
の中にパーツだけを作っていってしまって、そのクラス名をあとで使いまわしていくのが良いのかなと思います。
<button class="button button--level1">
というのを作っているので、あとはボタンを置きたいときに、このHTMLをコピペしちゃえばOKになります。
もし、コピペをしやすくしたい場合は、parts.html
というのを仮で作ってしまって、その中にパーツ集を作って、実際のページはindex.html
の方に書いていけばよいかと思います。(CSSは共通で<link>
で引けばOKです。)
「レスポンシブ」に作るべし!
「レスポンシブ」と聞くと、スマホでもPCでも見られるを作る場合のときだけなイメージがあります。
ブラウザの幅を小さくしていくと、「PC→タブレット→スマホ」の順に、それぞれ最適化されたデザインになっていくページを「レスポンシブ」と呼ぶケースも多いと思います。
参考:ミツエーリンクスの企業ページ
ただ、スマホ向けだろうがPC向けだろうが、必ずレスポンシブを意識してコーディングすべきです。
横幅可変を常に心がける
例えば以下のようなデザインがあるとします。
これは、先ほどのbutton
というblockを使ってコーディングしています。(なのでbutton
のCSSは省略しています。)
<div class="inquiryLink">
<p class="inquiryLink__lead">以下からお問い合わせください!</p>
<div class="inquiryLink__button">
<p class="inquiryLink__buttonInner">
<button class="button button--level1">お問い合わせ</button>
</p>
</div>
</div>
.inquiryLink {
margin: 0 auto;
padding: 30px;
width: 600px;
background-color: #f5f5f5;
text-align: center;
}
.inquiryLink .inquiryLink__lead {
font-size: 15px;
}
.inquiryLink .inquiryLink__button {
margin-top: 10px;
}
.inquiryLink .inquiryLink__button .button {
width: 300px;
}
いい感じに書けていますね。
inquiryLink
というblockの中に要素が2つあるので、inquiryLink__lead
とinquiryLink__button
というelementを用意しています。
ただ、一点気になる記述があります。
.inquiryLink .inquiryLink__button .button {
width: 300px;
}
この部分です。
inquiryLink__button
の中に入ったbutton
の横幅はwidth: 300px
になるようにしています。
一見、大した問題はなさそうです。
しかし、実は、BEMのルールにはblockの中ですべて完結させるというルールがあります。
理由としては、もしbutton
のCSSが変わってしまったときに、予期せぬ表示崩れを起こす可能性があるからです。
なので、他のblockからスタイルを上書きはしたくありません。
では、このUIのときにどのように解決すべきかというと、、、
ボタンを横幅可変にしてしまえばいい!
わけです!
buttonのCSSを以下のように変えます。
.button {
display: inline-block;
/* 以下のwidthを追加 */
width: 100%;
border: none;
border-radius: 5px;
border: 1px solid;
padding: 9px 14px;
font-size: inherit;
text-align: center;
line-height: inherit;
cursor: pointer;
-webkit-appearance: none;
appearance: none;
}
ふざけているように見えますが、これで問題ありません!
button
をこの状態にしておいて、先ほどのinquiryLink__button
を修正します。
.inquiryLink {
margin: 0 auto;
padding: 30px;
width: 600px;
background-color: #f5f5f5;
text-align: center;
}
.inquiryLink .inquiryLink__lead {
font-size: 15px;
}
.inquiryLink .inquiryLink__button {
margin-top: 10px;
text-align: center;
}
.inquiryLink .inquiryLink__buttonInner {
display: inline-block;
width: 300px;
}
変わった部分は、inquiryLink__buttonInner
にスタイルを追加で当てて、button
へのスタイルを消した点です。
buttonの横幅が可変になっていることによって、
外側のelementが横幅を決める責任を担える
わけです。
blockに閉じたスタイルだけをかけるようにする
margin
、border
、padding
といったもので、余白や枠線を指定できます。
(top
、right
、bottom
、left
で表示位置も指定できますね。)
このうち、どれをblockのスタイルにしていいのかを掘り下げていきます。
Chromeの開発者ツールを使用すると検証をすると上の画像のものを出せます。
540
と58
と書かれているのがwidth
とheigth
になります。
上記の画像をよく見ると、margin
とborder
の線が実線で描かれています。(黒い線が濃く出ています)
この実線より内側のものをblockのスタイルとしてかけるべきです。
ただし、少しややこしいのですが、box-sizing: border-box;
を適用している場合は、**「width
とheight
で指定した数値は、border
とpadding
を含めた値」**になります。
(今回は、最初に全要素にbox-sizign: border-box
を適用しています。)
上の画像のケースでは、width: 600px
とpadding: 30px
にしているため、box-sizing: border-box
の効果により、実際のwidthの幅 = 600px - 30px * 2 = 540px
となっています。
つまり、box-sizing: border-box
を適用している場合は、
**「margin
とborder
の間の実線の位置が、ちょうどwidth
とheight
の値の位置」**になります。
なので、私が言った「この実線より内側のものをblockのスタイルとしてかけるべき」という言葉は**「width
とheight
は含めない」**ということになります。
なので、**blockにかけるべきものはborder
とpadding
**になります。
それよりも外側のものは、それを囲うものに担当してもらうのが良いです。
(top
やleft
なども外側の扱いです。)
なので、inquiryLink
は以下のように書き換えたほうが良いです。
.inquiryLink {
padding: 30px;
background-color: #f5f5f5;
text-align: center;
}
.inquiryLink .inquiryLink__lead {
font-size: 15px;
}
.inquiryLink .inquiryLink__button {
margin-top: 10px;
text-align: center;
}
.inquiryLink .inquiryLink__buttonInner {
display: inline-block;
width: 300px;
}
変わった点は、.inquiryLink
からmargin
とwidth
を削除しました。
削除した部分は、更に外側に来るblockに幅を決めてもらえばよいのです。
px
と%
を使い分けるべし!
「すべてレスポンシブで作れ」と言われると、「すべて%
で作るべきかな?」と思いがちです。
しかし%
で作ってしまうと、実はデザインが崩れてしまいます。。。
CSSで「余白」を制してデザイナーに好かれよう#グリッドシステムを知る
自分の記事で恐縮ですが、UIを作る上ではグリッドシステムを設計しているケースがあったり、設計はされていなくても余白の縦のラインは気にするケースがあったりすると思います。
この場合、margin
を%
にしてしまうと、一気に崩れてしまいます。
理由は**「margin
を%
指定にした場合、自分自身のwidth
に対しての百分率になる」**からです。
例えば、1カラム表示のときの左余白と2カラム表示したときの左余白は要素の幅が異なることで当然左余白に差分が生まれてしまい、縦の余白のラインが揃わなくなってしまうのは容易に想像できると思います。
せっかくsketchやphotoshopでデザインしても、ここがビシッと揃わないのは本当に嫌ですよね。。。
なので私は、基本的に
「幅のみ可変、それ以外は固定」
という考え方を推奨します。
グリッドリストUIを作る
「幅のみ可変、それ以外は固定」を実証するために、例えば以下のようなUIを実装してみようと思います。
まず、全体的なHTMLとCSSは以下の通りです。
<ul class="productsList">
<li class="productsList__item">
<a href="#" class="productsList__itemLink">
<div class="productCard">
<p class="productCard__thumbnail"><img src="https://dummyimage.com/200x200" class="productCard__image"></p>
<p class="productCard__title">タイトル1</p>
<p class="productCard__date">2019/01/01</p>
</div>
</a>
</li>
<li class="productsList__item">
<a href="#" class="productsList__itemLink">
<div class="productCard">
<p class="productCard__thumbnail"><img src="https://dummyimage.com/200x200" class="productCard__image"></p>
<p class="productCard__title">タイトル2</p>
<p class="productCard__date">2019/01/02</p>
</div>
</a>
</li>
<li class="productsList__item">
<a href="#" class="productsList__itemLink">
<div class="productCard">
<p class="productCard__thumbnail"><img src="https://dummyimage.com/200x200" class="productCard__image"></p>
<p class="productCard__title">タイトル3</p>
<p class="productCard__date">2019/01/03</p>
</div>
</a>
</li>
<li class="productsList__item">
<a href="#" class="productsList__itemLink">
<div class="productCard">
<p class="productCard__thumbnail"><img src="https://dummyimage.com/200x200" class="productCard__image"></p>
<p class="productCard__title">タイトル4</p>
<p class="productCard__date">2019/01/04</p>
</div>
</a>
</li>
</ul>
.productCard {
border: 1px solid #eaeaea;
padding: 15px;
}
.productCard .productCard__thumbnail {
text-align: center;
}
.productCard .productCard__image {
width: auto;
max-width: 100%;
height: auto;
}
.productCard .productCard__title {
margin-top: 10px;
}
.productCard .productCard__date {
margin-top: 3px;
font-size: 11px;
color: #808080;
}
.productsList {
display: flex;
flex-wrap: wrap;
margin-top: -10px;
margin-left: -10px;
}
.productsList .productsList__item {
flex: 1 1 auto;
min-width: 33.33%;
max-width: 33.33%;
}
.productsList .productsList__itemLink {
display: block;
margin-top: 10px;
margin-left: 10px;
color: inherit;
text-decoration: none;
}
まず、一個一個のカード部分をproductCard
というblockにしています。
そして、その全体を囲っているリスト部分をproductsList
というblockにしています。
前の章の通り、productCard
にもproductsList
にもwidth
が設定されていません。
横幅を決めているのは、各カード全体を囲んでいるproductsList__item
というところで決めています。
(今回は触れませんが、productsList
の横幅も、さらに大きなblockに囲われて決まることになります。)
ここで設定している値は33.33%
です。(width
ではなくmin-width
とmax-width
で指定しているのはdisplay: flex
で作っているためです。)
これは、productsList
の幅に対して33.33%
(つまり3分割)という指定になります。
このように、blockに対して、何分割ずつ配置するかが明確な場合は%
で指定します。
%
で指定しておけば、中身のproductCard
自体も可変で作られているため、ずっと3分割で表示されるようになります。
もし画面幅が広いときに4分割にしたければ、@media
で適当な横幅のときにwidth: 25%
にしてあげればOKというわけです。
また、各カードの上側と左側の余白を、productsList__itemLink
のmargin
で決めています。
このmargin
の値はちゃんと%
ではなくpx
にしています。
こうすることで、余白の数値が確実になりますので、章の冒頭で述べたとおり、productsList
の上下に来るblockの余白が合わせやすくなります。
さらに、productsList
に書いているmargin-top: -10px
とmargin-left: -10px
という指定ができるようになっています。
これは、productsList__itemLink
のmargin
を相殺しています。
なぜそうしているのかは、こちらも私の記事で恐縮ですが以下の記事を読んでみてください!結構便利です!
flex-boxを使わないでおしゃれなレスポンシブカラムリストを作る#基本はシンプルそして強引に
カラム構成を作る
「幅のみ可変、それ以外は固定」
という考えはもちろん大事なのですが、早速この言葉の反例をご紹介したいと思いますw
それが、タイトルの通りカラム構成を作るときです。
これを作るときは、px
を組み合わせて作ったほうがよいです。
以下の画像のような、左カラムは細くて右カラムは太いページなんかよく目にすると思います。
(有り合わせで作っているので、変なUIですみません。。)
これは、今回作ったproductCard
とinquiryLink
をカラム構成を決めるcolumns
というblockで囲んだ形になります。
<div class="columns columns--typeA">
<div class="columns__item">
<div class="productCard">
<p class="productCard__thumbnail"><img src="https://dummyimage.com/200x200" class="productCard__image"></p>
<p class="productCard__title">タイトル1タイトル1タイトル1タイトル1タイトル1</p>
<p class="productCard__date">2019/01/01</p>
</div>
</div>
<div class="columns__item">
<div class="inquiryLink">
<p class="inquiryLink__lead">
以下からお問い合わせください!
</p>
<div class="inquiryLink__button">
<p class="inquiryLink__buttonInner">
<button class="button button--level1">お問い合わせ</button>
</p>
</div>
</div>
</div>
</div>
.columns {
display: flex;
}
.columns.columns--typeA .columns__item:first-child {
flex: 0 1 auto;
margin-right: 20px;
min-width: 200px;
max-width: 200px;
}
.columns.columns--typeA .columns__item:first-child + .columns__item:last-child {
flex: 1 1 auto;
}
productCard
とinquiryLink
のHTMLはコピペなのでCSSは載せていません。
columns
は、3カラムだったり、2カラムだけど右カラムが固定されるケースなどもあるはずなのでcolumns--typeA
というmodifierを作って、それに合わせて中のcolumns__item
のスタイルが変えられるようにしてみました。
column__item
にスタイルをあてるためのセレクタの指定が今までよりもちょっと複雑ですが、
.columns.columns--typeA .columns__item:first-child
が左カラムで、
.columns.columns--typeA .columns__item:first-child + .columns__item:last-child
が右カラムです。
このような、左カラムが細くて右カラムが太いときのUIを作るときは、
狭い方のカラムを固定にしてしまう
とUIがきれいに見えます。
今回もflex
を使っているので、min-width
とmax-width
で固定しています。
おそらく左カラムがサブ情報になると思うのですが、左カラムを30%
にして右カラムを70%
で作ると、画面全体の横幅が広がっていったときに、「左カラムそんなに幅取る!?」という気持ちになると思いますw
左カラムにmax-width
を指定してももちろん良いのですが、今度画面幅が狭くなったときのためにmin-width
を指定したりしないといけなくなってきて、CSSの指定が複雑になってきます。
それなら、どの幅であっても左カラムは固定で取ってしまって、「画面幅が狭くなったら2カラムにするのをやめる」という記述を書いてしまったほうがシンプルにコードが書けます。
なので、狭い方の幅は固定で取ってしまうのをおすすめします。
最後に
いかがだったでしょうか?
最初に「小さいもの」から作るべしと述べてから始まったこの記事ですが、徐々に作るものが大きくなっていき、最後はカラムという大きいものコーディングになっているのに気づいていただけましたか!?笑
なので、小さいものからコーディングしていくのは案外できちゃうっぽいですね。
自分でも記事を書きながら「本当かしら?」と思いながら書いていましたが、大丈夫そうでしたw
実際、どこまでを「小さいもの」として、どこまでを「block」にすべきかを見極めるのは、結構難易度の高い作業だと思っています。
こういう作業は、やはりエンジニアの方が得意なのだと思います。(コンポーネント指向というやつですね。)
なので、非エンジニアの方は、見よう見まねで「小さいもの」を作ってみて、身近にエンジニアがいればアドバイスをもらうのも良いかもしれません。
ただし、「見た目の共通化」というのもとても重要なので、「コンポーネント指向」だけで共通化していくのもちょっと危険かもしれません。
非デザイナーの方は、デザイナーにデザインのコンテキストを聞いた上で共通化していくのも良いかもしれません。
結局のところ、今回私が書いたことは「Atomic Design」の入り口になるのかなーとなんとなく思いました。
まずはこの記事を試していただいて、そこからAtomic Designに触れていくのもアリな気がしました!
(もしAtomic Designをもう少し詳しく知りたい場合は私が書いた以下の記事も読んでみてください!)
Atomic Designってデザイナーには難しくない!?という話
FEという職は、デザインもエンジニアリングも両方分からないと勤まらない、結構難しい職種なのではないかと最近思い始めました。
このデザイナーとエンジニアの「中間」に位置する「FE」という職種の「持つべきスキルが何であるか」をどんどん解明できると、ものづくりがもっと楽しくなるかもですね!
そんな期待を込めて、この記事を締めます!ありがとうございました。
ご指摘やご相談等あれば、ぜひコメント欄にご記入ください〜