pre要素が横にoverflowして横転した話
lulliecatで使っているCSSのバグを直した話です。要素の中央寄せには、margin-inline autoではなく、display flexでjustify-content centerを使いましょう。
わりとしょうもない内容でしたが、忘れそうなのでメモ的に簡単に記事にしておきます。
前のポストで、このサイトでははじめて「```」を使ってコマンドプロンプトの作業について説明しました。 これはAstroのMarkdownの解釈システム(=unified, remark, rehype)では、preタグとcodeタグを使ってマークアップされます。 マークアップされたページをブラウザで表示させると、ブラウザの幅が狭い場合に、pre要素が横にoverflowし、同時に、pre要素を含むarticle要素も同じ横幅に広がってしまいました。 横スクロールしないようにウェブサイトを構築しているため、これは明らかなバグです。
最初はシンプルなmarkdownの記事を作りデバッグしていました。しかし、シンプルにしてもタグの入れ子が多く、なかなかバグを特定できませんでした。 そのため、ルートにtest.astroを作り、markdownの記事よりもっとシンプルな入れ子構造にしてから、入れ子構造を元に近づけていき、どこでoverflowが発生するかを確認しました。
バグはhtml > body > main > sectionで発生していました。このサイトでは、mainはブラウザの横幅いっぱいになるように設定してあります。一方、mainの子要素のsectionは、 max-widthを設定し、widthは設定せず、margin-inline: auto;を使ってsectionを中央寄せしました。 このmax-widthとmargin-inlineの組み合わせによる要素の中央寄せはわりと古典的なもので、昔からよく使われているようです。
しかし、このプロパティ指定による要素の中央寄せでは、sectionの子要素としてpreが利用されている場合で、 ブラウザ幅がmax-widthより狭い場合、pre要素のwidthがブラウザを超えてしまいます。 pre要素自体にはoverflow-x: scrollを設定してあり、横が溢れた場合もスクロールするようになっているのですが、 それにもかかわらず、pre要素の横幅がブラウザ幅を超えてしまいます。 pre要素にwidth: 100%を指定しても正しくレンダリングされませんでした。 pre要素のwidthにpxで直接値を設定すると横幅は正しく指定通りの幅になりましたが、その幅をcalcで計算させようとしても正しく指定できませんでした。 white-space: wrap指定すると、空白の箇所で内容が折り返し、ブラウザ幅を超えなくなります。しかし、 これは望む挙動ではありません。
原因は正直よく把握できていません。おそらくの推測ですが、pre要素には内在するコンテンツ幅の制約がきつい気がします。 sectionにwidthを指定せずmargin-inline: autoを使う手法では、widthを明示的に指定しないため、sectionのコンテンツ幅が 子要素のコンテンツ幅に影響されます。pre要素がブラウザ幅を超えるコンテンツ幅を持つ場合、sectionの幅もpreのコンテンツ幅に 従って広がったのではないか、と推測しています。
ただ、p要素など他の要素も内在するコンテンツ幅があるため、同じ問題が発生するような気もするのですが、何故preだけそのような挙動になったのかはわかりません。
ともあれ、この推測が正しいとすると、そもそもwidthを指定していないのが問題な気がしてきました。 そこで、widthを正しく指定しつつ中央寄せを行える手法として、flex layoutを利用しました。
flex layoutを利用した中央寄せは、近年よく使われると思います。align-items: centerとjustify-content: centerを使うことで、子要素を水平と垂直に中央寄せできます。 section要素のwidthを100%に明示的に指定し、section要素の親要素にdisplay: flexとflex-direction: column、align-items: centerを使用して中央寄せしました。 その他にもbox-sizingをborder-boxに変更するなど小さな修正をいくつか加え、無事要素を希望通りの表示にすることができました。
やはり、新しい手法であるflex layoutの方がシンプルで直感的ですね。widthを指定せずmargin-inline: autoにする手法は、どこか脱法的な香りがします。 昔からのブラウザの挙動が今でも実装されていることに期待した方法な気がします。 これからは、あまり深く考えずにflex layoutで中央寄せするのがよさそうですね!はい!