hogashi.*

日記から何から

切る/切って落とす

何を? 切る? 落とす?
切る 落とす
火蓋 切る 落とさない
口火 切る 落とさない

火ぶたを切って落とす? | ことば(放送用語) - 放送現場の疑問・視聴者の疑問 | NHK放送文化研究所

 「火蓋(ひぶた)」は、「(昔の鉄砲の)火縄銃の火皿の火口をおおうふた」のことで、「火ぶたを切る」の本来の意味は「火縄銃の火蓋を開いて点火の用意をする。また、発砲する」(『日本国語大辞典小学館)ことです。
(中略)
 ところで、「~を切る」という慣用語の一つに「口火を切る」ということばがありますが、この「口火」も火縄銃に関係があります。もともとは「火縄銃の火ぶたに点火するための火」のことで、ここから「物事を始めるきっかけをつくる」という意味の「口火を切る」が生まれました。

https://www.nhk.or.jp/bunken/summary/kotoba/gimon/137.html

きょうの日本語検定:時事ドットコムきょうの日本語検定:時事ドットコム

「幕を切って落とす」は、元々歌舞伎の用語で、舞台の幕を一気に落として演技を始めることから、何かを華々しく開始することをいう。

https://www.jiji.com/jc/e?g=e07&d=20180512&ans=3

ページ内のどの要素でscrollイベントが発火しているかとにかく見るには全部の要素にイベントリスナをつけると便利

 スクロールしたときどの要素で scroll イベントが発火しているか探すのが大変なことがあるけど、とにかく全部の要素にイベントリスナをつけて、実際にスクロールしてみることで、とにかく発見することができる。

document.querySelectorAll('body *').forEach(el => {
  el.addEventListener('scroll', e => {
    console.log(e.currentTarget);
  });
});

 たまにこういう力技が役に立つ。↓は以前やった body * の例。

blog.hog.as

Slackはハイライト部分をU+E000とU+E001で囲って表していそう

 Slack は、メッセージのどこからどこまでハイライトするかを、 Unicode の私用領域 *1の U+E000 と U+E001 を使って表しているらしく、こういう HTML を glitch とかで書いて、

<html>
  <head>
    <meta property="og:title" content="Slackで&#xE000;タイトルをハイライト&#xE001;する" />
    <meta
      property="og:description"
      content="Slackで&#xE000;説明&#xE001;&#xE000;好きな部分をハイライト&#xE001;する"
    />
  </head>
</html>

