Post on:2017年1月11日
sponsorsr
Webページを制作にする時に、マージンやパディングをどのようにつけるか悩むことがあります。2カラムの隙間は、左パネルの右マージンorパディングなのか、右パネルの左マージンorパディングなのか。
Web制作の今までの考え方がきっと変わる、モジュール式のアトミック デザインにおけるHTMLとCSSの実装のロジックを紹介します。
Learning from Lego: A Step Forward in Modular Web Design
下記は各ポイントを意訳したものです。
※当ブログでの翻訳記事は、著者様・元サイト様にライセンスを得て翻訳しています。
最近のWeb制作の手法は、数多くあるフレームワークやUIキットからあらゆる種類のコンテンツのブロックを組み立てています。しかしながら、モジュール性と汎用性はまだWeb要素レベルでは達成されていないと言えるでしょう。
LEGOブロックの考え方を学ぶことで、モジュール式Webデザインを一歩前進させることができます。
モジュール式のアトミック デザイン(Atomic Design)はここ1, 2年、注目されています。アトミック デザインとは一言で表現すると、Webのコンポーネントは多目的で再利用可能である、ということです。わたし達はそれらをレンガのように置くことができ、組み合わせて利用できます。しかもその時にコードを調整する苦労はありません。
今までは、これをコンテンツのブロックレベルでおこなってきました。すべてのブロックで横一列をいっぱいにし、すべてが同じ幅で、それぞれが自己完結型です。各ブロック内のスタイルや要素を考慮する必要はなく、異なるブロックを組み立ててWebページを作成することが可能です。これは大きい前進と言えるでしょう。また、フレームワークやUIキットが爆発的に増加し、Webページのデザインがモジュール化され、さらにアクセシブルになりました。
Webの要素レベルで、同様のモジュール性を達成することは容易ではありません。Pattern Labによると、UIパターンをマトリョーシカ(ロシアの入れ子構造の人形)のように相互に配置できる必要があると言っています。このマトリョーシカを考えてみると、各レイヤーには独自の厚みがあります。これはWebデザインにおけるパディングとマージンに相当します。3番目の人形を7番目の人形の隣に置くと、その間のスペースは均一ではありません。人形では特に問題はありませんが、Webページで空白スペースが不揃いになったり、CSSの上書きが複数レベルになってしまう可能性があります。
私はBootstrapとFoundationを何年も使ってきました。これらのフレームワークで複雑なレイアウトを作成すると、入れ子の列や入れ子の行など、すべてがマトリョーシカのように自身のパディングとマージンを持つ要素です。これらの入れ子を一つずつ確認し、余計なパディングやマージンを取り除き、計算をして、スタイルの上書きをして、コメントを加えたりします。
これらの作業は、スタイルシートの制作として美しいものではありませんでしたが、それでもまだ許容範囲でした。そんな時に、私はGraphiq社に入社しました、700以上の異なるトピックにデータ視覚化を提供するナレッジ企業です。ここでは、コンテンツエディタが読者の最も良い体験をつくり出すために、必要な任意の形式でどんなデータでも入力することができます。このような柔軟性は小規模なスタートアップにとって理にかなっており、単一のデータポイントからインフォグラフィックス、チャート、カラム、ブロック、カードまですべてを整理するのに役立つドラッグ&ドロップのインターフェイスがあります。コンテンツエディタは同じく、ページのレイアウトにロジックを加えることもできます。そのため、互いにすぐ隣にあう2つの同様の棒グラフは、全く異なるHTML構造にすることができます。この汎用性はあなたが想像する通り、デザイナーとデベロッパーの間で混乱の元になります。
CSS Grid Layoutはこれらの問題を解決するソリューションですが、残念なことに主要ブラウザでまだサポートされていません。ひょっとすると、数年かかるかもしれません。もしマトリョーシカのような入れ子構造の考え方を変えることができれば、ツールを利用してモジュール式のデザインに一歩踏み出すことができます。
分かりやすいメタファとして、LEGOを取り上げます。これはモジュール式のアトミック デザインの典型と言えるでしょう。LEGOで大きいものを作ることを想像してみてください、小さいLEGOブロックが入れ子で組み立てる時に、パディングやマージンについて心配する必要はありません。実際にはLEGOには、入れ子という概念はありません。すべての要素は、複数のレイヤーではなく、同じレベルで存在しています。
しかし、そのことはWebデザインにとってどういう意味になるでしょうか?
わたし達はセマンティックな構造のために、そして簡単に選択できるようにするために、Webの要素を入れ子にしなければなりません。HTMLの構造を変更すべきだという訳ではありませんが、わたし達のスタイルシートでは最下位のWeb要素(アトミック デザインにおける「アトム」)にだけスペースを入れることができ、その間には多くのレイヤーを配置することはできません。
個々のLEGOブロックの上部を思い出してください。丸の部分がコンテンツで、その周りを囲うようにパディングがあります。このパディングは要素間のギャップになる半分のサイズです。
LEGOブロックにおける、コンテンツとパディング
LEGOブロックで実際にレイアウトを作ってみます。
各ブロックの周りを囲うパディングは同じなので、すべての要素が同じギャップを持っています。
パディングは自身の外縁と隣接するブロックの外縁
わざわざパディングやマージンを別に用意する必要はありません。ブロックだけでギャップが作成されます。すべての要素(どれだけ入れ子をしていても)は同じレベルに存在するように見え、CSSの上書きや調整は不要で、first-やlast-childを使った調整も不要です。
これをコードにするとどうなるでしょうか。
半分のギャップを加えるclassを作成し、それをページ上のすべての最下位レベルの要素に適用することができます。これはレイアウト用のdiv要素から、.rowや.colのようなスペースを目的としたclassをすべて削除することができます。
1 2 3 4 | $gutter:20px; .element{ padding:$gutter/2; } |
注意すべき点は、パディングが.elementだけの時に、最も外側の要素と親のdivとの間のパディングは、溝の半分だということです。
最も外側のパディングは、溝の半分
これを解決するには下記のように、最も外側のコンテナにパディングを加えればよいでしょう。
最も外側のコンテナに、溝の半分のパディングを追加
コードは簡単です。
1 2 3 4 5 | $gutter:20px; .container, .element{ padding:$gutter/2; } |
溝の半分のパディングを追加すると、下記のようになります。
外側にパディングを追加したので、すべてのパディングが同じに
行や列をつかった最近のレイアウトを作成するために、レイヤーがいくつ必要か考えてみましょう。わたし達ができるベストは、下記のような方法です
横行と縦列をつかったレイアウトのサンプル
まずは昔の方法で実装してみます。
レッドの線がパディングで、パディングはそれぞれ異なります。
LEGOブロックの考え方を使うと、パディングはそれぞれ同じ、コードも非常にシンプルです。
下記に2つの例に示します。まずはfloatを使った実装から。
続いて、flexboxを使った実装です。
LEGOブロックをつかった考え方は、すべてがうまく解決する方法です。しかしLEGOブロックを使うと、レンガのパディングを微調整したり、水平と垂直のパディングを異なる値にすることができません。Webではこの点において、多くのバリエーションが必要になるかもしれません。
これを解決するには、1つの値を溝として設定するのではなく、4つの異なる変数を設定することで、柔軟なレイアウトを得ることができます。
1 2 3 4 5 6 7 8 9 10 11 | $padding-x:10px; $padding-y:20px; $padding-outer-x:40px; $padding-outer-y:30px; .container{ padding:$padding-outer-y$padding-outer-x; } .element{ padding:($padding-y/2)($padding-x/2); } |
各パディングの水平は10px、垂直は20px、そして外側にも均一になるように設定します。
それぞれ異なる値を使ったパディング
モジュール式ですが、よりダイナミックなスタイルを作成するためにさまざまなスペースを持っています。
レスポンシブデザインでは、さまざまなメディアクエリに異なるスペースを設定することができます。このアプローチをSassのMixinにしてみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @mixinlayout($var){ $padding-x:map-get($var,padding-x); $padding-y:map-get($var,padding-y); $padding-outer-x:map-get($var,padding-outer-x); $padding-outer-y:map-get($var,padding-outer-y); .container{ padding:$padding-outer-y$padding-outer-x; } .element{ padding:($padding-y/2)($padding-x/2); } } |
このMixinを使用することで、さまざまなメディアクエリに異なるスペースを設定するCSSのルールを生成できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | // Spacing variables $spacing:( padding-x:10px, padding-y:20px, padding-outer-x:40px, padding-outer-y:30px ); $spacing-tablet:( padding-x:5px, padding-y:10px, padding-outer-x:20px, padding-outer-y:15px ); // Generate default CSS rules @includelayout($spacing); // Generate CSS rules for tablet view @media(max-width:768px){ @includelayout($spacing-tablet); } |
このコードを使用すると簡単に、すべての要素がデスクトップとタブレットでスペースを異なって表示できます。
私はここ1年ずっとこの方法を使って、実装してきました。その中から特によく使う実践的なテクニックをいくつか紹介します。まずは、背景とボーダーの扱いです。
要素に背景やボーダーを追加するときは、.elementのdiv要素に適用しないでください。背景は要素のパディングにも適用されるので、グリッドの見た目は下記のように崩れて見えます。
.elementのdiv要素に背景を適用すると、崩れる
解決方法は、子供のdiv要素に背景を適用します。
1 2 3 | <divclass="element"> <divstyle="background-image:url();"></div> </div> |
入れ子にした子要素に背景を適用すると、グリッドの見た目は崩れません。
子要素に背景を適用
基本的にはすべてこの構造を使うとよいでしょう。同様に、ボーダーはボックスモデル内のパディングを囲んでいるので、正しいスペースを維持するために、要素のボーダーを子供のdiv要素に適用する必要があります。
ボーダーも背景と同じように、子要素に適用
横いっぱいに要素を表示させたい時に、パディングはどう扱えばよいでしょうか。
横行いっぱいに要素を配置
これを解決するには、.containerと.elementの構造が後ろに続く横行いっぱいの要素をスタイルするには、負のマージンを使用する必要があります。
1 2 3 4 | .element-full-row{ margin:0(-$padding-outer-x); padding:($padding-y/2)($padding-x/2+$padding-outer-x); } |
パディングに$padding-outer-xを加えることで、.element-full-rowのコンテンツと.elementのコンテンツがぴったりと整列して配置されます。
横行いっぱいとその下のコンテンツが揃った状態
上記のコードは水平方向のスペースですが、同じロジックを適用して垂直方向のスペースを扱うことも可能です。この方法で非常に簡単に、負のマージンを加えることができます。
1 2 3 4 | .element-full-row:first-child{ margin:(-$padding-outer-y)(-$padding-outer-x)0; padding:($padding-y/2+$padding-outer-y)($padding-x/2+$padding-outer-x)($padding-y/2); } |
このコードは単独のルールとして利用することも可能で、SassやLESSのMixinにしておくと便利です。
要素をネスト(入れ子)することにおいても、このLEGOの考え方を取り入れたメソッドは非常に有用です。ただし、最初に言っておきますが、唯一できない入れ子が.elementの中に.elementを配置することです。これはパディングを二重にしてしまうため、使用することはないでしょう。
そのためボタン、入力ボックス、テキストボックス、画像などの最下位のWeb要素(アトミック デザインにおける「アトム」)にのみに、.elementのclassを適用すべき理由です。
下記のようなごく普通のコメントボックスを例に、入れ子を見てみましょう。
ポイントは1つの「要素」として扱う代わりに、要素(タイトル、テキストエリア、ボタン、およびヘルパーテキスト)の定義済みグループとして扱う必要があります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <divclass="comment"> <h3class="comment-title element">Addanewcomment</h3> <textareaclass="element"></textarea> <divclass="clearfix"> <divclass="float-left"> <divclass="element"> <buttonclass="btn-post">Postcomment</button> </div> </div> <divclass="float-right"> <divclass="helper-text element"> <iclass="icon-question"></i> SomeHTMLisOK. </div> </div> </div> </div> |
.commentを1つの再利用可能なコンポーネントとして扱うことも可能で、同じように記述された他の再利用可能なコンポーネントとうまく連携し、上位レベルのHTML構造にグループ化することもできる「分子」としてアトミック デザインのコンテキストで扱うことができます。
ここまで紹介したレイアウトは、同じ高さを持ったパネルを使ってきました。そのため、このテクニックは定義された高さと幅を持つ要素に対してのみ機能すると考える人もいるかもしれません。
しかし、そうではありません。このテクニックの用途は非常に広いです。
要素の高さと幅が変化しても、遅延ロードを使っても、floatで実装しても、LEGOのようなパディングは要素間に一貫した同じ隙間を保証します。
Pinterest風の高さが不揃いのレイアウトにも対応
実際のコードも確認してみましょう。
コードは当然、メンテナンスも考えなくてはいけません。明らかに、新しい方法を採用するには時間を要します。しかし、この考え方を採用してCSSを書き始めると、メンテナンスは非常に簡単になります。
特にレイアウトのMixinでは、スペースに関するすべてのルールが集約され、変数のグループによって管理することができます。変数を1つ変更するだけで、Webページ上のすべての要素に対して自動的に反映されます。
これは今までの古い方法を使うと、パディングやマージンを数多く変更する必要があり、さらに期待通りに機能するかテストする必要もあります。これは非常に大変な労力です。
最後は、ブロックを並べただけではない非常に複雑なグリッドレイアウトです。一見かなり困難な作業になるかもしれない、と思うかもしれません。
ここで解説した多くの問題はCSS Grid Layoutで無くなるかもしれませんが、ブラウザのサポートを受けるためには数年を要するかもしれません。そこから更に実践的なテクニックやフレームワークになるには、さらに長い時間がかかります。またFlexbox(ほとんどのブラウザでサポートされています)のように、広く採用されるものとは限りません。
結局のところ、一般的なWebユーザーがCSS Grid Layoutを理解するのに長い時間を要するということです。同様にCSS Grid Layoutの最適なコードにするには、かなりの開発が必要でしょう。
列と行をつかった古い方法は分かりやすく、ネストが問題ではない限り、Webサイトを制作するための良い解決策と言えます。
わたし達はGraphiqで2016年の初めから、この方法を取り入れてきました。この1年の間、わたし達はこれを愛し、今後どのようにWebレイアウトを書くべきかと考えています。各ページをリファクタリングするにつれ、古いCSSコードを何百行も削除し、スタイルシートをより論理的で読みやすいようにしています。また過去のすべてのリファクタリングと比較して、レイアウトとスペースのバグがはるかに少なくなっています。そして現在では、コンテンツエディタがどのようにデータを入れ子にしても、心配する必要はほとんどありません。
レイアウトについて考え、そしてどのようにコード化するかはある意味ゲームと言えます。Webコンポーネントが要素レベルまで下がったLEGOブロックのようにモジュール式であると考えると、コンポーネントは多目的に利用でき、メンテナンスがしやすくなります。これがモジュール式Webデザインを取り入れる次のステップであると考えています。
ぜひこの方法を試してみてください。Webページを書く方法が変わるかもしれません。
sponsors