SASS : &記法による記述をネストを再現しつつ @extend する
月花です。
今日はSASSの備忘録的なTipsです。
SASSでは、 &(アンパサンド, アンド)によって親セレクタを参照することができます。
この親というのは、事実上の親ではなく、あくまでセレクタ記法としての親なので、たとえば .product というセレクタを .product-image の親にすることもできます。
これは別にDOM上の親子でなくともよいのがSASSの強みですが、こうやってこねくり回していると、じゃあこれを @extend で継承し、フォークしたくなったらどうすればよいでしょうか。
<div class="product"> <div class="product-image"><img src="xxxxxx"></div> <div class="product-text">xxxxxxxxx</div> </div>
こういうHTMLと、
.product{ display:block; &-image{ float:left; } &-text{ float:right; } }
こういうSASSがあります。
新しく
<div class="article"> <div class="article-image"><img src="xxxxxx"></div> <div class="article-text">xxxxxxxxx</div> </div>
こういうHTMLができました。
基礎のレイアウトは同じなので、これに当てるSASSは @extend を使ってそこから拡張していきたい、というときに
.product{ display:block; &-image{ // ←ここと float:left; } &-text{ // ←ここってどうやって @extend するの? float:right; } } // だって .article{ @extend .product; &-image{ @extend &-image; // ←ここの & は .article-image だから、 //.article-image-imageになってしまう } &-text{ @extend .product-text; // ←これなら通りそうだけど、全部に書くの? } }
という問題が発生しました。
ちなみに、
.article{ $parent : '.product'; }
単純にこうでいいのではというのは誤りで、コンパイルすると
.product, .article { display: block; } .product-image { float: left; } .product-text { float: right; }
こうなります。
&-text{} というような書き方では、ネスト上では親でもコンパイル後には兄弟になってしまうのです。
自分自身である & を使ってわかりやすく冗長に書きなおすと、
.product{ &{ display:block; } &-text{ float:right; } }
これと等価なので、一見子に見えても実は兄弟を指定しているためです。
Tipsなのでさくさくいきましょう。
変数を使って親の名前を保持しておく
.product{ // ←これを覚えると display:block; &-image{ // ←ここで使える float:left; } &-text{ float:right; } } .article{ $parent : '.product'; // ← 親を覚えて @extend #{$parent}; &-image{ @extend #{$parent}-image; // ← ここで展開 width:80%; } &-text{ @extend #{$parent}-text; color:black; } }
コンパイル後、
.product, .article { display: block; } .product-image, .article-image { float: left; } .product-text, .article-text { float: right; } .article-image { width: 80%; } .article-text { color: black; }
と、正しく @extend できた。
りくつ
SASS では、 #{$variable} と書くことで、文字列として展開することができる。
だから、親を変数に収めて、あとは書き足すだけ。
ちなみに、変数にドットを含めず、ドットを前に出すこともできる。
.article{ $parent : 'product'; @extend .#{$parent}; &-image{ @extend .#{$parent}-image; } &-text{ @extend .#{$parent}-text; } }
もう一段ネストしたら?
もう一段深くなって
.product{ display:block; &-text{ float:right; &-title{ font-weight:bold; } &-description{ font-size:12px; } } }
こう来たら、単純に
.article{ $parent : '.product'; // ←親を覚える @extend #{$parent}; &-text{ $child : #{$parent}-text; // ←子を覚える @extend #{$child}; &-title{ @extend #{$child}-title; // ←子を使う } &-description{ @extend #{$child}-description; } } }
コンパイル後、
.product, .article { display: block; } .product-text, .article-text { float: right; } .product-text-title, .article-text-title { font-weight: bold; } .product-text-description, .article-text-description { font-size: 12px; } .article-text-title { color: red; } .article-text-description { color: black; }
以上です。
CSS : 要素数・ブラウザ幅が可変長なサイトでflexをキレイに使う
月花です。
今回はCSSの備忘録です。
内容は、幅が可変長のサイトにおける、flexboxで要素は左寄せ、全体は中央寄せとする方法です。
テキストだと説明しづらいので、画像をつかっていきます。
やりたいこと
このようなレイアウトを組みたいとする。
コードでは下記のようになる。
See the Pen zdvwqQ by gekka (@gekka9) on CodePen.
しかし、同じCSSで横幅が少しでも異なると
See the Pen zdvwBQ by gekka (@gekka9) on CodePen.
このように、一見入りそうだけど、実はマージン込みでは入らず、下に落ちてしまう。
この右側のスキマが気になるので、直していく。
よくある失敗例
flexには、幅全体を使って等間隔に割り付ける、 justify-content:space-around という指定がある。
しかし、これを単純につかってしまうと・・・。
See the Pen YxyZMX by gekka (@gekka9) on CodePen.
このように、最下段がおかしなことになる。
解決方針
一段あたりの要素の個数が決まっているなら、よくあるハウツーでは剰余の数だけ空の要素を入れればいい。
しかし今回は、ブラウザの幅によって個数を変えて、常に入りうる最大の数を一段に押し込みたい。
つまり、下記のようになるのが理想である。
このためには、下記の X から Y を計算し、 Y/2 を margin-left に設定することでできるはずだ。
これも、数か幅のどちらかが固定ならば、シンプルに定まるものだが、その場合は計算せずとも space-around を使えばよいだけだ。
今回は可変長のため、一行あたりに何個入っているかをHTMLとCSSは知らないので、全体の幅から要素の横幅に個数をかけたものを引くなどというような、個数を用いる計算はできない。
そこで、個数に依存しない計算方法として剰余を用い、
・ Y = 100%(px) mod X(px)
と求めることができる。
もし、CSS の calc に剰余が実装されているならば、これでいけるはずだった。
しかし現実は非情である。実装されてないばかりか、そもそもcalcはモダンブラウザしか使えないのでIEが死ぬ。
ここはおとなしくJavaScriptを持ち出すことにする。
bootstrap : twinviteでbootstrapを活用してエモい招待サイトを作る
月花です。
先日、関西で行われるクラブイベントのWebページと、twinviteを公開しました。
そのとき使った手法が極めて有効であったため、下記に残します。
この記事は、イベントのWebサイトを作ったりtwinviteで凝ったことがしたい方の手引書を目指して書きました。
・気合をいれたイベントであることを強調したい。
・次は周年記念回なので、いつもよりきれいに作りたい。
・他のイベントとの差別化を図りたい。
様々な動機はあると思いますが、Webページをこだわることは、どれにも有効な手段です。
簡素な記事のため、説明不足の箇所が多いですが、分からないワードは積極的にググってみましょう。よく使われるライブラリについて書いているので、日本語で記事を起こしている先駆者はたくさんいます。
これらは、ある程度のHTML+CSSの知識は必要ですが、仕様などの深い理解は必要ありません。
今回作ったもの
・Webサイト
IzanagiDistribution3.0
いわゆるランディングページです。誘導対象はtwinviteですが、商業的な色を出さないために動線は最小限にしてあります。
・twinvite
http://twvt.me/id03
イベント招待サイトです。
自由にHTMLを書いてデザインできる部分がある、twiplaとかtweetviteみたいなやつです。
今回はここを攻略していきます。
bootstrapについて
Webサイト、twinvite共、bootstrapというライブラリを使っています。
getbootstrap.com
このライブラリは、Webサイトのあらゆるパーツのデザインを定義したCSSの詰め合わせと、便利なJavaScript関数の集合体です。
つまり、このライブラリで定義しているクラス名やID名を指定するだけで、グリッドシステムやモーダルの起動が可能です。
twinviteなどのHTMLを自由記述できる部分を含むページでは、スタイルは基本的にHTMLタグのstyle属性を使って、
<div style="〜〜〜〜"></div>
とすべてのタグに記述する必要がありますが、bootstrapに定義されているデザインを使う分にはクラス名の指定があればよいので、style属性が必要なくなります。
ここで、なぜtwinviteでbootstrapが使えるか、についてですが、twinviteは元々bootstrapを使って作られていて、私達が記述するより前の時点でリンク済みであるためです。
また、font-awesomeもリンク済みであるため、こちらもクラス名の指定だけで、様々なアイコンフォントを活用することができます。
fontawesome.io
つまり、Webサイトを別途作成する場合、そちらもbootstrapを使って実装してやれば、理想的にはHTML部分のコピペだけで、ほぼ同じページが作れる、ということです。
今回私が作成した2つは、そのようになっているため、Webサイト完成後の極めて迅速なtwinvite対応が可能でした。
ちなみに、こちらは以前私が作成した、LoveDive! というイベントのtweetviteページのソースコードです。
エディタの横幅に収まらないほど、style属性にガリガリ記述していることがわかると思います。
このコードは、下記のサイトの開催日時や金額が書かれたテーブル部分だけです。
http://gekka.sexy/love_dive.html
bootstrapが使えれば、もはやこのような苦労は必要ありません。
bootstrapの主な要素
レスポンシブ対応
近年、デバイスの増加により、様々な解像度の環境でWebサイトが見られることになります。
スマホ・PC・タブレットなど、その全てに対応するためにいくつもファイルを作り、デバイスを判断して読み込むHTMLやCSSを変えるといった解決策は非常に非効率です。
そこで、画面の幅だけを頼りに、CSSを出し分け、たとえばPCでは3カラムでスマホでは1カラムといったことが、1つのHTML、1つのCSSで実現可能になりました。そういった実装をレスポンシブデザインと呼びます。
冒頭で提示したサイトは両方ともレスポンシブです。PCでご覧になっているのであれば、ブラウザの幅をぐりぐり変えてみてください。手っ取り早くわかると思います。
bootstrapはレスポンシブに対応しており、デザインが切り替わる境界は全部で3つあります。
すなわち、4つの解像度レンジでデザインを出し分けることが可能です。当然、クラス名の指定だけによって。
グリッドシステム
グリッドは網目と言った意味がありますが、例えば正方形の画像を8つ並べるのであれば、PCでは横4つ縦2つ、スマホでは横2つ縦4つ、といった出し分けが適切でしょう。
このようなブラウザ解像度に合わせたグリッドレイアウトのカスタマイズが、bootstrapでは非常に強力にサポートされています。
Redirecting…
基本的には横幅を12分割し、そのうちどれくらいをHTML要素に割り当てるかによって指定します。
さらに、さきほどの、PCでは横4つ縦2つ、スマホでは横2つ縦4つといった実装は、グリッドの要素1つ1つに対して、下記のようなクラス名を当ててやります。
<div class="row"> <!--行の開始--> <div class="col-xs-6 col-sm-3 col-md-3"></div> <!--このdivが1つの要素--> <div class="col-xs-6 col-sm-3 col-md-3"></div> <div class="col-xs-6 col-sm-3 col-md-3"></div> <div class="col-xs-6 col-sm-3 col-md-3"></div> <div class="col-xs-6 col-sm-3 col-md-3"></div> <div class="col-xs-6 col-sm-3 col-md-3"></div> <div class="col-xs-6 col-sm-3 col-md-3"></div> <div class="col-xs-6 col-sm-3 col-md-3"></div> </div> <!--行の終了-->
この例は、さきほどのページであれば、下記の部分に対応しています。
・PC表示
・スマホ表示
それぞれのクラス名を説明します。
col-xs-6
このうち、xs の部分と、6の部分が重要です。
xsはブラウザの横幅が768pxより小さいときに適用するという指定で、
6は、先述の、横幅を12分割したうち、6個分の幅を使う、ということです。
同時に、
col-sm-3
を指定していますが、
mdはブラウザの横幅が768px以上のときに適用するという指定で、
3は、12分割中3個分の幅を使う、ということになります。
さらに、
col-md-3
によって、ブラウザの横幅が992px以上の場合も指定しています。
なので、
ブラウザの横幅が992pxより小さいときは、親要素の幅の半分の幅の要素が8個並び、
ブラウザの横幅が992px以上のときは、親要素の幅の1/4の幅の要素が8個並ぶ
という指定になります。
ここで、ひとつの div class="row" の中に合計12を超える指定をしていることになりますが、12を超えるごとに折返されるので、問題はありません。
その他の要素
見出しやアオリ文などのデザインを定義したTypography群、テーブルやボタン、フォームなど、ありとあらゆるものがすでに定義されており、単にHTMLを書いたものに適用するだけで非常に見栄えの良いサイトになります。
JavaScript
さきほどグリッドのところで提示した画像の1つ1つはボタンになっており、ボタンを押すとモーダルが起動するようになっています。
これは、bootstrapに元々組み込まれているJavaScriptによって、起動用のIDをボタンに設定し、対応するIDをモーダルの要素に設定してやれば、それだけで動作をします。
当然、このモーダルの中にもグリッドシステムなどの使用が可能です。
画像はtwinviteでの動作例ですが、私はこのためのJavaScriptを1文字も書いていません。
この他にも様々な関数が用意されています。
twinviteへの適用
twinviteでは元々bootstrapが読み込まれているため、上記のような機能がすべて実装済みです。
twiplaやtweetviteでこったことをしようとして、HTMLタグにstyle属性をガリガリ書いている方であれば、これがどれほど強力なことかがわかるでしょう。
twinviteでは、linkタグやstyleタグが使えるため、そのようなことはもはや必要ありませんが、これらのタグはセキュリティ上の危険を孕むため、いつ使えなくなるかわかりません。
その日が来る前に、是非bootstrapの学習をオススメ致します。
ただし、1つだけ大変なところがあります。
それは、自由記述部分の横幅が、ブラウザの横幅と一致しないことです。
先程のグリッド部分を、同じ幅のブラウザで表示してみました。
・Webサイト
・twinvite
Webサイト方はグリッドシステムがブラウザの横幅すべてを使っているため4つ入りますが、twinviteでは自由記述部分はかなり狭くなるため4つ入れると画像のサイズが極めて小さくなってしまいます。
そのため、グリッドシステムだけは、調整しています。
といっても、 col-sm-6 のようなクラス名を書き換えてやるだけです。
総括
さまざまなイベントが増え続ける今、同じハコや同じテーマでイベントをやることも多いでしょう。
その際、他と違うことを強調したい場合に、凝った招待サイトを作るといったことは非常に有効な手段だと考えています。もしくは、周年記念回のときだけ凝ってみるとか。
気合の入れた宣伝ページを作ることは、そのイベントの本気度や意気込みにそのまま直結していきます。
本気のイベントを気合を入れて打ち出し、最高のイベントへと導くことは、本当に楽しいです。
この記事の内容は私のような職業エンジニアでなくとも、十分に達成できる難易度のものだと思っています。
私自身もそういった告知ページを見ることは好きなので、こういった技術が浸透することを願っています。
是非、気合の入ったページを見せてください。