シカクいブログ

あるプログラマーの随筆

フロントエンドに対する愚考

classという曖昧な存在

二つのHTMLがある。

<!-- some.html -->
<div id="some">
  <div class="button">ボタン</div>
</div>

<!-- home.html -->
<div id="home">
  <div class="button">ボタン</div>
</div>

さてbuttonというトークはどういう意味を持っているのだろうか?

  1. 要素の役割を説明するための、ただの文字列。
  2. cssから.buttonでスタイルが当たっている。
  3. cssから#some .buttonでスタイルが当たっている。
  4. cssから#home .buttonでスタイルが当たっている。
  5. jsから.buttonで処理が登録されている。
  6. jsから#some .buttonで処理が登録されている。
  7. jsから#home .buttonで処理が登録されている。

答えは上記のどれか、もしくはいくつかを組み合わせたものであり、また二つのbuttonが同じ意味を持つとは限らない。

答えは上記のどれか、もしくはいくつかを組み合わせたものであり、また二つのbuttonが同じ意味を持つとは限らない

ふざけてる。何かしらの県の条例に違反しているに違いない暴挙だ。

HTMLもCSSプログラミング言語ではないが、コードである

誰がなんと言おうとHTMLもCSSプログラミング言語ではない。そんなことはケツを拭いた紙で顔を拭いてはいけないことくらい明らかだ。

しかしだからと言って管理が必要ないわけではない追跡できなくても良いわけではない

CSSに注視する

まずはCSSを吊し上げる。JSも似たようなものだから、脳内でいい感じに変換して欲しい。

/* base.css */
.button {
  width: fit-content;
  padding: 0.5rem;
  border: solid;
}

/* home.css */
#home .button {
  color: red;
}
<!-- some.html -->
<div id="some">
  <div class="button">ボタン</div>
</div>

<!-- home.html -->
<div id="home">
  <div class="button">赤文字ボタン</div>
</div>

はっ。ゴミだ。ファミチキだけ先に食べてしまった後に残ったファミチキバンズくらいゴミだ。

どこがどうゴミなのか

二足歩行動物ならば、上記のコードのどこがダメなのかはすぐに理解できるはずだ。なのでこのセクションは猫に向けて書いたものである。

まずは発想の転換だ。CSSだのHTMLだの、そんな先入観はファミチキバンズに挟んで熱々のMacBookの上に置いておこう。

特殊なプログラミング言語として捉えるのだ

home, someはネームスペース、buttonは関数、cssは関数定義、class="button"button関数に引数としてその要素を渡す、とても気持ち悪い書き方だ。

このルールに従ってJSっぽい擬似コードとして書き換えるとこうなる。

// #1
function button(element) {
  element.width = "fit-content";
  element.padding = "0.5rem";
  element.border = "solid";
}

namespace home {
  // #2
  function button(element) {
    element.color = "red";
  }
}

namespace some {
  // #1のbutton関数が呼ばれる。
  button(window.some.buttonElement);
}

namespace home {
  // #1と#2のbutton関数が連続して呼ばれる。
  // ここだけ見てもそれはわからない(追跡不可能)。
  button(window.home.buttonElement)
}

同名の関数が存在すれば暗黙的にその全てを順番に呼び出してくれる、そんな親切なプログラミング言語だ。なんとネームスペースまで考慮してくれるぞ!

こんなプログラミング言語があったらどうだろうか? 少なくとも私は使いたくない。世の中の主流プログラミング言語の仕組みの傾向から見るに、多くの人たちは私と同意見のはずだ。

どうしてもこの言語を使わざるを得なくなっても、メンテナンス可能なコードにするために、暗黙的な呼び出し機能を回避してこう書き換えるはずだ。

function button(element) {
  element.width = "fit-content";
  element.padding = "0.5rem";
  element.border = "solid";
}

function homeButton(element) {
  // 明示的に呼び出すことで、追跡可能となった。
  button(element);
  element.color = "red";
}

namespace some {
  button(window.some.buttonElement);
}

namespace home {
  // 特定の一つの関数に絞られたため、追跡可能となった。
  homeButton(window.home.buttonElement)
}

なんならこう。

function button(element) {
  element.width = "fit-content";
  element.padding = "0.5rem";
  element.border = "solid";
}

namespace some {
  button(window.some.buttonElement);
}

namespace home {
  button(window.home.buttonElement)
  // 関数にするほどのことでもない。
  window.home.buttonElement.color = "red";
}

以上のことを踏まえて、我々はどうすべきか

トークン(classだろうが何だろうが)は一つの意味しか持つべきではない。マイナンバーも一人一個だ。そういうことだ。

HTMLから最後の最後まで追跡可能な仕組みであること。無限の可能性を考慮するのに、人生は短すぎる。

CSS

  • 同名のブロックを決して定義しない(ネストしていても不可)
  • 当然再利用もしたい。

TailwindCSSを使う。applyが重要だ。

TailwindCSSは全部ベタ書きを推奨しているようなので、仕組みを使っても理念には(完全には)従わない。

@layer components {
  .button {
    @apply border-solid w-fit p-2;
  }
  .home-button {
    // buttonまで追跡可能。
    @apply button text-red-500;
  }
}
<!-- some.html -->
<div id="some">
  <div class="button">ボタン</div>
</div>

<!-- home.html -->
<div id="home">
  <!-- 特定の一つのcomponentに絞られるため、追跡可能。 -->
  <div class="home-button">赤文字ボタン</div>
