<picture>まわり雑感 その1

Chrome 38が出て<picture>が有効になったので、いくつか記事を訳した。

HTML5 Rocksのは<picture>の簡単な使い方をざっと紹介。Dev.Operaのネイティブうんぬんは<picture><img srcset>, <img sizes>を細かく説明。もひとつのDev.Operaのサンプルのやつはユースケースごとに組み合わせをいろいろ書いたサンプル。それぞれ少しずつ違っている。おすすめは2つ目。ちょっと長いけど、書いているのがBlink, WebKit<picture>とかを実装しているYoavなので。

以下いろいろ。

だいたい<img srcset>で事足りる気がする

要素ということもあって<picture>に目が向きがちだけれど、“Don’t use (most of the time)”などで言われているとおり何が何でも<picture>つかえというわけではない。

使うのは<img srcset>Retina対応(x デスクリプタ使うやつ)が多いのではないか。他の属性やら<picture>はResponsive Web Designでの利用が多そうだけれど、Retina対応はRWD関係なくやりたいことだろうから。

なので基本的にはこんなコードでよさそう。2xな画像を書いたsrcsetをつけるだけという。

<img srcset="image-2x.png 2x" src="image.png" alt="...">

ただiPhoneさまが3xになったので、3xな画像を…といきっちゃうかもしれない。そしたらこうだ。

<img srcset="image-2x.png 2x, image-3x.png 3x" src="image.png" alt="...">

画像リソースの数は増えるけれど、マークアップが複雑になったとはまだ言わなくてもいいレベルではないか…な。

3xいるのかね

さて、3x。そんなに要らないのではないかと思っている。というのは1x→2xほどのぼけ具合がないから(個人の感想です)。

Androidは昨年秋から3x時代に入ってるのだけれど、アプリのアイコンやアセットで3xなものがあるのはまだ多くない。たとえばLINEとか、スタンプがうっすらぼやけたりしている。 とはいえアプリの対応とかはiPhoneが牽引している感があるので、iPhone 6 Plusが発売されたいま、3xな画像が増えてくるのかなとも思う。

でもね…あまりにもバリエーションが増えすぎてしまうと作成や管理の面でもえらく大変になるだろうし、3xや4xが出たからといって純朴に対応しているとすりきれてしまうのではないか。

軽く調べた感じだと、いまのところAppleapple.comで3xな画像を出していない。iPhone 6 Plusは3xといっても、幅1242pxな画面を1080pxに縮小して表示とすごいことになってるので、単純に2xのアセットを3xで表示した見た目になるわけではない。なのでぼけ度合いは2xなものを3xでというものよりは多少よいのかもしれない。

<img>ではコントロールできない

srcsetsizesで指定する画像はあくまで「ヒント」なので、「意図とは違った画像が表示されるかも」というのは頭の片隅に置いとくといいかもしれない。

たとえば「重いしRetinaなんかいらねえよ」みたいなオプションが設定についたり、ブラウザがそこら辺賢くなってくれたりすると(Operaとかやりそうな気がする)、2x/3xなディスプレイでも1xな画像を出しちゃうなんてことが起こるだろう。

最近だとBlinkで、リサイズ時にすでに高解像度の画像がある場合は、candidateが変化してもそれをダウンロードしなくなった。軽くバグな気もするけれど……

<picture><source>でコントロールできなくもない

「コントロールできないのはちょっと…」というケースはあまりあってほしくないけれどあるかもしれない。<picture><source>を使えば、コントロールさせることも一応できる。<source>はヒントではなく「命令」になるからだ。

たとえば、2xには2xな画像を、3xには3xなそれを確実に提供したい場合はこうなるだろう。

<picture>
  <source media="(min-resolution: 3dppx)" srcset="image-3x.png">
  <source media="(min-resolution: 2dppx)" srcset="image-2x.png">
  <img src="image.png" alt="...">
</picture>
  • srcsetに画像をならべるのではなく、<picture><source>をならべる
  • srcset内の3xの代わりにmediamin-resolution: 3dppxを使う

1行でだいたい同じものが書けてたのにだいぶ大げさになった。Webでコントロールを求めればめんどくさくなるのだ、というのを暗に伝えたいのかもしれない。

もちろん、art directionのように画像を意図どおりに切り替えたいというケースはある。それはちゃんと<picture>を使わないとだめだろう。でもそうでない場合はなるべく減らして、ブラウザに任せたほうが賢いかなと。


マークアップとスタイルのseparation of concernsあたりについても書こうと思ったのだけど、考えがまとまってないのでとりあえず。

<script async>でJavaScriptの非同期読み込みを

JavaScriptファイルをスクリプトから非同期で読み込むパターンは古い、という話を目にしたのはもう半年前のこと。

言ったのはIlya Grigorik。月末のGoogle Japanでのイベント月初のHTTP2ConferenceにくるWebパフォーマンス界のすごいひとですよ。


件のパターンは、スクリプトで動的に script を生成して、そこに読み込みたいJavaScriptファイルをぶっこんで読み込むというもの。

<script>
    var script = document.createElement('script');
    script.src = "//somehost.com/awesome-widget.js";
    document.getElementsByTagName('head')[0].appendChild(script);
</script>

