レスポンシブWebデザインと長い縦書きのコンテンツ

公開

なかなか的確なタイトルが思い浮かばないのですが主旨は次の通りです。縦書きで表示させたい長い文章がある状況で、画面の左端まで到達した時にまだ表示していない文章がある場合、画面右下に移動してまた左に向かって表示させることができるのか否か、です。表示領域の高さ(height)と段組(column-count)を指定すれば良いのでは?と思われるかもしれませんが、文章量は不定、画面幅もスマートフォンからタブレット、パソコンまでさまざま、という条件です。局所的に短文を縦書き表示させるのとは少し事情が違うように思います。heightを指定せず、段組なしで表示できるときは段組なしで表示する、必要な分だけ段組が構成されて文章が表示される、1行の文字量(後述しますがinline-size)は自由に調節したい、ということです。

結論としてはcolumn-widthを指定することで複columnコンテナ(multi-column-container)となり目的が達成できました。CSS Writing Modes Level 4の「7.3.2. 直交フローにおけるブロックコンテナの自動サイズ法」でも言及されていますが、正直なところ難しく完全理解までは至っていません。また時間を取って研究したいと思います。なお、「自動的な複columnフローの誘発はリスク下にある。」とあるので今後の動向に注意する必要もありそうです。
Chromeで宮沢賢治の銀河鉄道の夜を表示させた画面。2段組で文章が表示されている。
iPhoneで宮沢賢治の銀河鉄道の夜を表示させた画面。こちらも2段組で文章が表示されているが文章が次の段に行く位置がパソコンと違う。

ちなみに、サンプルコードでもblock-sizeinline-sizemargin-block-startのような論理的プロパティを使用している中で、column-widthを使うことにどうももやもやします。column-sizeはないのでしょうか。

サンプルコード

サンプルのHTMLファイルもアップロードしています。ご覧ください。

HTML

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>宮沢賢治「銀河鉄道の夜」</title>
</head>

<body>
  <main>
    <div class="text-vertical work">
      <h1 class="work-title">銀河鉄道の夜</h1>
      <div class="work-author">宮沢賢治</div>
      <div class="work-content">
        <p>「ではみなさんは、そういうふうに川だと云いわれたり、乳の流れたあとだと云われたりしていたこのぼんやりと白いものがほんとうは何かご承知ですか。」先生は、黒板に吊つるした大きな黒い星座の図の、上から下へ白くけぶった銀河帯のようなところを指さしながら、みんなに問といをかけました。</p>
        <p>カムパネルラが手をあげました。それから四五人手をあげました。ジョバンニも手をあげようとして、急いでそのままやめました。たしかにあれがみんな星だと、いつか雑誌で読んだのでしたが、このごろはジョバンニはまるで毎日教室でもねむく、本を読むひまも読む本もないので、なんだかどんなこともよくわからないという気持ちがするのでした。</p>
      </div>
    </div>
  </main>
</body>
</html>

CSS

.text-vertical {
  writing-mode: vertical-rl;
  font-family: serif;
}
.work {
  margin: 1em 0;
  column-width: 80vh;
  column-gap: 3em;
  column-rule: dotted 1px;
  block-size: 100%;
  // inline-size: 70vh; 不要でした
}
.work-title {
  margin-inline-start: 2em;
}
.work-author {
  margin-block-end: 2em;
  margin-inline-end: 1em;
  font-size: 1.25rem;
  text-align: end;
}
.work p {
  text-indent: 1em;
}

複カラムになった時に高さが正しく算出されていない

複カラムになった時、縦書きエリアの後にあるコンテンツが縦書きエリアの途中に表示されることに気付きました。どうも縦書きエリアの高さが正しく算出されないようです。

現時点ではどうやっても対処できないように感じたので、JavaScriptでフォローしてやることにしました。具体的には縦書きエリアの最後の要素の位置などから縦書きエリアの高さを算出し、縦書きエリアにstyle属性でheightを指定します。2つめのサンプルのHTMLファイルもアップロードしています。

なお、このやり方の欠点は、どうも見た目の良いところで次のカラムに移行しないところです。やはり縦書きはまだ厳しいのか…。

(function () {
  let timerId = null;
  let isSetHeight = false;
  let currentInnerWidth = null;
  function resetVerticalTextElemHeight() {
      isSetHeight = false;
      const attitudes = document.querySelectorAll('.text-vertical');
      attitudes.forEach((attitude) => {
          attitude.style.height = 'auto';
      });
  }

  function calcVerticalTextElemHeight() {
      isSetHeight = true;
      const attitudes = document.querySelectorAll('.text-vertical');
      attitudes.forEach((attitude) => {
          const elemTopPositionY = window.pageYOffset + attitude.getBoundingClientRect().y;
          const lastElem = attitude.querySelector('.work-content p:last-child');
          const lastElemRect = lastElem.getBoundingClientRect();
          const containerHeight = window.pageYOffset + lastElemRect.bottom - elemTopPositionY;
          attitude.style.height = containerHeight + 'px';
      });
  }
  window.addEventListener('load', () => {
      currentInnerWidth = window.innerWidth;
      requestAnimationFrame(calcVerticalTextElemHeight);
  });
  window.addEventListener('resize', () => {
      if (currentInnerWidth !== window.innerWidth) {
          if (timerId) {
              clearTimeout(timerId);
          }
          if (isSetHeight) {
              resetVerticalTextElemHeight();
          }
          timerId = setTimeout(() => {
              requestAnimationFrame(calcVerticalTextElemHeight);
          }, 500);
      }
  });
}());