そのページを Slack で展開させたりすることで、好きな部分を勝手にハイライトできて面白い *2 *3

 ちなみに printf "\ue000寿司\ue001が光ったら成功" | pbcopy とかして Slack のメッセージ欄にペーストして普通に送信しても、そのまま豆腐が出るだけだった。 API 経由で送ったりしたらハイライトされたりするかも。

 詳しくどういうことなのかはわからないものの、ハイライトすべき部分を U+E000 と U+E001 で囲い、そこをハイライトする HTML タグ (スマホアプリではそれ用のコンポーネントとか?) に変換したりしていそう。
 これに気づいたのは偶然で、同僚が「Slack の検索画面で自分の名前が豆腐に囲まれている」と言っていたのがきっかけ。文字コードを調べると U+E000 と U+E001 で、これをググってふむ〜って Slack に貼ったら光っていて、マジか!と言いながら glitch を開いて確かめた、という感じ。

 「Slack E000」とかでググると意外とヒットして、というか Slack の API の説明にも登場する (https://api.slack.com/search?query=e000 で検索できる)。登場するのは https://api.slack.com/methods/search.messageshttps://api.slack.com/methods/search.files で、どちらも同じような説明が書かれている。メッセージやファイルを検索する API で、ハイライト部分を表すのに U+E000 と U+E001 が使われているよ、とのことだった。

All search methods support the highlight parameter. If specified, the matching query terms will be marked
up in the results so that clients may replace them with appropriate highlighting markers
(e.g. <span class="highlight"></span>). The UTF-8 markers we use are:

start: "\xEE\x80\x80"; # U+E000 (private-use)
end  : "\xEE\x80\x81"; # U+E001 (private-use)
search.messages method | Slack

*1:https://www.unicode.org/charts/PDF/UE000.pdf とかを見ると「E000-F8FF」は「Private Use Area」で「The Private Use Area does not contain any character assignments, consequently no character code charts or names lists are provided for this area.」らしい

*2:クエリパラメータは違う URL として認識してもらって展開のキャッシュを無視するためにつけている

*3:面白いのでこの記事の og:description の最初の読点の前後にも入れてみた → もっと面白いとよいということで「U+E000 と U+E001 を使って」をハイライトするようにしてみた

ブラウザで:has()セレクタが実装されてjQueryの:has()セレクタの挙動が変わったの調べた

 Chromeに実装された疑似クラス「:has()」がjQueryの「:has()」に悪影響、一定の条件下でWebサイトが壊れる可能性 - Publickey を読んだので、調べたものとあわせてまとめる。

三行

原因

  • jQuery には CSS セレクタの拡張がされている
  • jQuery は、セレクタによって要素を取得する際、パフォーマンスのためにブラウザの querySelectorAll() メソッドを使う
    • セレクタが不正だった場合は querySelectorAll() メソッドがエラーになるので、 jQuery の拡張された実装で要素を取得し直す (フォールバックするような感じ)
  • かつては :has() はブラウザの querySelectorAll() メソッドにとって不正なセレクタだったため、 (エラーになるので、) jQuery の実装で要素が取得されていた
    • このほどブラウザで :has() が実装された
      • ここまでは問題なく、 jQuery でやっていたことがブラウザでもできるようになったということ
    • ただし、 :has() の引数に書かれたセレクタは不正でも無視される
  • これにより、 :has() の引数に、ブラウザでは対応していない jQuery の拡張のセレクタを書いた場合、 jQuery で処理されなくなってしまった
    • 今まで jQuery で取得できていたが、取得できなくなった
forgiving-selector-list

 MDN から :has() の仕様をたどるとここで、引数には <forgiving-relative-selector-list> をとると書かれている。

The relational pseudo-class, :has(), is a functional pseudo-class taking a <forgiving-relative-selector-list> as an argument.

https://w3c.github.io/csswg-drafts/selectors-4/#has-pseudo

 <forgiving-relative-selector-list> の項 https://w3c.github.io/csswg-drafts/selectors-4/#typedef-forgiving-relative-selector-list を見ると、 <forgiving-selector-list> でありながら <complex-selector> ではなく <relative-selector> としてパースされるものとある。今回は <forgiving-selector-list> であるという部分だけ気にしたらよい。

 <forgiving-selector-list> は、セレクタそれぞれをひとつずつパースし、パースに失敗したセレクタは無視して、成功したものだけを使うとのこと。今回の (ブラウザの) :has()querySelectorAll() だけを試すとこういう感じで、ブラウザではセレクタとしてパースできない :even が引数にあるが、エラーにならずに単に無視されている *1


ChromeSafari の状況の違い
  • 記事中のツイートでは、 Safari の実装では jQuery の挙動を変えないと書かれているように読めた
    • しかし調べたところでは、 Safari でも部分的に jQuery の挙動を変えてしまっていそうに見える
  • Safari:has() の引数を forgiving-relative-selector-list として完全に実装できていないので、 jQuery の挙動が変わってしまう場合と変わらない場合がある

 実際 SafariquerySelectorAll() だけを試すとそのようになっている *2:even はブラウザでパースできないので、 :even がついたセレクタだけが引数にある場合 (1行目と 3行目) はエラーになっている (この場合は jQuery が要素を取得でき、挙動は変わらない)。対して 2行目は body がパースできるセレクタのため、エラーにならない (この場合は jQuery が処理をしないので、挙動が変わってしまう)。


されている対応と今後

Of course, there's still some breakage for selectors like `div:has(div, span:contains('Item'))` but, as I understand, Chrome is hoping that there's not much usage of it in the wild considering WebKit was able to go away with it.

https://bugs.chromium.org/p/chromium/issues/detail?id=1358953#c40

感想

 jQuery 側を直したい気持ちになるけど、古いバージョンのまま残っているサイトを壊さないという観点ではそれは難しいので、ブラウザ側がなんとかして避けるしかないのが (いつもそうだけどやはり) 大変そう。 forgiving-selector-list は初めて知ったし forgiving/unforgiving という表現が使われるのはへ〜という感じだった。あと Chromium の issue で querySelectorAll()qSA と略されて呼ばれているのが面白い。

*1:Google Chrome 105.0.5195.102

*2:Safari 16.0 (17614.1.25.9.10, 17614)