ところが、こうしてしまうとスクリプト中のURL(ここでは //somehost.com/awesome-widget.js)がブラウザのプリロードスキャナにひっかからないこと、そしてこのスクリプトの実行がCSSOMの構築を待つために、遅くなっちゃうんだと。

で、HTML5から導入された <script async> を使えば、非同期で読み込まれるし、プリロードスキャナの恩恵にも預かれるとのこと。サポート状況も良くなってきたので、そっち使ったほうがいいのではないかと。

<script src="//somehost.com/awesome-widget.js" async></script>

シンプル。古のスクリプト読み込みが戻ってきた感。こういうハックなしにいいことできるようになってほしいよね。

ソーシャルボタンの読み込み部分を書き換える

さて、このIlyaのエントリが公開されてからしばらくして、スクリプトで非同期読み込みをしていた+1ボタン<script async> を使うものに変わった。こんな感じになった。

<!-- スクリプト -->
<script src="https://apis.google.com/js/platform.js" async defer></script>

<!-- ボタン -->
<div class="g-plusone" data-annotation="none"></div>

実質2行。シンプル。

で、他のソーシャルボタン系も書き換えられないかと思ってやってみた。読み込むパターンはだいたい同じなので、そんな大した労力ではないはず。

Facebook

<div id="fb-root"></div>
<script>(function(d, s, id) {
  var js, fjs = d.getElementsByTagName(s)[0];
  if (d.getElementById(id)) return;
  js = d.createElement(s); js.id = id;
  js.src = "//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.0";
  fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>

こうなった。

<script src="//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.0" id="facebook-jssdk" async></script>

<div id="fb-root"></div> どうしようかなと思ったのだけど、なくても自動挿入されるので省いちゃった。

Twitter

<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script>

こうなった。

<script src="//platform.twitter.com/widgets.js" id="twitter-wjs" async></script>

プロトコルを判別するコードは、protocol relativeなURLにした。

はてなブックマーク

ボタンのページ見たら、すでに <script async> 使うようになってた。わーい。

<script type="text/javascript" src="http://b.st-hatena.com/js/bookmark_button.js" charset="utf-8" async="async"></script>

関数を使った読み込みも書き換えてみる

身の回りでそれ系のボタンを使うときは、「ソーシャルボタンはお友達さ(・ω — MOL」にある非同期読み込みをする関数をベースにしたものを使っていた。

<div id="fb-root"></div>
<script>(function(d, s) {
  var js, fjs = d.getElementsByTagName(s)[0], load = function(url, id) {
    if (d.getElementById(id)) {return;}
    js = d.createElement(s); js.src = url; js.id = id;
    fjs.parentNode.insertBefore(js, fjs);
  };
  load('//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.0', 'facebook-jssdk');
  load('https://apis.google.com/js/plusone.js', 'gplus1js');
  load('//platform.twitter.com/widgets.js', 'tweetjs');
}(document, 'script'));</script>

これがこうなった。

<script src="//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.0" id="facebook-jssdk" async></script>
<script src="https://apis.google.com/js/platform.js" async defer></script>
<script src="//platform.twitter.com/widgets.js" id="twitter-wjs" async></script>
<script src="http://b.st-hatena.com/js/bookmark_button.js" async></script>

はてなを加えても4行。わーい。

以前だったかLikeボタンを設定する時に、読み込む関数のなかでパラメータを設定してた記憶がある。そうだったらちょっと面倒だなと思っていたのだけれど、最近のソーシャルボタン系はURLのクエリーやら data- 属性で指定できるのね。なのでとくに必要なかった。

もしある場合はどうしようかね。元のコードを見るしかないからどうも言えないか。


いまのところLikeボタンもTweetボタンもちゃんと動いているっぽい。他の非同期読み込み系だとGoogle Analyticsがあるけど、あれも読み込み部分は書き換えられそう。

-webkit-alt プロパティ

これを読んでいて、内容とはまったく関係ないのだけれど -webkit-alt プロパティのことを思い出した。昨年11月に実装されたgenerated contentの読みを提供するためのプロパティだ。

実装された時期的にSafari 8/iOS8 Safariに入っててもおかしくないのだけれど、どうなのかな。誰か確かめておくれ。

装飾的なテキストをつける場合に、擬似要素にぶっこむという方法がある。

[data-new]::after {
  content: "\2730”; /* a.k.a. ✰ , literally “shadowed white star”  */
}

これでOKとおもいきや、どうやらVoiceOverはgenerated contentも読み上げてしまって、この星印を“shadowed white star”と読んでしまうらしい。DOMに存在してたらARIAの属性つけられるけれど、擬似要素なのでそうもいかない。そこで読みを提供するプロパティを導入したいと。

[data-new]::after {
  content: "\2730”;
  -webkit-alt: "New";
}

attr() も使えるので、ローカライズもしやすいとのこと。

[data-new]::after {
  content: "\2730”;
  -webkit-alt: attr(data-new);
}

ふうむ。擬似要素にテキストぶっこむというケースがどれくらいあるのかわかんないのだけど、広くサポートされる時代はすごく先になりそうだなあ。


これもまた全然関係ないのだけれど、絵文字を見る機会が増えてきた。ただ、グリフのデザインがよくないのか「これなんだろう?」と思ってしまう文字が多いのだよね。とくにぼくはケータイ持つのが遅くて絵文字の読解に慣れてないというのもあり、ハンディキャップというかなんかそういうのを感じている。絵文字イリテラシーというのかね。

meta-contactを使わずに連絡先をマークアップできないか

blink-devにこんなメッセージが。

たとえばおさいふ落とした時に銀行やカード会社に連絡とかしづらいから、電話番号、メールアドレス、住所を <meta name="contact"> なるものにぶっこんで、緊急な際にそのWebサイトに行く→ブラウザのメニューから「Call」ですぐ連絡できるよ!といったアイデアの実現をSamsungが考えているようで。そうですか……

なんでもこの電話、メール、住所のタプルは複数指定できるらしい。

<meta name="contact" content="Chicago: +1-555-555-5555 abc@xyz.com '5844 South Oak Street, Chicago, Illinois'; Brookfield: +1-444-444-4444 def@xyz.com '2341 Cherry Lane, Brookfield, Illinois'; Naperville: +1-333-333-3333 jkl@xyz.com '515 W. Jefferson, Naperville, Illinois 60540'">

おおう……

先月にはWHATWGでだいたい同じような提案をしていたようで。

この当時は website-mail, website-number, website-address と別のプロパティだったのにまとめられてしまった。どうしてそうなった。

website-mail<link>mailto: なURLにせいや」というコメントがあったんだけど「リンクタイプの拡張は仕様書き換えないといけないし…」という理由で <meta> らしい。違うんだけどさ。でもこういう標準化トラックの誤解はけっこうあるのだろうなあ。わかりやすさが必要ですね。

いまあるものでどうにかできないか

「電話番号」「メールアドレス」「住所」というプロパティを考えると、すでにボキャブラリはある。vCardとかSchema.orgとか。HTMLへの埋め込みについても、MicroformatsMicrodata、RDFaとかがある。Microformatsはvisible metadata志向なのでとりあえず除外しよう。

Microdata

MicrodataSchema.orgだとこうなる。

<meta itemscope itemtype="http://schema.org/Organization" itemref="tel email adr">
<meta itemprop="telephone" content="+810000000000" id="tel">
<meta itemprop="email" content="foo@example.com" id="email">
<meta itemprop="location" content="123 Bar St. ..." id="adr">

<meta> でやろうとすると入れ子にできないので itemref でプロパティそれぞれにつけた id を参照しないといけない。結果ちょっとつらくなる。あと itemscope のための <meta> もうれしくないね。 location のExpected Typeは PostalAddressPlace なので本当はもういっこ itemscope が増えてしまうのだけど、ちょっと楽をした。

Microdataもコンテンツがそれなりに構造化されてマークアップされていることをどこかで求めているので、フラットな meta だけだと無理がくる。入れ子にできたところで開発者は入れ子を嫌う(偏見)ので、受けが悪そうな気がする。

RDFa

RDFaだとこうかなあ。

<meta typeof="schema:Organization" resource="#contact">
<meta property="schema:telephone" content="+810000000000" resource="#contact">
<meta property="schema:email" content="foo@example.com" resource="#contact">
<meta property="schema:location" content="123 Bar St. ..." resource="#contact">

すっきり書けるかなと思ったけどそんな変わらなかった。

まずはSchema.org名前空間。RDFa 1.1だとschema接頭辞が組み込まれてるので vocab を省ける。ただ接頭辞が長いので名前がちょっと長たらしい。

<meta> が入れ子にできない問題は resource 属性でてきとうなURIをリソースに与えプロパティから参照させることで解決。Microdataitemrefitemscope からプロパティという一方向で、かつ id を再利用するのでプロパティそれぞれに別個の識別子をふらないといけないのがだるい。RDFaは resource なる新しい属性を導入したので、双方向にできている。

あと、最初に typeof のためだけの <meta> を入れてるけど、この部分はプロパティのある要素に移動できるので、要素の数は3つに減らせたりする。

<meta property="schema:telephone" content="+810000000000" typeof="schema:Organization" resource="#contact">
<meta property="schema:email" content="foo@example.com" resource="#contact">
<meta property="schema:location" content="123 Bar St. ..." resource="#contact">

3要素に全部 typeof 入れられもする。そうするとひとつの <meta> に依存しない利点がある。しないけど。

データ的には嬉しくないだろうけど、typeof とっちゃうのもありかもしれない。

<meta property="schema:telephone" content="+810000000000" resource="#contact">
<meta property="schema:email" content="foo@example.com" resource="#contact">
<meta property="schema:location" content="123 Bar St. ..." resource="#contact">

こうすると、resource がちょっと余計に見えるけど、まあお約束ということにすれば。


というわけで、各プロパティが分かれてる場合、RDFaだとただの <meta> とだいたい同じくらいの楽さで同じことができそうではある。Schema.orgだとほんとはContactPointのほうが良さそうだけど、まあ。

<meta name="contact">ワンライナー的なものだからできない。こういう時にRDF/XMLみたいな要素としても属性としても書けるっていうバーサタイルなものが欲しくなるけど、不幸しか呼ばないだろう。

フラットになると抜けるもの

ただまあ、MicrodataやRDFaつかうとなると、MicrodataやRDFaの仕組みを実装しないといけない感がでてしまうので敬遠されるだろうなあという気はする。ただの <meta> にすれば、特定の名前に対して処理を決めうちしてやればいいので楽だ。resource とかも必要ないし。

ただ「情報」として考えると無理がある。さっき「フラットな <meta>」と書いたけど、これはWebページというスコープが暗黙にあるからフラットになっている。連絡先はページにも関連するかもしれないけど、もとの提案は銀行の支店とかを考えているようなのでページとは直接関係しない情報だ。ページに直接関わらないものを <meta name="foo"> に押し込むような名前と処理を定義してもいいんだろうけど、だいぶ乱暴ではないか。

拡張ごとにマイクロシンタックスを増やすのは、健康的ではないよね。そういう点でOGPはだいぶ頑張ったしえらいなという気はする。

もうちょっと自由度が低くて、でも書くぶんにはふつうの <meta> と変わらないRDFaのサブセットがあればいいのかもしれない。resource さえ許容できれば、さっき書いたのでだいぶいい線いってるとは思うけど。

ServiceWorkerの記事を書いた&所感

HTML5 Experts.jpにServiceWorkerの記事を書いた。

Google I/Oで見たServiceWorkerのセッションを紹介したもの。セッションの内容を文字にして説明しているという雑な記事。セッションのビデオを見るよりは早いかと思うので、見てない人にはよいかと。見ている人は…なんだろ、紹介されたコードにちょっとコメント入れたので、それを……

コードで思い出した。サンプルで&&amp;になってしまってるんだけど、なんかWordPressプラグインのせいなのかどうしても直せなかった。Syntax Highlighting的なプラグインもよくわからず使えず…WP力が低い。

記事を書いていていろいろ考えたことがあったので以下雑多に後記てきなものをば。

ServiceWorkerの更新

記事でも書いたけども、そんな触れられてなかったSWの更新についてちょっとだけ広げる。

AppCacheの「セットされたら最後」問題をアドレスするため、ServiceWorkerではブラウザが最低でも24時間に一度はSWの更新チェックをすることになっている。FetchしてみてSWが更新されていれば、そのSWのoninstallハンドラを実行する。だいたいキャッシュの追加とかになると思う。

oninstallハンドラが処理されたあとは待機状態になる。待機する理由は前のバージョンのSWが実行されているタブがあったりすると問題だから。前のバージョンがコントロールしているアプリがすべて終了したら新しいSWが起動して、activateイベントが発火する。なのでSWにonactivateハンドラを書いとけばそれが処理される。activatefetchが発火する前に必ず発火するようになってるので、破壊的?な処理はここですることになると。

待機せずに新しいSWをすぐ使わせたい場合は、oninstallハンドラ内でe.replace()を実行すると入れ替わってくれる。キャッシュに追加し忘れたものを追加したとか、そういう小さい&致命的なfailureが起こらない場合はこれを使ってもいいのかなと。

ちょっと気になってるのが、v2が待機状態になる前にoninstallが走ること。ちゃんと仕様読んでないだけなんだけど、以下の場合どうなるのかなと。

  1. v1インストールで https://example.com/foo.png をキャッシュ
  2. v2開発。foo.png がちょう変わる
  3. v2インストールでその新しい foo.png をキャッシュ
  4. 開きっぱのタブがあってv2が待機状態に
  5. foo.pngへのfetchが行われる

こうなったとき、v2のキャッシュ参照されたりしないのかなと。ちゃんと仕様読もうか……

named Cache

セッションや紹介記事とかで、最初のinstall時にキャッシュに“static-v1”という名前をつけて静的リソースをキャッシュさせている。

this.oninstall = function (e) {
  e.waitUntil(
    caches.create('static-v1').then(function (cache) {
      return cache.add(
        '/', // ...
      )
    })
  )
}

Cacheオブジェクトは自動では消えないのでかなり面白いんだけど、この「自動で消えないものに名前を付けられる」というところで、特定の特定のnamed cache前提のコードを書いてしまうケースがあるのではないかとちょっと思った。

// v1
this.oninstall = function (e) {
  e.waitUntil(
    caches.create('static-images').then(function (cache) {
      return cache.add(
        '/img/...',
        '/img/icons/...',
        // ...

v1時にこういう画像のキャッシュを用意したとする。その後バージョンを上げるんだけど、使ってる画像は一緒ということで、常に「static-images」なCacheを参照するようにしちゃう。

// v2
this.onfetch = function (e) {
  if (e.request.context === 'image') {
    e.respondWith(
      caches.get('static-images').then(function(responses) {
        return responses[0]
      }
    ).catch(function () {
      return e.default()
    })
  }
}

で、「画像変えてないのにインストール時にFetch走るとかやだよね、消そっか」みたいなノリでoninstall内の caches.create('static-images') なところを消してしまった。これで何が起こるかというと、v2以降に始めてアクセスした人には「static-images」なキャッシュが作られないので、悲しくなると。

単なる思考実験ではあるんだけど、

  • Webという「インストール」の概念がなかったものにそれがもたらされる
  • 自動では消えないキャッシュを用意でき、さらに参照しやすい名前までつけられる

というのがあるので、最初から継続的に開発しているひとだと変にこういう状態に陥ったりしないかなと。

開発ツール側にもSWにくっついたCacheを削除するとかそういうオプションは要るだろうなあ。

Fetchのrequest context

SWのセッションを見てておもしろかったのが、テンプレート適用やら画像のトランスコードやら、オフラインに限らないプロキシ的な使い方をするところ。

画像のトランスコードなんかは、フォーマットに対応してないブラウザでの表示だけじゃなく、対応してるブラウザで画像をダウンロードさせたときにも使えるかなと思った。ほら、WebPファイルダウンロードできても困るケースはけっこうあると思うので。

Fetch仕様ではrequest contextにdownloadなんてものがある。<a download href='blah'>なリソースのfetchはそんなコンテキストらしい。これがSWでも取得できたら画像をURI化したものをhrefにぶっこんどいて、onfetch内でひっかけられたらなと。

<a href="foo.webp" download>donwload image</a>
this.onfetch = function (e) {
  if (e.request.context === 'donwload') {
    e.respondWith(
      e.default().then(function (r) {
        if (r.headers.get('content-type') === 'image/webp') {
          return transcode(r.body);
        } else {
          return r;
        }
      })
    )
  }
})

こんなことができるとなあと思ってたんだけど、FetchEvent.contextにはdownloadがなかった…うおお。

表現のコンポーネントとエレメント指向

Google I/Oに行ってきたのでそれ関連の話題を。

Paper Elementsのエフェクト要素

Material Designというデザイン言語が出て、そのWebへの適用手段としてPolymerPaper elementsが発表された。

CodeLabsでもPolymerとPaper ElementsでTodoリストアプリをPolymerとPaper Elementsで作るというコースがあった。この中に、エフェクトを指定するステップがある。ここでほーと思ったのが、影をキャストする際にはpaper-shadowを、波紋の効果を出すpaper-rippleを使うこと。エフェクトが要素になっているのだ。

表現が必ず要素化されているわけでもない。固定化されたツールバーがあって、スクロールし始めた際に下のコンテンツから浮き出るような表現をMaterial Designではwaterfallと呼んでるのだけど、ツールバーにその表現を与えるにはmode="waterfall"という属性をつけてやるらしい。

エフェクトのコンポーネント

影や波紋がひとつの要素として定義されているのはどのUIでも汎用的に使われる視覚効果で、それをコンポーネントとして使いたいからなのだろう。ドキュメンテーションからは、自分たちが定義するコンポーネントにエフェクトを与えたい時にこれらの要素を使えと書かれている。waterfallが要素化されていないのは、いち資格効果というよりも、スクローラブルなUIのいち表現という面が強いからだろう。

なので、エフェクトも必ず要素にせよというわけではない。そう言われたとしても、それはPolymerのお作法という側面が強いはず。たぶん…

とはいえ、Polymerであれなんであれ、再利用可能なコンポーネントはインポートしちゃえばいろいろできるので、コンポーネント時代が来たらコスメティックな表現だけの「ユーティリティ」要素が増える可能性だってある。そうなるとページ内の各要素にpaper-shadowを与えて〜と、非効率なマークアップが増えるかもしれない。

エレメンタル、クラシカル

古い人間なので、表現まわりはCSSをはじめとする、表現の定義を要素に適用するアプローチのほうがいいんじゃないかと思ってしまう。大体の場合において、そちらのほうが高効率な気がするからだ。ところがWeb Componentsでは、コンポーネント内で使われる視覚表現であったり挙動であったりを分離して管理・適用する仕組みが弱い気がする。Decoratorsがひとつの解なのだろうけど、いまのところ用意されてない。

Decoratorsのプライオリティが低い理由として、コンポーネントを読み込む際にはself-containedなもののほうがパフォーマンスや依存関係の面で都合が良いということがあるのかなと思う。

もうひとつは、ワークアラウンドでなんとかできるというのもあるんだろう。現在のPolymerもそうしている。たとえばさっきのpaper-shadowも、タグを子として書くだけという方法のみを提供してるわけではない。

The paper-shadow element is a helper to add shadows to elements. Paper shadows are composed of two shadows on top of each other. We mimic this effect by using two elements on top of each other, each with a different drop shadow. You can apply the shadow to an element by assigning it as the target. If you do not specify a target, the shadow is applied to the paper-shadow element's parent element or shadow host element if its parent is a shadow root. Alternatively, you can use the CSS classes included by this element directly.

併記してDOMで関連づけることもできれば、各ステートをclass属性値としてexposeしている。なので今のUIコンポーネントがやってるやり方も使える。HTMLもしくはスクリプトで適用することになるから、CSSでどうこうという話ではないんだけれど、直接書くよりはいくぶんか効率よいのではないか。

でもpaper-rippleにはドキュメンテーションを見る限りはそういうのがないんだよね。なんでだろ。

DeclarativeとImperative

Web Componentsを語るときにたまに出る単語として“Declarative”, “Imperative”というものがある。HTMLのタグはdeclarativeで、JavaScriptでDOM操作をするのはimperativeだ。SVGはdeclarativeでCanvasはimperative、AppCacheはdeclarativeでService Workersはimperativeだ。そんな対立というよりは対比がある。

PolymerはDeclarativeな性質をかなり推している。というよりもエレメンタル指向なのかもしれない。だからといってImperativeなものが否定されるわけではない。ただ、declarativeはそのわかりやすさから“magic”を生みだし、時たま不都合や混乱を生み出す。古いもので<select>、まあまあ新しいものでAppCacheとか。

わかりやすさの責任がとれないと、僕らが不幸になる。Magicではなく、どう振る舞うのかが説明されて、はじめて強力なものになる。Extensive Web Manifestoが目剤しているのはそこだ。Polymerが要素でなんでもしようとしてるけど、それはWeb Componentsが下にあって、モデルを提供しているからになる。こうすると、エレメンタルだけではなくクラシカルなアプローチも提供できる。影を要素として日の下に出すことも、今までのようにクラスに潜ませることもできる。


DeclarativeとImperative、エレメンタルとクラシカル、相互に補完することで、コンポーネントのデザインはより柔軟になるんだろう。ただ設計をするひとは、どこでimperative(スクリプトをごりごり書くか)それともdeclarative(タグ書きまくるか)にするのかということをそれないり意識しないといけないのかも。

コンポーネントならいいけれど、文書のマークアップとして要素を作るときはさらによく分からんくなるのかも。要素なのかそれともクラスなのか。

実際にコンポーネント書く前に、そんなことばっかり気になってしまっている。

Safari 8?の機能予想

WWDC直前ということでSafariの話題を。

といってもネタは3週間以上も前のもの。5月8日に「safari-538.34-branch」というWebKitのブランチが切られた。

昨年も書いたのだけど、これまでの動きから考えてこれが次のSafariのもとになるブランチのはず。というわけでコミットログとかから次のSafariを予想しようかと。

WebKitMac portで有効にされる機能は、FeatureDefines.xcconfig というファイルで管理されている。これらはビルドフラグなので、有効にされてないとナイトリーでも使えない。あと、ランタイムフラグもあるらしいんだけどこれは詳しく知らない。

Safari 8に入りそうなもの

538ブランチのFeatureDefines.xcconfigで有効にされてるものはこんな感じ。

FTL JITは昨年ブランチ後にパッチがガンガン入っていたし、先日Surfin' Safariでも大々的に取り上げられた

このうち、IndexedDBについてはバグのコメントを読むとwindow.IndexedDBにアクセスしてもnullを返すように仕組んであるとか書いてある。ソースのコメントによるとまだ作ってる最中という話だけど、状況はどうなのかしら。

その他入ったもの

とかとか。昨年から真面目に追いかけてないのもあって思い出せない……

JavaScriptCoreに追加されたもの

JSCにはENABLEマクロ的なものが見当たらない。ここらへんSpiderMonkeyみたくそんな後方互換性重視してないのかなという感じがする。

というわけでJavaScriptCoreのログをふにふにと追ってみた。

ES6がいろいろ入った。Spread oprsやDestructuring assgnmnt、for-ofはうれしい。

あとArrayの関数がJavaScriptで書き直されたりもしていた。その前にビルトイン関数をJavaScriptで書けるようになったので、今後他のものもJavaScriptで書かれるようになるんだろうか。

Safari 8に入りそうにないもの

538.34ブランチで無効にされてるものはこちら。

しゅーん。

Web TimingはNavigation Timing, Resource Timing, User Timingを指す(もともとGoogleから提案された時にWeb Timingという1つの仕様だったことに由来する)。Trunkで有効にされてうおーって思ったのだけど、ブランチが切られてからしばらくして消されてしまった。ただ作業はしているので、実装が追いついてないのかもしれない。

機能的にこれからというものもある。CSS Exclusionsはparsingしか入ってなかったらしい

他にもChromiumが離脱した絡みか、Shadow DOMやらiframe@seamlessとかいろいろなくなっていたりする。

よくわからないもの

条件付きで有効にされているものがある。そのひとつがtelephone number detectionで、iOSの電話番号に自動リンクつけるやつ。たぶんiOSのコードをupstreamした関係でWebKitの方にも入ったのだけど、今年のはじめの方にちょこちょこ作業されてて、Mac port用のマクロが用意されている。有効にされてるのは ENABLE_TELEPHONE_NUMBER_DETECTION_macosx_101000 となってるので、10.10なんだろう。あれが便利だと思ったことはないのだけれど、デスクトップにもあの機能がつくのかな。

ENABLE_FOO_macosx_10nnnn っていう特定のOS Xで有効にされてるのは他にもある。


こんな感じかなあ。さてどうなりますかね。

新しいiPhoneの解像度とCSSピクセル幅を考える

そろそろSafari 8?のベースになるWebKitのブランチが切られるかなと思って待っていたら月末になってしまった。ネタがないのでiPhoneの噂話でもしよう。

iPhoneの画面解像度は?

まず、確かな情報筋()によると、4.7インチと5.5インチのモデルが出ると。

4.7インチは750×1334らしい。現行iPhoneのディスプレイと同じ326ppiなものを4.7インチにするとこうなると。5.5インチだとフルHDな1080×1920らしい。こちらは新しいディスプレイで401ppiだって。

さて、5.5インチについてはまだわかるんだけど、4.7インチの謎解像度はないのではないかと思っている。というのはデバイス非依存ピクセルを想像すると2つのモデルで幅が異なる可能性が高いから。同じディスプレイが使えるという製造観点での利点や理由はあれど、アプリとかの観点から考えると煩わしすぎるわけですよ。

CSSピクセルで見るiPhoneの横幅

デバイス非依存ピクセル…面倒なのでCSSピクセルにしとこう(CSSに限った話じゃないけど)。あ、あとviewportはwidth=device-widthのときね。よし。

ピクセル密度や画面解像度の変更はあれど、iPhoneは登場時から横幅320csspxを維持してきた。iPhone 3Gまでは320×480。iPhone 4ではRetina displayとして640×960としたものの、レイアウト面でアプリやWebコンテンツへの影響がないように、1csspxを2dpxで描画するようにした。CSSピクセル的には、320×480と変わらない。

iPhone 5では640×1136になった。これまで3:2だったアスペクト比が変わって16:9(くらい)になった。HDなコンテンツをレターボックスなしで見られるようにするためだろうけど、幅320というCSSピクセルは変えずに高さを増やした。結果として320×568と収まりが悪い感じになった。

Androidはだいたい幅360

最近のAndroidスマートフォンの多くは、◯◯HDみたいな解像度が多い。HDを冠するだけあってHDコンテンツとの相性がよいんだろう。最初はたぶんqHDで540×960。次にHDで720×1280。フルHDのも出てきて1080×1920。2Kなんてのも発表されて1440×2560。もうよくわかんなくなるよね。

解像度はばらけているけど、ピクセル密度がそれぞれ違うので、CSSピクセル的にはこれらすべてが360×640になる。Androidでも一貫しているところはあったんだよ!!

さて、横幅が360csspxというの、iPhoneに比べて40csspxも余裕がある。つくりによるけど、iPhoneでは詰まったWebサイトもAndroidでは横にちょっと余裕がある。◯VGAな端末だと横幅320csspxだけど、iPhoneと同じなのでそんな影響はない。

Nexus 4はなぜだか768×1280→幅384csspxという謎仕様だったけれど忘れとこう。見た目もアスペクト比もよいと思うけど、たぶん悲しみしか生んでない。

iPhone 6は幅360になるのか

iPhone 6のうわさスペックを見ると、4.7インチモデルは幅750、5.5インチモデルは幅1080。ピクセル密度から考えると、CSSピクセルは4.7インチモデルでは幅375、5.5インチモデルでは幅360となる。

まず、320というこれまでの幅がでてこない。360以上になっている。これまで頑なに320を維持していたのに、それがついに変わるのか。

Webコンテンツに関しては、ゲームとかだとけっこう辛いのかな。ただ静的なWebサイトなら最近のAndroidを考えているならそんな問題ない気がする。考えてなくてもたぶんそんな問題は出ないんじゃあないか。

影響があるのはやっぱりアプリだろう。これまでみたくレターボックスが導入されると、edge-to-edgeなデザインが生きない。拡大モードを使うと、360÷320=1.125なので、うっすらぼける。Retina displayほどではないだろうけど、ちょっと影響が出てくる。

ただ、iOS7での大きなテイスト変更もあるので、アプリはいずれアップデートしないといけない。また、その新しいテイストだと画像とかよりテキストを推している感じがするので、拡大によるぼけはけっこう避けられるのかもしれない。なので幅360へのスイッチは、それなりにタイミングがいいのかもしれない。

ほんとに4.7インチ?

すっかり360前提で話をしてしまった。でもやっぱり、4.7インチモデルとやらから導かれる幅375csspxというのは考え難い。異なるモデルで幅が違うとかね。というわけで、もし幅を変えるのであれば2モデルとも幅360csspxにそろえるのではないか。

4.7インチという話はリークされたケースから来ているらしい。それくらいの大きさで◯HDなものだと解像度はHD、720×1280が適当かなあ。これでPPIを計算すると312くらい、これまでの326ではない。

逆にこれまでの326を使って幅720とした場合、大きさが4.5インチ程度になる。言われている4.7インチより0.2インチ小さい。5mmくらい、さすがに誤差とはいえないか……

ピクセル密度比が下がることはRetina display的にどうなのだろうか。では3xの新しいディスプレイになったとする。想定される解像度は1920×1080。これで4.7インチな端末は…HTC Oneがそうらしい。ふーむ。

まとめ(られてない)

噂されてる解像度がほんとなら、これまで維持してきた幅320csspxがついに終わる。狭くなるわけじゃないのでレイアウト崩れは想像しづらいけど、アプリ、とくにゲームとかは大変そう。

ただ4.7インチモデルの噂においては解像度の予測が疑わしい。幅360ベースになおすと326ppiのディスプレイは使えない。4.7インチモデルではピクセル密度比3、5.5インチモデルでは4になったりするかもしれない。

まあ、わかんないってことで。幅は360になるんじゃないかとは思うけど。

Sassでlinear-gradient()のmixinをつくる その6

このエントリはCSS Preprocessor Advent Calendar 2012の記事の続編です。

察せ。


Sass 3.3がついにリリースされました。リリースされないものだと思っていましたがよかったです。
アルファ版からインストールしていましたが、いまいち使っていませんでした。というわけで、これまで作ったMixinからSass 3.3の新機能を実際に使えないか試してみます。

Part 8: マップライクな処理はマップに置換え

linear-gradient()-webkit-linear-gradient()など接頭辞つきのバージョンとでは方向を示すキーワードが違います。対応関係があるためマップやハッシュで表現したいところですが、これまでのSassにはそういったものがなく、Sass 3.2の次に実装するとされていました。
そしてSass 3.3でついにマップが実装されました。わーい。

Sassのマップは(key1: value1, key2: value2)のように、ラベルつきのカンマ区切りリストみたいなかたちになってます。マップから値を取り出したりマップに値を追加したりする際には、新たに定義されたマップの関数を使います。

というわけで、キーワードの変換部分に使っていたマップライクな処理をマップに置換えてみます。
まずはキーワード版の処理を。こうなってました。

@mixin lg-keyword($keyword, $colorstops...) {
    $prefixes: '-webkit-';
    
    // 標準のキーワード
    $standard_keywords:
        to bottom, to left, to top, to right,
        to top left, to top right, to bottom right, to bottom left,
        to left top, to right top, to right bottom, to left bottom;
        
    // 接頭辞版のキーワード
    $legacy_keywords:
        top, right, bottom, left,
        bottom right, bottom left, top left, top right,
        right bottom, left bottom, left top, right top;
    
    // キーワードのインデックスを取得
    $idx: index( $standard_keywords, $keyword );
    
    // キーワードが不正な場合は何も出さない
    @if $idx {
        // マッチする接頭辞版のキーワードを取得
        $legacy_keyword: nth( $legacy_keywords, $idx );
        
        @each $prefix in $prefixes {
            background-image: #{$prefix}linear-gradient(
                $legacy_keyword, $colorstops);
        }
        background-image: linear-gradient($keyword, $colorstops);
    }
}

標準のキーワード、接頭辞版のキーワードを2つのリストにして、引数に与えられたキーワード(標準版)のインデックスを取得。出力時にそのインデックスを使い、接頭辞版のキーワードを引っ張ってきています。
これがマップを使うとこうなります。

@mixin lg-keyword($keyword, $colorstops...) {
    $prefixes: '-webkit-';

    $keywords_map: (
        to bottom:       top,
        to left:         right,
        to top:          bottom,
        to right:        left,
        to top left:     bottom right,
        to top right:    bottom left,
        to bottom right: top left,
        to bottom left:  top right,
        to left top:     right bottom,
        to right top:    left bottom,
        to right bottom: left top,
        to left bottom:  right top
        );

    // キーワードが不正な場合は何も出さない
    @if map-has-key($keywords_map, $keyword) {        
        @each $prefix in $prefixes {
            background-image: #{$prefix}linear-gradient(map-get($keywords_map, $keyword), $colorstops);
        }
        background-image: linear-gradient($keyword, $colorstops);
    }
}

(標準版: 接頭辞版, ...)というマップに作り直しました。引数が標準版のキーワードになっているかを調べるにはmap-has-key()関数を使えばOK。マップから値を取り出すときはmap-get()関数を使います。

ソースを整形してるため行数的にそんな変わってませんが、インデックスを取得するとかをしなくなったので、だいぶわかりやすくなったのではないかと思っています。
ただマップがマップとして読めない感はありますね…キーは内部的にリストとして扱われているので、括弧でくくってやるとちょっとはわかりやすくなるかな…うーん。

まとめ

とりあえずマップライクな処理を置換えても問題ないことがわかりました。他にもマップが使えるところがありますが、そちらはこれほどストレートフォワードではないので、また次回に。
えっ、次回…?

補足:-prefixed-linear-gradient()いるかい?

今回はlinear-gradient()から-webkit-linear-gradient()などの接頭辞版の構文互換の記述を吐き出すmixinを書きましたが、標準の構文がサポートされてからけっこう経ちます。

一番サポートが遅かったのはWebKitなのですが、こちらはSafari 7.0からサポートされています。Safari 6.0以前のサポートによって入れるか入れないかを決めてもよいのではないかと。あるいは-webkit-gradient()を吐き出すなら、特に入れなくてもいいのではないかと思います。

WOFF 2.0 Evaluation ReportとBrotli

いつだったかにWOFF2のことを書いた。

タイトルかたいな!

その後どうなったのかなと思いつつもめんどくて調べてなかったんだけど、1月末にWOFF 2.0 Evaluation Reportというのが出た。WOFF2で検討されている圧縮の仕組みなどについて調べたレポートとのこと。

以下、2013年夏くらいからの話題なので新しくないよ。

LZMAはやめたらしい

GoogleによってWOFF 2.0の元になる仕組みが提案された当初、圧縮アルゴリズムLZMAを使うことになっていた。ただ、高圧縮率の犠牲としてえらい圧縮時間とメモリ使用量が必要ということがわかったので、その採用はなくなったとのこと。ある計測結果によると圧縮にかかる時間がgzipの5倍以上、展開時のメモリ使用量が2倍くらいだったそう。

Webフォントはサブセットを配布しないのなら一度圧縮するだけで済むけれど、展開時のメモリ消費量は気になる。とくに世の中がモバイルモバイルしている中でこれはだめだったんだろう。

ほかにも、LZMAの仕様がない(リファレンスコードをリバースエンジニアリングするしかない)、IP関連でロイヤリティフリーにできる保証がないということも問題になったよう。仕様があるって大事なんだね……

Brotli登場

代わりとなったのが、Google内部でDEFLATEをベースにしたBrotliというもの。昨年Googleから出たZopfliやWebP Loslessを作った人たちによるものらしい。

Evaluation ReportによるとLZMAにはやや劣るけれど、フットプリントは半分近くになるらしい。それでもWOFF1と比べて大きいけれどトレードオフなのかと。

実装もChromeにすでにフラグ付きで入ってるらしい。知らなんだ。

今後はBrotliの標準化(IETF?)と平行してWOFF2を標準化するらしい。いつくらいになるのでしょうねえ。

余談:Webでの利用は?

Mozillaニュースグループでも取り上げられていて、そこではフォントだけではなくて、HTTPとかWeb全般に使えるのではというコメントつきで紹介されている。

Introducing Brotli - an alternative to LZMA - Google Groups

とくに議論が発展してないけれど。新しいものを導入するとなるとだいたい切ない話になるので誰も入ってこないのだろうか。

システムの文字サイズを取得できないものか

80歳の方にiPad Airを使わせてみた方のエントリを読んだ。

母とNexus 7

ちょうど年末年始の帰省時に母(60くらいだったかな?)にNexus 7(2012年モデル)を渡したのだけど、このエントリにある「ボタンはしっかりと押さないとね!」というのがあって困った。画面上じゃなくて電源ボタンも無意識に長押しになるので電源オフにするダイアログが出る。実家から戻るときにはだいぶ良くなってたけど、タップはぎこちなかった。慣れてくれるといいな。

あと面白かったのが、アプリアイコンとブックマークを混同していたというか同一視してたこと。「ニュースを見たい」とアプリ一覧を指して言って「ほえ?」となった。アプリ一覧はできないけど、ちょうどChromeがメニューからホームスクリーンに登録できるようになったので、それを教えてあげた。ホームスクリーンがアイコンだらけにならないといいけれど。

しかし、Windowsのデスクトップを見たところWebサイトへのショートカットがばかすかあるわけでもなく、なんでNexus 7でそんな認識になったのかわからない。Androidはまたアプリ一覧とホームスクリーンがあるのでややこしいよね。iPadだったらまた違う反応をしてたのかな。

 他にも面白かった…というかめんどかったのが、半透明のグレーのやつをオーバーレイさせる系のチュートリアルを読みもせずすっとばすこと。「えっえっ」って言って一番目立つ色のボタンを押しちゃってチュートリアル終了という。わかんないと言われてもこっちだって見てないし…アプリ詳細からデータ削除してもう一回やりなおしたりとか。あれ系を採用する場合にはぜひともチュートリアルをやり直すオプションがほしい。

システムの文字サイズが反映されないアプリがかなりある

母の観察記はほどほどにして本題を。件のエントリでも触れられていた点が特に気になった。

文字の表示サイズを大きくできる

「太字」「文字を2まわりくらい大きく」な設定にしてきました。だってiPadの文字を虫眼鏡を通して読んでいたんですもん…。
私が普段コーディングをしながら「ギャアア」と思っている文字サイズ変更機能も、こういう人向けに必要なのですね。知識として知ってはいましたが、「ああ、こういうことなんだー」と思いました(直接的には少々違いますが、概念として)。

こちらもAndroidの設定から文字サイズを指定できたので、てきとーに大きくしておいた。Chromeにも設定あるんだけどそっちはどうだったかな…でも-webkit-text-size-adjust設定されてたら意味ない気がするけど。

システムの設定はできても、拡大できるのはシステムのサイズを継承してくれるUI周りで、コンテンツ周り?は拡大してくれないアプリが多かった。ピンチズームも効かなくてうーんと思った。

ちょっと見てみて、WebView使ってそうなアプリにそういうのが多い感じがした。システムのサイズを取ってくるAPIとかないのだろうか。

IndieUI User Context

Web標準側にもそういうのは今のところないはずで、構想がIndieUI WGでつくってるIndieUI 1.0: User Contextにあるくらいか。“feature key”というメディアクエリーの媒体特性みたいなの(たまに媒体特性としても使えるらしくよくわからない)にuser-font-sizeというのがあるのでそれを使えばよいらしい。

// example of settings keys defined within the IndieUI User Context specification.
window.userSetting('user-font-size'); // returns computed value in CSS pixels, e.g. '16px'

とはいってもまだ構想段階な感じ。TPACのときにあったCSS WGとのジョイントミーティングWebApps WGとのジョイントミーティングでは、ハイコントラストモードの検出とか一部の機能については支持があったけど、セキュリティ・プラバシー的な懸念とかもやっぱりあって、まだまだという印象を受けた。


使えたら使えたで「システムの文字サイズ継承とか…」みたく思ってしまうのだろうけど、読めないよりは崩れてても読めたほうがいいよねえ。

Web技術について書くときの媒体の違いを考える

このエントリはEditors' & Writers' Advent Calendar 2013の12日目のやつです。

これまでいろんな媒体で、HTMLやらCSSやらに関することを書いて、そして書かせていただいてるので、媒体ごとの違いなどを考えてみました。

ブログ

このweblogや過去に書いていたブログ、勤めていたときにお仕事で書いていたWeb標準Blogなど、ぼくが書く技術系のコンテンツのプライマリな媒体はブログです。

ブログのよいところは、好きなときに好きなことを好きなだけ書けるという、書き手中心のところでしょうか。お仕事で書いていたブログについては、会社のコンテンツということもあり多少なりとも内容についての確認などはありましたが、それでも他の媒体と比べて自由度は高いのかなと。

いっぽうで悪いところは自由すぎるところでしょうか。タイミングも分量も表現も自由ですので、自重しないと話しの軸もターゲットも容易に見失います。このブログがよい例です。

オンラインメディア

いまはHTML5 Experts.jpでちょくちょく書いて(と言いたいのだけどまだ1本…すみませんすみません)、お仕事では以前Gihyo.jpさんで原稿を書かせていただいたことがあります。これら2つからオンラインメディア全体について語るのはアレなのですが、とりあえず。

よい点としては、「メディア」として幅広い読者層がいるだろうということが強みでしょうか。自分のブログよりも広い相手にリーチできるのかなと。

わるい点としては、ターゲットを想定しづらいことでしょうか。メディアによって読者層は違うのでしょうが、多くの人が集まるぶん、狭すぎるものは心理的に書きづらく思います。また、広い読者層がいるわけで、自分のキャラが通じないことは意識しないといけないかなと。書き手が基本一人の個人ブログだといいのでしょうけど、多くの執筆者が居て、多くの読者がいるメディアでは、それが伝わらず、たとえば毒舌キャラのまま書いたら無駄な炎上を引き起こしたりとか、そういうのが考えられます。何かを伝えたいのに伝わらない、というか変なコミュニケーションミスまで起こってしまうというのは悲劇です。

また、メディアによっては掲載日というものの関係から、すぐに発信したいニュース的なものを投稿することが難しくなるでしょう。また、こちらもですが、編集権限がないため、文章は提出する前にかっちりさせなければなりません。こちらは編集者のお仕事でもあるのですが、みなさんが技術にえらく詳しいわけでもないので。ぼくはずぼらなので、このブログなんかは「あとで編集しよっと」と思いながらだらだら書いて公開後にだだっと編集してますが、そういうやり方ができません。

雑誌

雑誌の特集記事や連載をお仕事でさせていただいたことがあります。なかでもWeb Designingさんにはとてもお世話になりました。

雑誌で書くことのよい点は、まず肩書的になんとなく箔がついてくれること。いやらしいですけど、自己紹介とかで書きやすいのです。
って、これは書いたことか。

書くにあたってよいなと思うのは、物理的な媒体、つまり面積に縛られるので、文字数や図版などを収める工夫をしないといけないことです。文章は推敲が必要だし、図版などは見せ方を気にしないといけない。Webでできないわけではないのですが、強制されるので、ずぼらなぼくみたいな人にはとても効果があります。面倒ではありますが。

わるい点は、これは扱うテーマがWebという進みの激しいものというせいもあるのでしょうが、お店に出るまでのディレイがかなりあることです。ニュース的なものは他の媒体に食われてしまうので、書く意味はそこまでなくなります(ニュースに疎い層がターゲットであればいいのかもですが)。また、あまりにパッと湧いて出た話をすぐに拾ってしまうと、その後の話を記事では説明できないので、あまり健康的ではありません。Web Designingでは、Web標準がらみのトピックをとりあげる連載をさせていただいたのですが、何度かこれで失敗したなと思うことがありました。


ちょっと時間がないので草稿でだしとく。あとでもうちょいいじる。