• ITに強い編集プロダクション・リブロワークスのWebサイト

    CSS組版の小技を紹介します!

    『CSS組版Vivliostyle入門』のではmargin-breakプロパティについて解説しています。これは要素がページ上部に配置されたときに、上マージンを調整します。この説明自体は間違いではありませんが、1つ補足が必要です。

    書籍P.74

    margin-breakプロパティのautoは、自然な流れによって要素が次ページに送られた場合は、上マージンを削除します。右ページ上の囲み枠パーツ(ティーブレイク)は上マージンが削除されていますね。

    自然な流し込みで次ページに送られた場合(わかりやすいように版面に着色)

    しかし、break-afterなどを使った任意改ページで送られた場合、上マージンを削除しないのです。これは組版としては不自然ですね。

    任意改ページで送った要素の上マージンは削除されない

    解決編:任意改ページ後の上マージンを削除する①

    この問題を解決するには、任意改ページ後に要素が続くときだけ、margin-break: discard;を指定します。ふだん筆者はhr要素を改ページの指定に使っているので、hr + .column-dというセレクタを追加しておけば、改ページ後の要素の上マージンを削除できます。

    column-docking.css

    /* hr(改ページ)の直後のコラム */
    hr + .column-d {
      margin-break: discard;
    }
    
    任意改ページのあとでも上マージンが削除される

    解決編:任意改ページ後の上マージンを削除する②

    見出しの場合、上記の方法では解決できません。VFMが見出し要素を囲むsection要素を自動生成するため、次のようなHTMLになることがあるのです。これだとhr + h4のような簡単なセレクタでは選択できません。

    <section>
      <h3>h3の見出し</h3>
      ……中略……
    
      <hr>
      <section>
        <h4>h4の見出し</h4>
        ……中略……
      </section>
    </section>
    <section>
      <h3>h3の見出し</h3>
      ……中略……
      <section>
        <h4>h4の見出し</h4>
        ……中略……
        <hr>
      </section>
      <section>
        <h4>h4の見出し</h4>
        ……中略……
      </section>
    </section>

    これらのパターンも解決しようとすると、次のようなセレクタを書く必要があります。

    main.css

    /* hr(改ページ)の直後のh4 */
    hr + h4,
    hr + section > h4:first-child,
    section:has(hr:last-child) + section > h4:first-child {
      margin-break: discard;
    }
    

    言葉で説明すると、「hrの直後にあるsection内にある最初のh4」と「最後の要素がhrであるsectionの直後にあるsection内にある最初のh4」となります。かなりややこしいですが、これで見出しでも上マージンを削除できるようになります。

    h4要素の上マージンを削除

    見出しの要素ごとに個別に設定するのも面倒なので、新しめの疑似クラス関数である:is()を使うと、指定をまとめられます。必要に応じて:is()のカッコ内に要素を追加してください。

    main.css

    hr + :is(h3, h4),
    hr + section > :is(h3, h4):first-child,
    section:has(hr:last-child) + section > :is(h3, h4):first-child {
      margin-break: discard;
    }
    

    今回の記事のサンプルファイル

    https://github.com/libroworks/CSSkumihan_freeformats/tree/main/blogs/margin-break