エイチームライフスタイルアドベントカレンダー2017、12日目です!
今回は 株式会社エイチームライフスタイル のデザイナー @themeaningof8 が担当します。
はじめに
私達デザイナーにとって、CSSは身近なものであり、日々の業務でもよく触るものです。
覚えたばかりの頃は、それはそれは楽しく触っていましたが、
日が経つにつれ、多人数で作業する際につらさをを感じる機会が増えてきました。
CSS、壊れないように設計するのって難しいですよね(白目)
設計で手を抜くと本当にどうしようもなくなってしまいます。
弊社では独自のコーディング規約を策定し、一定のクオリティを担保しているのですが、
今回、「そもそも技術でなんとか出来んのかな?」と学習する過程で、CSSをカプセル化する技術と出会い、
「今すぐ業務に導入したい!!」
と、めちゃめちゃテンションが上がった過程をお話したいと思います。
こんな人向け
- 普段からコーディングをやっているデザイナーの方
- CSSはつらい、なんとかしたい
- 現状のCSSをもっと効率化したい
- デザイナーは何で困ってるのか興味のあるエンジニア
CSSの一体何が辛いと感じているのか
そもそもなにがつらいと感じているか? ですが、
- クラス名考えるのがつらい
- ブラウザ対応がつらい(ベンダープリフィクス)
- 優先度書き換わるのつらい(書き換え効かない、とか)
- スコープがないのがつらい(諸悪の根源)
などがあげられます。
諸悪の根源、グローバルスコープ問題
「グローバルなスコープってなんぞや?」と思われたデザイナーもおられるかもしれませんので補足いたしますと、
CSSには範囲を限定する「スコープ」という考え方がありません。なので基本的にCSSは、ページ全体に影響を与えます。
「部分テンプレートファイルであろうが何であろうが」です。
こういうことってありませんか?
* 部分テンプレートファイル触ってページ全体表示崩れ
* さらに意図しないページでも表示崩れ
* どうしてもスタイルが当たらなかったので!important
連発
例を次にあげます。以下のようなボタンがあった時に
<button class="btn">送信</button>
.btn {
color: #ff0000;
}
パーシャルで要素自体を上書きしてしまうと、
「あれ?このボタン黒かったっけ?」となるわけです。
button {
color: #000000;
}
こんな感じに。
.btn {
color: #ff0000!important;
}
さらに、「急いでるし暫定で」とか言って!important
をつけちゃったりするわけですね(白目)
これが、パーシャルのCSSの範囲(スコープ)が限定できないことで起きる、
いわゆる**「グローバルスコープ問題」**です。
このような問題を解決する手法として、BEMなどのクラス名での運用方法もありますが、
クラス名冗長だなとか、結構学習コストかかるなとか、
あくまでも「現状のCSSを運用するためのルール」だと感じています。
ところが「CSSのカプセル化」という技術で、根本的にそれらの問題を解決することができます!
CSSのカプセル化とは・・・
文字通り、CSSをカプセルの中に閉じ込めてしまうことです。
上図でいうと、コンポーネント外のbutton要素を変更したとしても、コンポーネント内のbutton要素には影響がないですし、
逆にコンポーネント内の要素に変更を加えても、コンポーネント外の要素に影響を与えません。
機能実装時にページ崩れなど余計な心配をしなくていいのは気が楽ですし、
触った範囲の検証だけで済みます!
また、カプセル化されるということは、
装飾のためのクラスは最小限で済むというのもメリットかなと思います。
今まで装飾のためだけに沢山クラスをつけてきましたが、それからも解放されます!
これは今すぐにでも業務で使いたい・・・。
もう無駄にクラス名で悩む必要はないぞ!!!!
カプセル化を実現できる技術
今回は以下の2つを試してみました。
- Web Components(と Polymer)
- CSS in JS
##1. Web Components
Web Componentsは、WebページやWebアプリケーションの中で新たに、再利用可能でカプセル化された独自のHTMLタグを作成するためのWebプラットフォームのAPIです。
確かに最近目にする機会もようやく増えてきた気が・・・
既に各ブラウザ最新のバージョンであればPolyfillで対応可能なんですね。
https://www.webcomponents.org
◆ Shadow DOM
カプセル化をしている主な機能が、Shadow DOMです。
これによってコンポーネント内のカプセル化が実現できます。
<div class="submitButton">送信ボタンをここに出す</div>
<template id="submitButtonTemplate">
<style>
button {
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .3);
border-radius: 5px;
font-size: 20px;
font-weight: 700;
color: #ffffff;
text-transform: uppercase;
background-color: #ff0000;
}
span {
display: block;
font-size: 10px;
}
</style>
<!-- ここが表示されます -->
<button>
<a href="#"></a>
submit<span>送信する</span>
</button>
<!-- /ここが表示されます -->
</template>
const element = document.querySelector('.submitButton');
const shadow = element.attachShadow({
mode: "open"
});
// .submitButtonに#submitButtonTemplateの内容を表示
const template = document.querySelector('#submitButtonTemplate');
const clone = document.importNode(template.content, true);
shadow.appendChild(clone);
上記のサンプルで言うと、#submitButtonTemplate
内がカプセル化されています。
例えば、
button {
color: #000000;
}
このような記述がされてしまった場合、意図せずスタイルが上書きされてガッカリ、みたいな事ありませんか?
カプセル化されていればそのようそのような心配も無くなります。
◆ Polymer
Polymerは、カスタムの再利用可能なHTML要素を作成し、実行可能で保守可能なアプリケーションを構築するのに役立つJavaScriptライブラリです。(Polymer公式から)
要はWeb Componentsを使い易くしてくれるものみたいですね!
- Polymer CLIをインストール
PolymerにはCLIが用意してあるので、サクッとインストールしてしまいます。(npmとか細かいことは割愛)
npm install -g polymer-cli
次に作業用ファイルに移動して、
polymer init
で簡単に雛形が出来上がります!
今回はpolymer-2-starter-kit
で作ってみました。
- 中身を見てみる
中身を見てみると、あらかたテンプレートは用意されているみたいです!
<!-- Load your application shell -->
<link rel="import" href="src/my-app.html">
headタグの中でsrc/my-app.html
ってのをimportしてました。
ここを触るみたいですね!
ちなみにbodyタグ内は、
<body>
<my-app></my-app>
<noscript>
Please enable JavaScript to view this website.
</noscript>
<!-- Built with love using Polymer Starter Kit -->
</body>
これだけです!めっちゃシンプル。
中身はこんな感じ。
<!-- Main content -->
<app-header-layout has-scrolling-region>
<app-header slot="header" condenses reveals effects="waterfall">
<app-toolbar>
<paper-icon-button icon="my-icons:menu" drawer-toggle></paper-icon-button>
<div main-title>My App</div>
</app-toolbar>
</app-header>
<iron-pages
selected="[[page]]"
attr-for-selected="name"
fallback-selection="view404"
role="main">
<my-view1 name="view1"></my-view1>
<my-view2 name="view2"></my-view2>
<my-view3 name="view3"></my-view3>
<my-view404 name="view404"></my-view404>
</iron-pages>
</app-header-layout>
~ 使ってみて ~
- Shadow DOMには可能性を感じた
- Polymer CLIは思っていた以上に簡単だが、2.x系はbowerインストールしなきゃいけない
- ブラウザ実装が進まないと実務で使うのはもう少し先になりそう
##2. CSS in JS
文字通りCSSをJavaScriptに書いてしまうことで様々な問題を解決してしまおうというものです。
import React, { Component } from 'react';
import { StyleSheet, css } from 'aphrodite';
class App extends Component {
render() {
return <div>
<span className={css(styles.red)}>
This is red.
</span>
<span className={css(styles.hover)}>
This turns red on hover.
</span>
<span className={css(styles.small)}>
This turns red when the browser is less than 600px width.
</span>
<span className={css(styles.red, styles.blue)}>
This is blue.
</span>
<span className={css(styles.blue, styles.small)}>
This is blue and turns red when the browser is less than
600px width.
</span>
</div>;
}
}
const styles = StyleSheet.create({
red: {
backgroundColor: 'red'
},
blue: {
backgroundColor: 'blue'
},
hover: {
':hover': {
backgroundColor: 'red'
}
},
small: {
'@media (max-width: 600px)': {
backgroundColor: 'red',
}
}
});
こちらよりソースを拝借しております。
~ 使ってみて ~
- CLIやWebpackといったパッケージに依存しない
- CSSに変数突っ込んでみたいな使い方が簡単にできそう
- インラインでCSSを書き出すため、疑似クラスなどが使えない。CSSファイルと併用するか、同じ動きをJSで実装する必要がある
おわりに
私は普段業務でフロントエンドをがっつり触るわけではないのですが、
そんな私でも恩恵を受けられる技術だなと思いました。勉強してみて良かったと感じています。
CSSの辛さから解放されることは、デザイナーがよりUI/UXの向上に集中できるというメリットをもたらしてくれそうです。
今回CSS Modulesは残念ながら触れなかったのですが、CSS Modulesも有望そうですよね。
また、最近はAtomic Design初めデザイナーにもコンポーネント指向の考え方が求められてきていますし、こういった技術を知った上で新しいデザイン手法を取り入れると、より価値の高いデザインができるようになるのでは?と思います。
エイチームライフスタイルアドベントカレンダー2017、明日はデザイナーの @gilly さんがデザイナー視点からgitについて書いてくれます。お楽しみに!
株式会社エイチームライフスタイルでは、一緒に働けるチャレンジ精神旺盛な仲間を募集しています。興味を持たれた方はぜひエイチームグループ採用サイトを御覧ください。
http://www.a-tm.co.jp/recruit/