</div>

なんならこう。

@layer components {
  .button {
    @apply border-solid w-fit p-2;
  }
}
<!-- some.html -->
<div id="some">
  <div class="button">ボタン</div>
</div>

<!-- home.html -->
<div id="home">
  <!-- 新しいcomponentにするほどのことでもない。 -->
  <div class="button text-red-500">赤文字ボタン</div>
</div>

場合によってはstyle-プレフィックスをつけても良いかもしれない。

JS

ReactやVueなら特に工夫する必要はない。

  • classとコールバックは必ず一対一
  • スタイルとの名前衝突回避のため、js-プレフィックスをつける。 スマートではないが、仕方がない。 Stimulusを使おう。
import $ from 'jquery';

$('.js-home-button').on('click', () => { console.log('Clicked home button.'); });
<!-- home.html -->
<div id="home">
  <div class="button">赤文字ボタン</div>
</div>

<!-- some.html -->
<div id="some">
  <!-- 特定の一つのJS処理に絞られるため、追跡可能。 -->
  <div class="home-button js-home-button">ボタン</div>
</div>

ここから先は普通にJS書いていれば追跡可能。

Stimulusは普通にしているだけで条件を満たせる。やはりRailsが最強か(Rails信者脳)。

結果

これでHTMLからその要素に何が起こるのかが追跡可能になった。削除漏れが起きづらい。

逆側からも同じで、そのスタイルorJSがどの要素に当たっているのかの追跡が楽になる。つまり影響範囲の調査も楽。

最後に

知らんけど。

規則正しい生活などなかった

 驚くことに、私はすでに規則正しい生活を放棄している。強い気持ちでそれを決意したのはちょうど一週間前。

 やる気はあったし、それだけは持続している。散歩にも毎日出かけたが、大きな問題があった。眠れないのだ。それも夜だけ。

 十時にベッドにつき、七時間後である五時にアラームをセットする。寝付きは良くないが、大きな問題ではない。問題は起床時間である。一時前後には起きてしまうのだ。今日の昼なんか、昼寝のつもりが十時間も寝てしまったというのに!

 この長く眠れないタイプの、それも夜だけの不眠問題を、私はかなり長いこと抱えているが、何を改善すれば良いのか皆目検討もつかない。運動不足だと思っていたが、毎日一時間程度の散歩では足りないのか、それとも違っていたのか。

 慢性的なものだから、そう簡単には改善されないという説もあるため、とりあえず、いきなりパーフェクトを目指すのは放棄して、散歩だけは継続しようかと考えている。

 道程は長い。

小説が書けない

 恥ずかしながら、小説を書いている。ネット上に投稿して、そこそこの評価――と言っても、書籍化には程遠いもの――をいただけたものある。しかし、それは処女作であり、プロットもなしで、行き当たりばったりに設定を乗せたために、続きを書けなくなってしまった――エタったのだ!――。一人称だった所もツライところだ。

 それで、今度はひっそりと、ある程度完結の目処が立つまでは、オフラインで書こうと思っているのだが、これが難しい。三千字程度までは何とか書けるのだが、どうも面白くない。文章にどうも違和感があり、書いたり消したりを繰り返してる内に、飽きてしまうのだ。

 これではだめだ、と次は見直しを最低限に、とりあえず一万字まで書き続けてみようかと思っている。果たして私に完結作品が書けるのだろうか……。

 乞うご期待! である。

強い気持ちで生活リズムの改善を決めた

 浅はかな人間である私は昨日、

【天才たちのルーティン①】後世に名を残す偉人には共通の習慣がいくつもあった! - YouTube

 を見て、強い影響を受けた。

 断っておくが、これは自分の生活リズムさえ整えれば、天才に化けるかも知れないなどという期待から来る考えではない。――嘘だ。恥ずかしながら、実際には少しばかりの期待はある。

 いつからか、頭がぼんやりと重たいのだ。学生の頃はそうでもないような気がするのだが、はっきりとは思い出せない。思い出せないということは、当時は少なくとも気にするほどの症状はなかったという証明でもある。

 私はこれを運動不足のせいだと思っている。病院に行ったわけではないので、確証はないが、高校生で帰宅部に入学して以来、日々の運動量は限りなくゼロに近く、体重も増え、お腹もぽっこりと出てきた――誓って言うが、太っていると言うほどではない――ので、間違いないだろう。

 この運動不足を解消しようと私は自宅で筋トレをしてみたり、ジムに入会してみたり、リングフィットアドベンチャーをプレイしてみたりと、色々試行錯誤したが、どれも長くは続かなかった。私は辛いことが嫌いなのだ。例え健康を約束されようとも。

 散歩というのは意外な盲点だった。やはり運動といえばランニング以上のものだろう、という先入観があったのだ。もっとも、散歩にしたって――それも、一時間以上の!――、簡単に続けられるものだとは思えない。しかし、過去の偉人たち――それも複数の――が実践していた、天才になれるかもしれないルーティーンとなると、少し違うのではないか。誰だって天才になりたいものである。

 果たしてこの決心が何日続くのかは、未来の私のみが知ることだが、少なくとも現在の私の決心は固い。――今までに思いつき、そして挫折した他の数々のプランと同じくらいには。

 私はここに宣言する! いや、やはりやめておこう。恥をかくリスクを自ら背負うことはないのだ。