ものづくりカフェひつじ第1話「来店!マテリアルデザインの使者!」
※筆者は病気です。(精神的な意味で)オススメの精神科があればご一報ください。
※登場人物のモデルになった人であれば、口調の改変等OKです。
https://gyazo.com/622ecee8df0c4df6e130745aada36fca
舞台
https://gyazo.com/6ffda56ddd834c3318abf4fb28d2ebdf
ものづくりカフェひつじ
全席にコンセントとwifiを完備し、オライリーをはじめとする多くの技術書が置いてありエンジニアに愛されている。
コーヒーはお代わり自由。
日中はカフェ、夜は勉強会の会場として貸し出しており、この貸出料で日中の売り上げ不足を補っている。
登場人物
https://gyazo.com/25b4d8412ccf0cd1bbdd9009b32efdeb
ぜんの店長
猫の姿をしているのに人の言葉を喋る。
元は人間だったらしいという噂があるが、それを探ろうとしたものが次々と行方不明になっている。
普段はプログラムの実装に困っている客にアドバイスをしたりモフラれたりして過ごしている。
仕事は全てバイトに丸投げムーブしている。
語尾にニャをつけて喋るが、それはわざとであり素が出るとおっさんの声で関西弁になる。まさに猫かぶり。
https://gyazo.com/8f0180ff6965b70b6afefd71dd823a4c
マスター加藤
マスター加藤は実はただのニックネームのバイト。
ものづくりカフェひつじのコーヒー、デザート、軽食の開発及び提供などの業務を行なっている。
初見の客にはマスター加藤というニックネームも合間って、店長とよく勘違いされる。
この仕事を辞めて、フリーランスエンジニアになりたいらしいが、ぜんの店長に致命的な弱みを握られているため辞められず、社畜になってしまっている。
https://gyazo.com/e6db7f9ed8366b569b18ace13e0f1062
スティーブ
ものづくりカフェひつじの常連。
現在大学の2回生である。
日々興味のあることに挑戦しており、ものづくりカフェひつじでは他の客や店員などからアドバイスをもらいながら日進月歩している。
その場にいるだけでアメリカンコメディのようなノリを生み出す特殊能力を持っている。
https://lh3.googleusercontent.com/-Tx5RZOsOYzA/AAAAAAAAAAI/AAAAAAAAAHA/JM8Mkon027g/photo.jpg
マテリアルお兄さん
通称マテ兄(自称)
ものづくりカフェひつじに来店してはマテリアルデザインを布教している。
出禁一歩手前(ガチ)
プロローグ
zenno.icon 今日も平和だニャ〜
店長もたまには仕事手伝ってくださいよ ktr.icon
zenno.icon こんな体でどうやって何を手伝うニャ
カラーンカラーン
zenno.icon お客さんだニャ
ktr.icon いらっしゃいませ
こんにちは!マスター今日も元気? スティーブ.icon
ktr.icon スティーブさん今日もきてくれたんですね。いつもの席空いてますよ!
ありがとう!コーヒーをブラックで一杯頼むよ スティーブ.icon
ktr.icon かしこまりました
zenno.icon で、今日は何に挑戦するのかニャ
最近マテリアルデザインに興味があってガイドラインに従って色々UIを作って見ようかなって スティーブ.icon
zenno.icon マテリアルデザイン...嫌な予感がするニャ...
ktr.icon ブラックコーヒーお待たせしました
ありがとうございます(ニコッ)。さぁて、やるぞ! スティーブ.icon
https://gyazo.com/6c4e53bb3465d9ddf45ab1bf696385f2.png
本編
うーん スティーブ.icon
zenno.icon どうかしたのかニャ
マテリアルデザインのガイドラインにそったTextFieldが上手く作れなくて スティーブ.icon
バァァァーーーン!!(ドアが破壊される音)
good-loser.icon お困りのようだね!!!!!
にゃゃゃ!!店のドアがぁぁぁ!! zenno.icon
またあなたですか...(呆れ) ktr.icon
次迷惑行為したら出禁だって言ったニャ!! zenno.icon
スティーブ.icon 誰なんですか?この変な人は
good-loser.icon よくぞ聞いてくれた
good-loser.icon 私はマテリアルデザインの使者!マテリアルデザインを布教するために活動しているものだよ
ただの変質者だニャ zenno.icon
あぁいうのを社会不適合者って言うんでしょうね ktr.icon
good-loser.icon スティーブくん、TextFieldを作れずに困っているそうだね
そうなんですどんな風に作ればいいのかわからなくて スティーブ.icon
good-loser.icon 大丈夫!私がレクチャーしてあげよう!
えっと...じゃぁお願いします スティーブ.icon
good-loser.icon まず、作りたいTextFieldはこんな感じのものでいいのかな?
https://gyazo.com/b29fb3f307c1faac5401bb48ac8f2d72
そんな感じです! スティーブ.icon
good-loser.icon 承知!では始めよう
やっと本題ですか ktr.icon
長い前フリだニャ zenno.icon
good-loser.icon それじゃ、HTMLとCSSをまず見せよう
code:index.html
<div class="material-field">
<label for="material-input" class="material-input-label">
<!-- ラベルのテキスト -->
</label>
<div class="material-input-container">
<input id="material-input" class="material-input" type="text"/>
</div>
</div>
code:index.css
.material-field {
/*--- style ---*/
width: 100%;
border: 0;
display: inline-flex;
padding: 0;
position: relative;
min-width: 0;
/*--- end ---*/
/*--- layout ---*/
flex-direction: column;
vertical-align: top;
/*--- end ---*/
}
.material-input-label {
transition: color 200ms cubic-bezier(0.0, 0, 0.2, 1) 0ms, transform 200ms cubic-bezier(0.0, 0, 0.2, 1) 0ms
top: 0;
left: 0;
position: absolute;
transform: translate(0, 24px) scale(1);
transform-origin: top left;
color: rgba(255, 255, 255, 0.7);
padding: 0;
font-size: 1rem;
line-height: 1;
}
.material-input-label.focus {
}
.material-input-label.float {
transform: translate(0, 1.5px) scale(0.75);
transform-origin: top left;
}
label + .material-input-container {
margin-top: 16px;
}
.material-input-container {
/*--- style ---*/
position: relative;
cursor: text;
font-size: 1rem;
line-height: 1.1875em;
/*--- end ---*/
/*--- layout ---*/
display: inline-flex;
align-items: center;
/*--- end ---*/
}
.material-input-container::before {
left: 0;
right: 0;
bottom: 0;
content: "\00a0";
position: absolute;
transition: border-bottom-color 200ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
border-bottom: 1px solid rgba(255, 255, 255, 0.7);
pointer-events: none;
}
.material-input-container::after {
left: 0;
right: 0;
bottom: 0;
content: "";
position: absolute;
transform: scaleX(0);
transition: transform 200ms cubic-bezier(0.0, 0, 0.2, 1) 0ms;
pointer-events: none;
}
.material-input-containert.focus::after {
transform: scaleX(1);
}
.material-input {
outline: none;
font: inherit;
color: currentColor;
width: 100%;
border: 0;
margin: 0;
padding: 6px 0 7px;
display: block;
min-width: 0;
box-sizing: content-box;
background: none;
-webkit-tap-highlight-color: transparent;
}
うゎ...CSSがすごい多いな...でもjavascriptは必要ないんだね スティーブ.icon
good-loser.icon javascriptはクラスの付け外しに必要だけど、がっつり必要なわけじゃないんだ
クラスの付け外しくらいならわかります! スティーブ.icon
good-loser.icon よし!それじゃCSSを一つずつ解説して行こう!widthやborderなどの定番の解説は省くよ!
了解です! スティーブ.icon
good-loser.icon まずは.material-fieldのスタイルの解説だ!
https://gyazo.com/6c4e53bb3465d9ddf45ab1bf696385f2.png
display: inline-flex
good-loser.icon このスタイルで特筆するプロパティは display: inline-flex; だ
inline-flex?inline-boxは使ったことありますけど スティーブ.icon
good-loser.icon まさにそれに近いしいものだね。inline-flexはinlineの特性を持ったflexboxを定義しているんだ、flexでも問題なく動作するけどinlineの特性を持っていた方が都合がいいことが多いんだ。
inline要素じゃないと効かないスタイルもありますからね ktr.icon
そもそもHTMLのinputタグがinline-boxだからニャ zenno.icon
なるほど、出来るだけ元々の使い心地に寄せてるんですね! スティーブ.icon
good-loser.icon その通り
https://gyazo.com/6c4e53bb3465d9ddf45ab1bf696385f2.png
flex-direction: column
good-loser.icon 次はflex-direction: columnだ
flex-directionってことはflexに関係することなのかな? スティーブ.icon
good-loser.icon その通り、このプロパティはflexコンテナ内のアイテムの配置方法を指定しているんだ。デフォルトではflexアイテムは左から右に向かって配置される。だがこのプロパティを使えばそれを変えることができるんだ!
便利ですね! スティーブ.icon
good-loser.icon 今回指定したcolumnはアイテムを縦に積み重なるように配置しているんだ
なるほどこれで上からラベル、テキストフィールドの順で表示されるわけですね! スティーブ.icon
ちなみに逆順で表示するrow-reverseやcolumn-reverseもありますね ktr.icon
合わせて覚えて置くと後々役に立つニャ zenno.icon
https://gyazo.com/6c4e53bb3465d9ddf45ab1bf696385f2.png
vertical-align: top
good-loser.icon vertical-alignはテキストや画像などの縦方向の位置を指定する際に使うプロパティだ
今回はtopを指定しているから上揃えってことですね スティーブ.icon
good-loser.icon その通り!
ちなみにvertical-alignプロパティはインライン要素とテーブルセルにしか効かないので注意です ktr.icon
https://gyazo.com/6c4e53bb3465d9ddf45ab1bf696385f2.png
good-loser.icon 次は.material-input-labelのスタイルを見て行こう!これはラベルのスタイルを定義している部分だ
大事なところですね! スティーブ.icon
transition: color 200ms cubic-bezier(0.0, 0, 0.2, 1) 0ms, transform 200ms cubic-bezier(0.0, 0, 0.2, 1) 0ms
good-loser.icon まずはtransitionプロパティだ。transitionプロパティは4つのtransition関連のプロパティを左から順にスペース区切りでtransition-property、transition-duration、transition-timing-function、transition-delayを使って指定指定いるんだ。今回のようにカンマ区切りで複数指定もできる
なんかごちゃごちゃしてますね スティーブ.icon
good-loser.icon 一つずつ解説していこう。まずtransition-propertyはどのプロパティに時間的変化を適用するかの指定するプロパティだ
なるほど、今回の場合だとcolorとtransformプロパティが変わったときに時間的変化を適用してるわけですね。 スティーブ.icon
good-loser.icon その通り!次のtransition-durationは変化にかかる時間を指定するプロパティだ
えーと今回は200msだから0.2秒かけて変化するってことだね スティーブ.icon
good-loser.icon OK!次はtransition-timing-functionだが、こいつがわかりづらい、このプロパティは俗に言うイージングを実装するためのものだ
cubic-bezierとか言う初めて見るものが書いてありますね スティーブ.icon
good-loser.icon このcubic-bezierはcubic-bezier関数と呼ばれていて。cubic-bizier関数は4つの値を用いて下の図のような3次ベジェ曲線を指定して時間の経過に対する変化を作成することができるんだ。
https://gyazo.com/c2407322bfbbdca455e52ccd6d44027b
すごく難しそうですね... スティーブ.icon
good-loser.icon 大丈夫、マテリアルデザインのガイドラインにはどんなイージングが適切かcubic-bezier関数で書いてあるからそれを参考にすればいい。もし自分で作る必要ができても簡単に作成することができるサイトがあるよ。
ちなみにeaseやlinerのように値で指定することもできるのでそんなに心配しなくても大丈夫です ktr.icon
良かった!これを知っているかいないかでデザインに差が付きますね! スティーブ.icon
good-loser.icon 最後はtransition-delayだ。このプロパティは指定した時間が経過してから変化を開始するようにできるプロパティだ。delayの名の通り遅延を実装できるわけだ
今回だと0msですから遅延はなしってことですね! スティーブ.icon
https://gyazo.com/6c4e53bb3465d9ddf45ab1bf696385f2.png
transform: translate(0, 24px) scale(1);
good-loser.icon transformプロパティは要素の2D変形もしくは3D変形を適用適用するためのプロパティだ。スペース区切りで複数の値を指定することができる。
今回はtranslateとscaleが指定されてますね スティーブ.icon
good-loser.icon 例のごとく一つずつ解説していこう。まずはtranslateだ。これは要素を移動距離を指定するときに使う値だ。今回の値の指定の仕方だとtranslate(x方向の移動距離, y方向の移動距離)になるからX方向には移動せず、Y方向に24px移動ってことになる。
なるほどこれがないとラベルがイメージする位置にこないわけですね スティーブ.icon
good-loser.icon その通り
ちなみに他にもtranslateXやtranslateY、translate3dなどがあるニャ zenno.icon
えっ?じゃあtranslateYでいいんじゃないの? スティーブ.icon
good-loser.icon シャラップ!!好みの問題だ!
※まじで好みの問題です
次はscaleですね!名前からして縮尺を指定するものなのかな? スティーブ.icon
good-loser.icon その通り!コツを掴んできたねスティーブ!scaleは本来のサイズを1として値を指定して行くんだ。1より大きければスケールアップ、1より小さければスケールダウンと言った具合だ
なるほど、あれ?でもtranslateの時と違って一つしか値が指定されてませんね スティーブ.icon
good-loser.icon sclaleは1つしか値を指定しなければ縦横比を保ったままスケールアップ、スケールダウンすることができるんだ
へぇー便利ですね!(あれ?scale(1)ってそもそも指定しなくていいんじゃ) スティーブ.icon
scaleにもscaleXやscaleY、scale3dなどがあるニャ zenno.icon
ktr.icon ちなみに今回のように複数の値を指定するときはスペース区切りで必ず指定しましょう。transformプロパティを複数宣言しても新しいtransformで上書きされてしまうので気をつけましょう
https://gyazo.com/6c4e53bb3465d9ddf45ab1bf696385f2.png
transform-origin: top left
transform-origin。名前からしてtransform関連ですね スティーブ.icon
good-loser.icon そう、transform-originは名前の通りtransformの起点を指定するためのプロパティだ。今回はtopとleftの二つの値を指定しているから左上を起点にするってことだね
なるほどラベルが左上から降りてくる様に見えるのはこのプロパティのおかげなんですね スティーブ.icon
他にもcenterやpxでの指定もできるニャ zenno.icon
https://gyazo.com/6c4e53bb3465d9ddf45ab1bf696385f2.png
クラス付け替え時のスタイル
good-loser.icon 次はラベルにクラスを付与した時のスタイルだ。まずは簡単なfocusクラスが追加されている時のスタイルだ。
colorプロパティだけ定義されていますね スティーブ.icon
good-loser.icon これはinputにフォーカスされた際にラベルのテキスカラーを変えるために定義してある。
確かに色が変わってますね スティーブ.icon
good-loser.icon それだけだ。次はfloatクラスのスタイルだ。floatクラスにはtransform: translate(0, 1.5px) scale(0.75)が定義してある。
あれ?translateのY方向の値がマイナスじゃないですけどさらに下に行っちゃいません? スティーブ.icon
good-loser.icon さっきマスター加藤が注意点として言っていたけどtransformは宣言が重複すると新しいものに上書きされる。つまりこの場合は本来の位置から1.5px下に移動するということで、実際は24px - 1.5px = 22.5px上に移動していることになるんだ
なるほど!それとscale(0.75)でスケールダウンをして、さっきと同じ様にtransform-originで左上を起点にして滑らかなアニメーションを作ってるんですね! スティーブ.icon
https://gyazo.com/6c4e53bb3465d9ddf45ab1bf696385f2.png
label + .material-input-container
good-loser.icon このセレクタに書いてあるスタイルmargin-topと大したことがないが、これがないとTextFieldの部分がラベルにめり込むことになるので注意してほしい
ありきたりだからこそケアレスミスしちゃいそうなところですね スティーブ.icon
https://gyazo.com/6c4e53bb3465d9ddf45ab1bf696385f2.png
before&after
good-loser.icon さぁここからはいよいよTextField周りのスタイルの解説に入っていくぜ!普通のセレクタには...解説するところがないな...
この::beforeとか::afterって何ですか?:hoverとかならよく使うんですが... スティーブ.icon
ktr.icon おや?擬似要素をご存知ないとは珍しい
まぁ初心者にはわかりずらいし敬遠されがちな要素だからニャ zenno.icon
擬似要素? スティーブ.icon
good-loser.icon よろしい、では擬似要素の説明から入ろう。擬似要素とは名前の通り要素の様なもので本来のHTMLには書かれていない
ktr.icon beforeなら要素の直前に
zenno.icon afterなら要素の直後に擬似要素が挿入されるニャ。例えば
code:index.html
<div>テキスト</div>
zenno.icon このdivタグにbeforeとafterが挿入されると
code:index.html
<div>
::before
テキスト
::after
</div>
zenno.icon こんな感じの位置に挿入されるのニャ
なるほど、でもこれを使うメリットってあるんですか?複雑になるだけじゃ? スティーブ.icon
ktr.icon よくある質問だね。スティーブさんは見た目のカスタマイズのためだけに要素を作ったりしてないかい?
ありますね。なるほど擬似要素を使えばそういう無駄がなくなるんですね! スティーブ.icon
zenno.icon それだけじゃないニャ。擬似要素は検索エンジンからだとCSSだから、SEOも向上するニャ
good-loser.icon 大体わかったかな?ちなみに今回はTextFieldの下線を表現するために使っているんだ
https://gyazo.com/6c4e53bb3465d9ddf45ab1bf696385f2.png
content
good-loser.icon じゃあまずはbeforeの方から解説していこうか。擬似要素を知らなかったってことはcontentプロパティも知らないのかな?
そうですね。 スティーブ.icon
good-loser.icon 了解! contentプロパティは擬似要素にのみ適用できるんだ擬似要素に文字列や画像を挿入するときに使用するんだ。
なるほど、でも\00a0って何でこんな変な文字列なの? スティーブ.icon
good-loser.icon この\00a0はUnicodeエスケープシーケンスでスペースを意味するんだ。普通にスペースを入れただけじゃちゃんとスペースが入らないんだ。ちなみにこのcontentを指定いないと擬似要素は生成されないから注意だ!
\00a0の意味はわかったけど何でスペースが必要なんですか? スティーブ.icon
good-loser.icon 解説のためだ(キリッ
https://gyazo.com/6c4e53bb3465d9ddf45ab1bf696385f2.png
pointer-events: none
good-loser.icon point-events: noneはマウスイベントを無効にすることができるプロパティだ
これは結構使い道ありそうですね スティーブ.icon
ktr.icon ちなみにSVG要素以外ではautoかnoneしか指定できませんが、SVG要素にはstrokeやfillなどの値が指定できイベントの対象を変更する場合にも使えます
https://gyazo.com/6c4e53bb3465d9ddf45ab1bf696385f2.png
transform: scaleX(0)
good-loser.icon 次はafterを解説していこう。と言ってももうほとんど解説してしまっているんだよね
あれ?transform: scaleX(0)って何も表示されないんじゃスティーブ.icon
good-loser.icon あぁ、このafterはフォーカスが当たった時の下線だから初めは非表示にしてるんだ
それでfocusクラスが追加された時のafterにtransform: scaleX(1)が指定されているんですね スティーブ.icon
good-loser.icon その通り!ちなみにscaleY(0)でも非表示になるけどscaleXを使っているのは真ん中から横方向に広がる様にアニメーションされるからだ
エピローグ
good-loser.icon ふぅ、とりあえず解説が必要なのはこの位かな?どうかな理解できたかい?
おぉ上手く実装できました! スティーブ.icon
good-loser.icon 良かった良かった。ちなみに今回作ったベーシックなTextField以外にもマテリアルデザインにはOutlined TextField, Filled TextFieldもあるからチャレンジしてみてくれ
はい!挑戦してみます! スティーブ.icon
一件落着だにゃ zenno.icon
ktr.icon キリもいい様ですが、もうすぐ閉店ですよスティーブさん
もうこんな時間ですか、じゃあそろそろ失礼します スティーブ.icon
また明日も来るといいニャ zenno.icon
そうさせてもらいます! スティーブ.icon
good-loser.icon そうさせてもらおうか
あっ、あなたはもう出禁です。次きたら通報します。 ktr.icon
good-loser.icon えっ
次回予告
レスポンシブデザインを実装しようとしたスティーブの前にフォントサイズが立ちはだかる。
font-sizeごときと甘くみていたツケが回る。いつだって本当に怖いものは日常にあるものだとわかっていたはずなのに...
次回!「翻弄するフォントサイズ!店長のAnleitung!」