たまに18歳未満の人や心臓の弱い人にはお勧めできない情報が含まれることもあるかもしれない、甘くなくて酸っぱくてしょっぱいチラシの裏。RSSによる簡単な更新情報を利用したりすると、ハッピーになるかも知れませんしそうでないかも知れません。
の動向はもえじら組ブログで。
宣伝。日経LinuxにてLinuxの基礎?を紹介する漫画「シス管系女子」を連載させていただいています。 以下の特設サイトにて、単行本まんがでわかるLinux シス管系女子の試し読みが可能!
ツリー型タブのWebExtensions移行の後半作業と並行して進めてたマルチプルタブハンドラのWE移行ですが、こちらも一区切りとしてバージョン2.0をリリースしました。こちらはTSTほどには語る内容が無いので手短に。
マルチプルタブハンドラ(以下、MTH)は元々、「そこにあるFirefoxのタブを雑にドラッグして選択したらメニューが出てきて『で、この選択したタブをどうしたい?』と次のアクションを訊ねてくる」という、操作対象を起点とした操作、本来の意味での「オブジェクト指向」らしい操作というコンセプトに基づくアドオンでした。そのコンセプトを具現化するために、レガシー版ではタブの上でのクリックやドラッグどいった操作をハンドルし、時にFirefox本体の挙動をキャンセルして、「タブをドラッグして選択」という挙動を実現していました。
ところが、WebExtensionsではFirefoxのタブの上での生のイベントをハンドルすることが許されていません。そういうAPIが欲しいという要望は挙がっていましたが、WebExtensions APIのコンセプトに反するということでWONTFIXになっています。よって今後もそういう事ができるようにはならないでしょう。
ただ、WE版TSTは専用のサイドバーを提供していて、その中で発生するイベントを扱う事に関してであれば自分の裁量で好きなようにAPIを提供できます。 なので、WE版MTHは当初は「TSTに完全に依存したアドオン」として開発を始め、TSTにAPIを実装してはMTHでそれを使ってみるという形で両者の開発を並行して進めていたのでした(TSTのAPI整備とその動作検証のための体のいい実験台になってもらったとも言えます)。 その過程で、ツールバーボタンから開いたパネル内であればドラッグ操作でのタブの選択もできなくはないと思い立ったため、TST完全依存のアドオンではなく一応単体でもそれなりに機能するアドオンとしてリリースする方針に切り替えて不足部分を整備し、この度ようやくリリースに至った次第です。
そういう経緯なので、本来意図していたMTHのユーザー体験は、WE版においてはTSTとの併用時においてのみ実現されています。単体のWE版MTHはあくまで仮の姿で、TSTと併用した時にのみ真価が発揮されるとは、なんとも中二病くさい仕様ですね。
ところで、Firefoxにはずいぶん前から(具体的には8年前から)タブを複数選択する機能の実装提案がなされています。 この機能がいつまで経っても実装される様子がないので、渋々MTHを今までメンテナンスしてきた、という部分も実を言うとあるのですが、なんとここに来てそれなりの優先度で解決(実装)に向けて動き始めてきたようです。 もっと早くやってくれていれば、MTHはWE版を開発せずそのまま開発終了にできたかもしれなかったのに……
ともあれ、将来のどこかの時点でMTHがお役御免となるのなら、それに越したことはありません。 その日が来るまでの間は、できる限りメンテナンスを続けていこうと思っています。
以上、MTHのWE版リリースの裏事情でした。
Here is the English version of this article. このエントリはQiitaとのクロスポストです。
2017年の8月下旬に思い立って、ツリー型タブのWebExtensions版を作り始め、去る9月26日にバージョン2.0としてリリースしました。
重い腰を上げて取り組む気になれたのは、必須と目していたAPIが一通り実装されてきて、Firefox 57でようやく技術的に作れる目処が立ってきたからでした。 関係者の皆さんの尽力に改めて感謝の意を表明します。
やっている事自体はそう難しい話ではなく、技術的に目新しいトピックは無いのですが、主に歴史的資料としてレガシーなアドオンの移行の一事例の記録を残しておこうと思います。
I started to develop WebExtensions-based version of the Tree Style Tab at late August 2017, and released as the version 2.0 at 26th November.
The largest reason why I did it is: many numbers of new WebExteisons APIs I required are landed to Firefox 57. Thank you developers for their great effort.
There is no technical novelty topics, but I wrote this as a historical document: a migration story of a very legacy addon.
When I start Firefox, tree of tabs and favicons are always lost. Even if I reorganize tree of tabs again, they are flattened after every restart.
Firefoxを起動すると、必ずタブのツリーとタブのアイコンが失われます。ツリーを作り直しても、再起動する度にツリーが失われてすべてのタブが同階層に表示されてしまいます。
Please press Ctrl(Command)-Shift-J to open the "Browser Console" - one of developer tools of Firefox. Is any error message like this reported?: NS_ERROR_ILLEGAL_VALUE: Component returned failure code: 0x80070057 (NS_ERROR_ILLEGAL_VALUE)
[nsISerializationHelper.deserializeObject] Utils.jsm:94
Screenshot:
Then, the problem may be caused by invalid information stored in your session data. Try following steps to cleanup your session data:
var TabStateCache = Components.utils.import('resource:///modules/sessionstore/SessionStore.jsm',{}).TabStateCache;
Array.forEach(
gBrowser.browsers,
(browser)=>
TabStateCache.update(browser, {
iconLoadingPrincipal : null
})
);
"OK"
Ctrl(Command)-Shit-Jを押して、Firefoxの開発ツールの1つである「ブラウザコンソール」を開いて下さい。以下のようなエラーメッセージが出力されていませんか?:NS_ERROR_ILLEGAL_VALUE: Component returned failure code: 0x80070057 (NS_ERROR_ILLEGAL_VALUE)
[nsISerializationHelper.deserializeObject] Utils.jsm:94
スクリーンショット:
もしこのエラーが出ているなら、問題はセッション情報の中に混入してしまった不正なデータが原因で引き起こされている可能性があります。以下の手順でセッション情報をクリーンアップしてみて下さい。
var TabStateCache = Components.utils.import('resource:///modules/sessionstore/SessionStore.jsm',{}).TabStateCache;
Array.forEach(
gBrowser.browsers,
(browser)=>
TabStateCache.update(browser, {
iconLoadingPrincipal : null
})
);
"OK"
Firefox用アドオンは現在、Mozillaによる署名が必須となり、未署名のアドオン=Mozillaによる内容のチェックが行われていないアドオンはインストールできない、インストールしても有効化できなくなっています。
Firefox 47までのバージョンおよび法人向けの長期サポート版(ESR版)ではxpinstall.signatures.required
という隠し設定を使って未署名のアドオンを強制インストールできるようになっていましたが、この設定はFirefox 48で削除されました。
そのため、リリース前に自作アドオンを自分で使って試したい(ドッグフーディングしたい)人は、正式リリースされたFirefoxでアドオンを試す方法がなくなってしまっています。
この問題に対する救済措置として、上記隠し設定が利用可能な「ノーブランド版Firefox」がアドオン作者向けとして公開されています。 このエントリでは、ノーブランド版Firefoxの使い方と注意点をまとめておきます。
ノーブランド版と通常リリース版の違いは以下の点です。
xpinstall.signatures.required
をfalse
に設定すると、アドオンの署名チェックを無効化できる。Mozilla Wikiの、アドオンの署名に関する情報のページ内の「Unbranded Builds」という項目にインストーラのダウンロード用リンクがあります。 2016年8月3日現在ではリリース版Firefox 48.0相当の物へのリンクがありませんが、親ディレクトリから辿っていくとインストーラを入手できます。
このインストーラを実行すると、通常のFirefoxとは異なり、構成ファイル一式は「C:\Program Files (x86)\Mozilla Developer Preview」のようなフォルダにインストールされるようになっています。 インストールしたはずの物が見つからない!という時はインストール先を確認してみて下さい。 カスタムインストールすれば今までと同じ位置(「C:\Program Files (x86)\Mozilla Firefox」など)にインストールする事もできます。
xpinstall.signatures.required
を再設定してアドオンを有効化する。
今まで通常版のFirefoxでxpinstall.signatures.required
をfalse
にして使っていた人が、Firefox 48に自動アップデートされてアドオンが無効化されたという場合、「このアドオンは署名チェックに引っかかって無効化された」という情報がプロファイル内に保存されます。そのため、その後でノーブランド版を入れて起動しても、アドオンは無効化されたままとなります。
xpinstall.signatures.required
を1回true
に設定して、もう1回false
に設定し直すと、この情報がリセットされてアドオンが再び有効になります。自分はこれに気付いていなくてハマりました。browser.tabs.remote.autostart
=true
(これは設定ダイアログにあるチェックボックスに対応する項目)browser.tabs.remote.force-enable
=true
(アクセシビリティ機能によるe10s無効化を抑止)extensions.e10sBlocksEnabling
=false
(アドオンがあることによるe10s無効化を抑止extensions.e10sBlockedByAddons
=false
(同上)現地時刻で2016年6月13日から17日にかけて行われたMozilla All Hands in London、通称MozLondonに参加してきました。
最近はこの種のイベントに参加する機会が減ってしまい、「えっ、Mozilla関係で何かやってる人だったの?」みたいになってそうな気がするので、ちょっと記録を残しておこうと思います。
Mozillaの活動に関わっている人はMozillaの雇用スタッフもそうでない人も世界中に散らばっていてコミュニケーションコストが高いので、半年ごとにAll Handsと称して社員と外部の開発者を一箇所に集めて色々話し合っています。 ただ、社員は全社員が招集されるのに対して、自分のような外部の人は活動のアクティブさの度合いなどに応じてボランティア枠で招待される形です。 自分は連絡を頂いた時点ではBugzilla上でそんなにアクティブではなかったのですが、今回はアドオン作者へのヒアリングということでアドオンチームの方から推薦を頂いたようです。 「ボランティア」とはいっても招待なので、交通費・食費・宿泊費は全部Mozilla持ちでした。
Recently I wrote a blog entry for developers of addons for Firefox, who are planning to migrate his/her XUL-based addon to WebExtensions. This is the full version which includes some side topics not related to WebExtensions. I hope this helps you to migrate your ancient addon to WebExtensions.
ツリー型タブの最近の改善でやったことをまた地味に解説するよ。誰得な記事。
ツリー型タブには、「ブックマークからタブを複数開いた時に1つのツリーになってた方がいいけど、でもツリーにするには親になるタブが必要で、だからといって同列のブックマークの中で1つだけが親になるのってなんか違和感あるよね」という場面のための「グループ化専用のダミーのタブ」を開く機能がある。というか、about:treestyletab-group
というURIを読み込んだタブはそういう用途のタブとして扱うようになる。そのときタブの内容が空っぽだと味気ないので、そのタブ配下のタブのツリーをタブの内容として表示するようになっている。
それとはまた別の話で、ツリーになっているタブの上でしばらく待つとそのタブ1つだけじゃなくて配下タブの名前も一緒にツリー表示して、さらにもう少し待つとそれらがリンクに切り替わってクリックしたらそのタブに切り替えられる、という機能もある。
見た目で分かるかもだけど、これらのツリーを生成する部分は共通のpseudoTreeBuilder(疑似ツリー)というモジュールになってる。
この疑似ツリーは、ちょっと前までのバージョンでは、タブの数が多くなるとそのままツリーが下に伸びていって、ウィンドウやツールチップの高さに収まらなくなった分はスクロールして見るという仕様になってた。 元々、おまけの機能だからそれほど作り込む必要性も感じてなかったんだけど、未処理のissueがたくさん溜まってたのを断捨離してたらその中に「このツリーをマルチカラム表示して欲しい」という要望があった事に気がついた。
このエントリを書くにあたって改めて調べ直してたら、別のもっと古いissueでは否定的なことを自分で言ってたみたいなんだけど、実際自分で使ってて「長いタイトルが折り返されるという事もなく巨大なツールチップが画面を覆い尽くして、そのくせちびちびスクロールしないと全項目は確認できない」という状況に意外とイライラしていたため、この機会に「じゃあやってみっか」と手を着けてみた。
で、最終的にはどうにかそれらしくマルチカラム表示できるようなった。
基本的にはCSSのマルチカラム機能を使ってるんだけど、ツールチップの方で僕の意図したとおりの結果を得るためにはちょっと工夫が必要だった。
「ツールチップの方で」と限定したのは、後で分かったんだけど、タブの中に表示する方はそこまで苦労しなくても勝手にいい感じにGeckoがレンダリングしてくれるから。 なので先にそっちの方から書いていきます。
先に要件を整理しよう。
まずコンテナとして、コンテンツ領域いっぱいに広がるボックスを置いておく。
コンテナには、内容が溢れたらスクロールできるようにoverflow:auto
も指定しておく。
#tree {
overflow: auto;
box-flex: 1;
-moz-box-flex: 1;
}
で、この中に置くツリーをマルチカラムにしたいわけなんだけど。
CSSのマルチカラム表示を有効にするだけなら、マルチカラムにしたい内容を含む上位の要素に列の数か幅を指定してやればいい。
2列なら、こう。この場合、列の幅はコンテナの半分になる(自動的に決定される)。
#tree > .treestyletab-pseudo-tree-root {
-moz-column-count: 2;
/* -moz-columns: 2 auto; と同等 */
}
列幅固定なら、こう。この場合、コンテナの中に1列しか収まらない時はマルチカラムにならないという、いわゆるレスポンシブデザイン的な挙動になる。
#tree > .treestyletab-pseudo-tree-root {
-moz-column-width: 20em;
/* -moz-columns: auto 20em; と同等 */
}
列数固定だとウィンドウの幅が広いときに余白ばかり広がってしまってあまり嬉しくないので、ツリー型タブではとりあえず主観で20em
と指定してみた。
自分の使ってる環境では、これでだいたい2~3列になる。
マルチカラム表示したいツリーを構成しているXUL要素の中で、内容が複数列に泣き別れてもいい物(=「1つのタブ」に対応する「アイコンとラベル文字列のペア」以外のすべてのボックス)は明示的にdisplay:block
にしないといけない。
display:-moz-box
のままだと、要素の作るボックスは途中でぶった切られる事が無いので、マルチカラム表示にはならない。
/* required to apply CSS multi columns */
#tree > .treestyletab-pseudo-tree-root,
#tree > .treestyletab-pseudo-tree-root vbox {
display: block;
}
当初はこれに気付いてなくて、わざわざXHTMLとXULを混ぜて実装してた。
でも、後になってからdisplay
の値を変えればXUL要素でも問題ない事が分かったので、今は全部XULに戻してある。
しかし、これだけだと項目の数が多い時に「縦に長いツリーがマルチカラムで表示される」「画面に収まらなかった部分は下にスクロールしないと見えない」ということになる。
こういうのは一覧性が悪くて死ねる。 だって、左の列を上から順に下まで見た後、次の項目を見るにはまた一番上までスクロールし直さなきゃいけないんですよ? あり得ないでしょ……
つまり、各列がコンテンツ領域の高さより高くなられると困る。 項目の数が多いときは、「縦に長ーいリストを2列で表示する」んじゃなくて、「コンテンツ領域の高さに収まる短いリストを3列、4列と列を増やして表示させる」方がいい。 ということ。
じゃあってんでさっきの要素に最大の高さを100%
と指定してみても、これは効果がなかった。相変わらず、親のボックスの大きさを超えてスクロール可能なまま。
#tree > .treestyletab-pseudo-tree-root {
-moz-columns: auto 20em;
height: 100%;
}
なので、resize
イベントでコンテナの高さを調べて、その都度ピクセル値で適切な高さを指定するようにしてみたら、ようやく縦のスクロールバーが消えて横方向にスクロールできるようになった。
...
this.window.addEventListener('resize', this, false);
...
handleEvent : function GT_handleEvent(aEvent)
{
switch (aEvent.type)
{
...
case 'resize':
return this.onResize();
...
}
},
...
onResize : function GT_onResize()
{
...
var container = this.document.getElementById('tree');
var tree = container.firstChild;
PseudoTreeBuilder.columnizeTree(tree); // ここでcontainerの高さをtreeのheightにピクセル値で指定し直す。
},
CSSのマルチカラムでは「列の数」の指定は絶対ではなくて、コンテナの幅と高さから溢れた分の内容は自動的に列の数を増やして表示するようになってる。
コンテナがoverflow:auto
になっていれば、溢れた分は横スクロールすれば見える。
全体の高さを指定していても、項目の数が「全部1列で表示するには多いが、2列を埋めるには足りない」程度の時には、領域の下の方に妙に余白が出てしまう。
これは-moz-column-fill:balance
という初期値のせい。この指定の時には、各列の内容の高さがなるべく揃うようにレイアウトされるため、結果として下の方に余白が産まれることになる。
まぁそれはそんなに悪くはないんだけど、今までコンテンツ領域の高さいっぱいまで並んでた物が急にその半分とかくらいの高さになるのは気持ち悪い。 違和感が無いのは、やはり、領域の高さに収まらなくなった分からちょっとずつ次のカラムに流し込まれていくという感じだろう。
そのための指定が-moz-column-fill:auto
で、これを指定しておくと、1列目は下まで項目が埋まって、入りきらなかった分だけが2列目に溢れるようになる。
実は、この-moz-column-fill:auto
を使うのにも、ボックス全体の高さを明示的に制限しておく必要がある。
というのも、-moz-column-fill:auto
の時は「高さが指定の高さに収まらなかったときに、その分を次のカラムに流す」という事になるので、高さが未指定だと「内容が溢れることもないからいつまで経ってもマルチカラムにはならず、縦にどんどんリストが伸びていく」という結果になってしまう。
……というわけなので、やっぱり全体の高さはスクリプトで動的にピクセル値で指定してやらないといけないのでした。
こちらも要件を整理する。
ここで曲者なのが3つ目の要件。 コンテンツ領域の中であれば「与えられた領域の中を最大限使って、残りは余白扱いにすればいい」ということになるんだけど、ツールチップだとそうもいかない。 というか、必要最小限のサイズで出てくれないと困る。 「内容を表示するのに必要な最小の大きさをどうやって決めるのか?」 これがツールチップの場合の難しい所だ。
先に結論を言ってしまうと、「とりあえず許されてる最大の大きさで試しにレンダリングしてみて、その後、実際に必要な大きさで改めて表示し直す」というのが答えになる。
とはいうものの、ツールチップを1回表示した後そこから小さく縮めるというのは見た目が宜しくない(一瞬だけとはいえ目に見える状態で大きなツールチップが出るというのはイラつきますよね)。
じゃあどうすれば?という事になるんだけど、逆転の発想というかなんというか、ツリー型タブでは「そもそも最初からベストのサイズで表示する事は諦める」という解決策をとっている。 どういう事かというと、いきなり違うサイズのツールチップを出すとギャップで見当識を失うので、まずは元の普通のツールチップと同じ大きさ・位置で1回表示して、そこからアニメーションでツールチップを必要な大きさまで拡大する、という事をしてる。
ツリー型タブの高機能なツールチップはだいたい元のツールチップよりは大きくなるので、この「1回小さめのサイズで表示した」状態で必要なサイズを確定させて、後からゆっくり拡大すればいい。
元より小さなツールチップで何故「最大の大きさで試しにレンダリングしてみる」ができるのかというと、XULのarrowscrollbox要素を使ってるから。 これは元々は、ツールチップが画面いっぱいに広がっていてもまだ内容が収まりきらない時のための対策として使っていた。 arrowscrollboxは中にどんなに大きな物を置いてもそれ自体やその親(ツールチップ)の大きさが広がらないので、安心して「めいっぱい大きく表示して、最小限必要なサイズをその結果から割り出す」ということができる。
「幅も高さもいい感じにする」というのは難しいので、ツリー型タブの場合はまず「画面の全体を覆い尽くさない程度」ということで画面の高さの70%(例えば画面が縦1024ピクセルなら、その7割の717ピクセル)を最大の高さとして、その中でマルチカラム表示の指定を反映させている。
arrowscrollbox > .treestyletab-pseudo-tree-root {
-moz-columns: auto 20em;
-moz-column-fill: auto;
height: 717px; /* ←実際にはその都度計算する */
max-height: 717px; /* ←実際にはその都度計算する */
}
こうすると、高さについては指定の高さまでに収まって、幅は必要な分だけ自動的に列が増えていくという形で、ツリー全体を収めるのに必要な領域を確定する事ができる。
高さは既に分かっているので、残るは幅なんだけど、これはツリー自体のboxObject.width
やclientWidth
からは分からない。
というのも、この時点でのマルチカラム表示されたツリーは「列の幅は指定されているが列の数は指定されていないので、要素自身の幅を超えて列が表示されている(可能性がある)」という状態で、要素自体の幅を調べても意味がないのです。
overflow:auto
になってる要素の幅を計測しても中身の幅は分からない、というのと同じね。
こういう時の「本来の内容の幅」は、RangeのgetBoundingClientRect()
で調べられる。
これは、DOMのRangeが含んでいる範囲の全要素が収まる矩形の位置や大きさを計測してくれるという便利なAPI。
これを使ってツリーの要素の「内容を」選択してそのサイズを測れば、ツリー全体を収めるのに本当に必要な最小のサイズが分かる。
var range = tree.ownerDocument.createRange();
range.selectNodeContents(tree);
var rect = range.getBoundingClientRect();
range.detach();
あとは、ツールチップ全体を広げるだけ。 「ツリー全体を収めるのに必要な幅」と「画面の幅さの80%(例えば画面が横1280ピクセルなら、その8割の1024ピクセル)」のどちらか小さい方をツールチップの新しい幅にしてやる。 ツリーはツールチップの中のarrowscrollbox要素の中に置かれているので、ツールチップがツリーよりも小さければ、はみ出た部分はスクロールして見る事ができる。
以上、マルチカラムなポップアップをいい感じに表示するためのノウハウの話でした。
実は、ここに書いた内容はmasterのHEADでの話で、解説を書くにあたって調べ直した結果の洗練された内容になってる。 今リリースしてるバージョンでは、そこまで洗練されてない状態の(でもだいたい同じような結果を得られている)コードになってるので、どこが無駄だったのかを洗い出して「こいつ技術力低いなあ!」と笑いものにしてくれていいです。
それにしても、昔なつかしNetscape Communicator 4では、フォルダの中にブックマークが大量にあるときはこんな風に段組表示してくれて一覧性が高くてものすごく便利だったんだけど、Geckoエンジンベースで作り直されたNetscape 6以降や、その流れの先にあるFirefoxには、その機能はついぞ引き継がれなかった。 業を煮やして複数のポップアップを並べることで擬似的に再現できないか?という実験をしてみたこともあったんだけど、不安定でダメだった。
今だったら、このやり方で行けるんじゃないか?という気がする。 というか、SUMOの質問に寄せられてる回答でStylish用のスタイルシートが公開されてて、2つの例のうち1つはCSSマルチカラムでやるようになってたので、間違いなくできる。
ただ、例に挙がってるStylish用のスタイルシートはカラム数が固定されていて、1列でいい時にまで常に2列3列になってしまうという問題がある。 ネスケ4の頃のそれのような使い勝手を実現するには、ここで解説したような細かい調整をやらないといけないんだと思う。 僕自身はやる元気がないので、誰か代わりにやってくれないかなあ……と、実現する見込みの低そうな事をネットの片隅でこっそり呟いてみる次第です。
ツリー型タブではタブバーに表示するスクロールバーについて、普通のスクロールバーよりも細く表示するようにしてるんだけど、その実装方法に少し改善があったので誰得だけど解説しておく。
ちょっと前までのバージョンでは、単純にCSSのmax-width
で以下のように実現していた。
tabs.tabbrowser-tabs
.tabbrowser-arrowscrollbox
> scrollbox
> scrollbar[orient="vertical"],
tabs.tabbrowser-tabs
.tabbrowser-arrowscrollbox
> scrollbox
> scrollbar[orient="vertical"] * {
max-width: 10px;
min-width: 10px; /* この指定がないと逆に最小サイズが大きくなってしまう */
}
tabs.tabbrowser-tabs
.tabbrowser-arrowscrollbox
> scrollbox
> scrollbar[orient="vertical"] {
font-size: 10px;
}
この方法の難点は、一部のプラットフォームで……というかWindowsでスクロールバーの端のボタンの表示がずれるということ。 スクリーンショットを見ると、「▼」がちょっと右にずれてるのが分かる。 何故こうなるかというと、Windowsのスクロールバーの端のボタンのアイコンは最小サイズが大きめに定義されているようで、それよりも小さなサイズを指定してもWindows側の最小サイズが優先されてしまうせい。
この問題は、実用上は問題がないので長らく放置してたんだけど、最近ツリー型タブのissue trackerで閉じられてないままの古いissueを断捨離してる時にもっとこうしたらいいよという提案があったことに今頃気がついて、その方針を最近のバージョンで採用してみた。
これはどうやってるのかというと、スクロールバーの幅を小さくする代わりに、「スクロールバーの左右にマイナスのマージンを設定して他の要素の下に潜り込ませる」ことで、擬似的に細く見せている。
何ピクセル潜り込ませるかは環境によって変わってくるので、document.getComputedStyle()
なども使ってその都度計算するという面倒なことをしている。
これで、「▼」がずれるということがなくなった。
しかし、今度は副作用としてタブバーの背景色を変えている時に表示が変になるという問題が起こってしまった。 例えばClassic Theme Restorerをインストールして且つ「Mixed」スキンを選択した状態だと、水色の背景の一部がグレーになってしまってた。 これは、先の「マイナスのマージンを設定して他の要素の下に潜り込ませる」という手法において、スクロールバーが潜り込む先となる(スクロールバーの上に載って一部を覆い隠す)ボックスの背景色の指定が必要となってしまって、決め打ちで指定した色がユーザのカスタマイズ後の色と違うせいで見えてしまっているということ。 タブバーの背景色を変える方法はuserChrome.cssやらテーマやらClassic Theme Restorerやら色々とあるので、すべての場合にマッチする万能の対策は事実上無い。
ということで頭抱えてしまって、なんとかスクロールバーの潜り込んだ部分(はみ出た部分)を綺麗に消す方法はないかと、思いついた方法を色々試してみた。
max-width
でちゃんと細くできてたんだし)と思って試してみたら、ボタン部分だけがスクロールバーからはみ出すという結果になってしまった。
overflow-x:hidden
だな!と思って、スクロールバー全体にこれを指定してはみ出したボタンだけをどうにかしようと思ったけど、実際やってみたらスクロールバー全体の動作がぶっ壊れてしまうので駄目だった。
万策尽きてDOMインスペクタの画面とにらめっこしてた所、clip
という名前が見えた。そういえばCSSにはそういう機能もあるんだった。試したこと無かったから、じゃあそれで行けるんじゃないか?
ということで実際試してみたんだけど、これもスクロールバーのボタンには効いてくれなかった。
でも、MDNのプロパティ解説を見るとdeprecatedと書いてあって、誘導先を見たらclip-pathを使えと書いてある。
clip-path
というとFirefoxのタブの見た目などを丸くするのに実際使われてるプロパティだったはずなので、こっちなら大丈夫だろうと思って再挑戦したら、ようやくうまくいった。
Classic Theme Restorerとの併用時にも何ら問題がないことが見て取れる。
実装は以下のようになってる。
tabs.tabbrowser-tabs
.tabbrowser-arrowscrollbox
> scrollbox
> scrollbar[orient="vertical"] {
font-size: 10px;
max-width: 10px;
min-width: 10px;
clip-path: url(#treestyletab-box-clip-path);
}
tabs.tabbrowser-tabs
.tabbrowser-arrowscrollbox
> scrollbox
> scrollbar[orient="vertical"] * {
font-size: 10px;
max-width: 100%;
min-width: 10px;
}
tabs.tabbrowser-tabs
.tabbrowser-arrowscrollbox
> scrollbox
> scrollbar[orient="vertical"] scrollbarbutton {
font-size: 10px;
margin-left: -3px;
margin-right: -2px;
}
参照してるSVGのクリッピングパスは以下の通り。
<svg:svg height="0">
<svg:clipPath id="treestyletab-box-clip-path"
clipPathUnits="objectBoundingBox">
<svg:path d="m0,0 V1 H1 V-1 H-1 z"/>
</svg:clipPath>
</svg:svg>
このクリッピングパスはどういう形かというと、仮想的なキャンバス全体を覆い尽くす矩形になってる。m
から始まる相対指定で(0,0)
から(1,1)
までを覆う矩形を作っている(左上から始めて、下、右、上、左と反時計回りに進んでパスを閉じてる。最初は逆方向の時計回りに回ってしまってうまくいかなかった)ので、クリッピングパスの適用対象になるボックスがどんなサイズであってもそれと同じ大きさになる。
スクロールバーに対してこのクリッピングパスを反映すると、この矩形からはみ出る部分、つまりネガティブマージンではみ出してるボタンが切り取られて表示されるようになる、というわけ。
今回の実装自体のノウハウをそのまま流用できる場面はそうそうなさそうだけど、なんかの機会にまた使うかもしれないので、解説してみた。
要点をまとめると、「要素のスクロールの可否といった動作に影響を与えないで、見た目の表示サイズだけを小さくしたい時は、clip-path
を使うとよい」といったところでしょうか。
以上、ちっこい三角ひとつのためだけに四苦八苦させられた話なのでした。
アドオンのe10s対応のための作業をしようと思うと当然e10s有効状態でFirefoxを動かしとかないと意味ないんだけど、まだ完成度が低いということでかe10sは事あるごとに勝手に無効化される。すぐ死ぬ。マンボウかスペランカーかってくらいに、気がついたら勝手に無効化されてる。
なので、主に法人ユーザ向けの集中管理機構を使って、アドオンのデバッグ用の環境ではe10sを有効化するための設定を強制するように設定した。 autoconfig.cfgの内容は以下のようにした。
// 1行目は必ずコメントとする。
// 基本的な有効化の設定(設定ダイアログにあるチェックボックスに対応)
lockPref("browser.tabs.remote.autostart", true);
// アクセシビリティ機能によるe10s無効化を抑止
// https://bugzilla.mozilla.org/show_bug.cgi?id=1198459
lockPref("browser.tabs.remote.force-enable", true);
// アドオンがあることによるe10s無効化を抑止
// https://bugzilla.mozilla.org/show_bug.cgi?id=1232274
lockPref("extensions.e10sBlocksEnabling", false);
lockPref("extensions.e10sBlockedByAddons", false);
これで心置きなくe10s状態でのデバッグができます。