きっかけ
コーディングの仕事を始めて1年、仕事でCSSを組む時、自分で学んだ知識である程度の物は組めるようになってきました。
今回は表示結果は同じでも、自分とは違うアプローチ方法を知りたくて既存のCSSフレームワークはどのように実装しているのか調べてみました。
その中で学びになったことを備忘録として記述します。
※記事内のCSSは必要な部分のみを抽出しています。
BULMA
列
<div class="columns">
<div class="column is-half">50%</div>
<div class="column">auto</div>
<div class="column">auto</div>
<div class="column">auto</div>
<div class="column">auto</div>
</div>
.columns {
display: flex;
}
.column {
flex-basis: 0;
flex-grow: 1;
flex-shrink: 1;
padding: .75rem;
}
.is-half {
width: 50%;
flex-grow: 0;
flex-shrink: 0;
flex-basis: auto;
}
flex-grow:余った余白を指定した比率で伸ばす。
flex-shrink:はみ出た横幅を指定した比率で縮める。
基本的に全て均等の横幅になります。
flex-grow,flex-shrinkを全て1に設定して要素の横幅を均等にしています。
is-half等のクラスをつけると残りのスペースで均等な横幅になります。
is-half等の横幅を指定した場合、felx-growとflex-shrinkを0にして要素が伸び縮みしないようにしています。
タイル
<div class="tile is-ancestor">
<div class="tile is-parent">
<div class="tile is-child">
<p class="title">タイル1</p>
</div>
<div class="tile is-child">
<p class="title">タイル2</p>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child">
<p class="title">タイル3</p>
</div>
</div>
</div>
</div>
.tile {
display: block;
align-items: stretch;
flex-basis: 0;
flex-grow: 1;
flex-shrink: 1;
min-height: min-content;
}
.tile.is-parent {
padding: .25rem;
}
.tile.is-child:not(:last-child) {
margin-bottom: .5rem !important;
}
.tile.is-vertical {
flex-direction: column;
}
.tile:not(.is-child) {
display: flex;
}
ancestor > parent > child という最低でも3つ階層が必要。
この手のレイアウトは自力で考えると結構時間が掛かるのですが、この方法をテンプレートとして覚えてしまえば素早く組めます。
is-childの最後の要素に対してmargin-bottomを削除する場合、自分なら
.tile.is-child:last-child {
margin-bottom: 0;
}
このように打ち消し用のCSSを作るのですが、:notを使うことで短く記述できるのが地味に学びポイント高いです。
利用頻度高いです。
<div class="tile is-ancestor">
<div class="tile is-vertical">
<div class="tile">
<div class="tile is-parent is-vertical">
<div class="tile is-child box">
<p class="title">タイル1</p>
</div>
<div class="tile is-child box">
<p class="title">タイル2</p>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child box">
<p class="title">タイル3</p>
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child box">
<p class="title">タイル4</p>
</div>
</div>
</div>
<div class="tile is-parent">
<div class="tile is-child box">
<p class="title">タイル5</p>
</div>
</div>
</div>
ネストさせる事で複雑なレイアウトも実装可能!
基本構造を組み合わせれば良いだけなので、HTMLの構造で迷わないのが素晴らしいです。
Hero
<section class="hero is-primary">
<div class="hero-body">
<div class="container">
<h1 class="title">タイトル</h1>
<h2 class="subtitle">サブタイトル</h2>
</div>
</div>
</section>
.hero {
align-items: stretch;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.hero-body {
flex-grow: 1;
flex-shrink: 0;
padding: 3rem 1.5rem;
}
.container {
margin: 30px auto;
font-weight: bold;
}
Heroって名前面白いですね。
色々プロパティ付いてますが画像のようなシンプルな構造の場合余白の設定だけで大丈夫。
hero-bodyなくても再現出来るが、背景が画像でCSSでオーバーレイしたい時はこの構造が参考になります。
heroに背景画像、hero-bodyにオーバーレイの設定をすることで実装できます。
Bootstrap
グリッドレイアウト
合計値が12になるように割り振るレイアウトです。
他のフレームワークでもよく見ました。
<div class="row">
<div class="col1"><p>1</p></div>
<div class="col3"><p>3</p></div>
<div class="col3"><p>3</p></div>
<div class="col5"><p>7</p></div>
</div>
ss
.row {
width: 100%;
display: flex;
flex-wrap: wrap;
}
.col1 {
flex: 0 0 percentage(1 / 12);
max-width: percentage(1 / 12);
}
.col2 {
flex: 0 0 percentage(2 / 12);
max-width: percentage(2 / 12);
}
.col3 {
flex: 0 0 percentage(3 / 12);
max-width: percentage(3 / 12);
}
// 省略
.col8 {
flex: 0 0 percentage(8 / 12);
max-width: percentage(8 / 12);
}
簡単なsassにするとこんな感じ。
percentage関数
計算結果を%に変換する。
percentageとはsassにあらかじめ備わった関数の1つ。
.item {
width: percentage(10px / 100px);
//width: 10%となる
}
xx.xxx%と書かれるよりも分かりやすいです。
media
<div class="media">
<img class="mr-3" src="sample.jpg">
<div class="media-body">
テキストテキストテキストテキスト
</div>
</div>
.media {
display: flex;
align-items: flex-start;
}
.media-body {
flex: 1;
}
.mr-3 {
margin-right: 1rem;
}
シンプルですね。
画像の位置を中央へ変更したい時はこちら
.align-self-center {
align-self: center;
}
input
<div class="input-group">
<input type="text" class="form-control">
<div class="input-group-append">
<span class="input-group-text" id="basic-addon2">submit</span>
</div>
</div>
.input-group {
display: flex;
}
.input-group > .form-control {
flex: 1 1 auto;
}
.form-control {
border-radius: .25rem;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.input-group-append {
margin-left: -1px;
}
.input-group-text {
border: 1px solid #ced4da;
border-radius: .25rem;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.form-control:focus {
z-index: 3;
color: #495057;
background-color: #fff;
border-color: #80bdff;
outline: 0;
box-shadow: 0 0 0 0.2rem rgba(0,123,255,.25);
}
一番勉強になったのはfocusの部分。
outlineだと横に要素がある時、枠線が画像のように被って困ったことがあったのですが・・・
box-shadowにz-indexを指定していました。
後は、送信ボタンにネガティブマージンを付けることでborderの被り部分を回避してるのが上手ですね。
Text wrapping and overflow
<div style="width:100px">
<div class="text-truncate">
テキストテキストテキストテキスト
</div>
</div>
.text-truncate {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
CSSのみではみ出たテキストを省略する方法。
方法よりも、クラス名が参考になりました。
truncate=切り捨てる
tailwindcss
最後はBULMA、Bootstrapとは違うタイプのフレームワークです。
こちらはユーティリティークラスを大量に集めたものになります。
「どこまでユーティリティーとして定義する?」と悩んだ記憶がありますが、tailwindcssは「全部だ!」というった感じ。
クラスの数は千差万別。今後ユーティリティークラスの名前に迷ったら真っ先にtailwindcssを参考にします。
<ul class="container p-0 mx-auto border-l border-r">
<li class="flex items-center border-t border-b px-4 py-4">
<div class="bg-grey mr-3 w-12 h-12"></div>
<div>
<div class="font-bold mb-1">タイトル</div>
<div class="text-sm">テキストテキストテキスト<br>テキストテキストテキスト</div>
</div>
</li>
<li class="flex items-center border-t border-b px-4 py-4">
<div class="bg-grey mr-3 w-12 h-12"></div>
<div>
<div class="font-bold mb-1">タイトル</div>
<div class="text-sm">テキストテキストテキスト<br>テキストテキストテキスト</div>
</div>
</li>
<li class="flex items-center border-t border-b px-4 py-4">
<div class="bg-grey mr-3 w-12 h-12"></div>
<div>
<div class="font-bold mb-1">タイトル</div>
<div class="text-sm">テキストテキストテキスト<br>テキストテキストテキスト</div>
</div>
</li>
</ul>
適当に組み合わせて組んでみました。
クラス名も直感的でわかりやすいのでほとんどドキュメントを見なくても組めます。サクサク組めて気持ち良いです。
迷ったら公式ドキュメントのDefault configurationを見ましょう。
前2つとは全く違うアプローチでした。
最後に
今まで自力でコーディングをしてきたのでフレームワークを使う機会はありませんでした。
今回フレームワークの実装方法を分析してみて自分の中の引き出しが増えたように思えます。
組み方以外にクラス名の付け方も参考になりました。