【学習61日目】重ねた文字のレイアウトがiOSで崩れる話

コーディング

緊急でブログを書いています。(言ってみたかったやつ)

前回の記事で、jQueryでユーザーエージェント使用デバイスを認識して、iOSだったらちょっとずらすコード書いて解決だったぜドヤー!って言いました。

HTML/CSSだけじゃなくて、スクリプトを使ったことでデキる人間になった気がしていました。

けど全然解決じゃありませんでした。

初回のロード時は上記の方法によりいい感じに修正できていたものの、ページを更新するとさらに左にずれてしまう……!という残念な結果に。

ページの更新なんてしなかったから気付かなかった。悔しい。

なおiPhoneでchromeを使用したときも同様のことが起きます。なのでブラウザというより、やっぱりiOSが悪い。

さあ何でこんなことが起きるのかな?考えてみよう!

不具合が起きているところを認識する

前回までの状況を振り返る

さて、前回設定したHTMLやCSSはこんな感じでした。(モバイル版のみ載せます)

<section class="main-bg">
    <img src="img/mainvisual.jpg" alt="歯科医師が患者の口内を治療しているシーン">
    <div class="main-bg-text">
        <div class="overlay-text">
            <h2>
                <span class="highlight">
                    <span class="blue">地域に愛される</span>歯科医院へ
                </span><br>
                <span class="highlight">
                    <span class="pink">健康な歯</span>で笑顔の毎日を
                </span>
            </h2>
        </div>
    </div>
</section>
/*        モバイル版         */
@media screen and (max-width: 600px) {
    .main-bg-text {
        top: 4%;
        left: calc(50% - 25%);

        position: absolute; /* PC版を引き継ぎ */
        transform: translateX(-50%); /* PC版を引き継ぎ */
    }    

    .iOS .main-bg-text {
        left: calc(50% - 35%);
    }
}

本来は画面の左半分の中央寄せでテキストを表示したい。

left: calc(50% – 25%);で左から25%の位置にテキストを置く。これだとテキストの左端が25%の位置に来ます。
なのでtransform: translateX(-50%);でテキストの半分だけ左に移動、つまりテキストの中央が25%の位置に来るようにする。

iOSだとこれが少し右にずれてしまうので、jQueryでユーザーエージェントを認識して、iOSからだったらbodyにiOSクラスを追加。
iOSクラスがbodyについていたら、テキストの位置を左から15%の位置に修正。

なんでcalc(50% – XX%)としているかって?chatGPT様がそうした方がいいよって言ったからだよ(つまり説明できません^^)

とりあえずこんな感じにしていました。

ここでおかしくなっているのはどこか、もう一度画像とにらめっこしてみましょう。

高さの指定であるtop: 4%;は正しく動いていそう。

おかしいのは左右の位置です。

前回はleftが悪いのかな?iOSは計算がちょっと違うのかな?とごり押しで%の数値を変えて対応していたのですが、ページ更新で変わってしまうあたりそうではなさそうです。

transformが悪さをしている説

leftじゃなければここかなと。理由も説明しますね。

Figmaで10%ずつにグリッド線を引きながら確認してみました。
左が初回ロード時、右がページ更新後です。

左から15%の場所を確認してみましょう。
初回ロード時はテキストの左端が、ページ更新後はテキストの中央が、左から15%の場所に来ていることが確認できました。

つまり、初回ロード時はtransform: translateX(-50%);が効いていなさそう!!!ということに気付きました。

確かにiOSとtransformが相性悪そう、っていうのは見たことがある……。けど、みんなtranslateZがうまくいかない、という記事ばかりだったので自信がなかった。
leftの位置を修正することで解決できたと思い込んで、目をつぶっていた。そこが反省である。

では、transformが悪さをしていると決め打って、対策を考えていきましょう!

transformを使わない書き方にしよう

transformを使わないで画面左半分の中央にテキストを設置したい。

これを考えていたとき、おぼろげながら、浮かんできたんです。「gridレイアウト」という文字が。

どうせならPC・タブレット版の表示もgridレイアウトにしてやろう。そうしよう。

どうグリッドを引くか考える

超絶雑ですが、こんな感じにしようかなと。

PC・タブレット版メインビジュアルのグリッド

デスクトップ・タブレットのメインビジュアル

デスクトップ・タブレットは左から35%の場所に中央寄せにしていました。

行は30:70、列も30:70でグリッドを引き、行2本目、列1本目のところにテキストを置く。
テキストはグリッドコンテナの中で上端・中央に寄せる。っていう計画。

これでテキストの中心線は35%のところにきます。

モバイル版メインビジュアルのグリッド

モバイル版のメインビジュアル

画面左半分の中央寄せ。

こっちの方が考え方は簡単でした。transform: translatex(-50%);も必要ない!!

行は4:96、列は50:50でグリッドを引き、行は2本目、列は1本目のところにテキストを置く。
そしてグリッドコンテナの中を上端かつ中央寄せになるように設定すればオッケー!っていう計画。

コーディングしてみる

まずはPC・タブレット版を作って、次にモバイル版のレスポンシブ対応をします。

PC・タブレット版グリッドレイアウトのコード

.main-bg {
    position: relative;
    display: grid;
    grid-template-rows: 30% auto; /* 30:70 */
    grid-template-columns: 35% auto; /* 35:65 */
}

.main-bg img {
    width: calc(var(--vw) * 100); /* 全幅指定 */
    object-fit: cover;
    min-height: 400px;
}

.main-bg-text {
    grid-row: 2; /* 2行目 */
    grid-column: 1; /* 1列目 */
    align-self: start; /* 上端揃え */
    justify-self: center; /* 中央揃え */
    color: #000;
}

行は30:70、列は35:65でグリッドを引き、行2本目、列1本目のところにテキストを置く。
テキストはグリッドコンテナの中で上端・左端に寄せる。

これで完璧!と思いきやそうでもない。

メインビジュアルがおっきくなっちゃった……。

メインビジュアルimgの大きさでグリッドを引いてほしかったのだけど、謎に大きくなってしまった。
そのせいでテキストの位置は理想より下になり、次のコンテンツ(当院の特徴)までの余白も大きくなってしまった。

.main-bg img {
    width: calc(var(--vw) * 100);
    object-fit: cover;
    min-height: 400px;
    grid-column: 1 / -1;
    grid-row: 1 / -1;
}

これは下の2行を追加して解決。

メインビジュアルimgは、グリッドの1(上端・左端)から-1(下端・右端)までですよ、って指定したところ、うまくいきました。

これよ。これこれ。

モバイル版グリッドレイアウトのコード

次が本番。

/*        モバイル版         */
@media screen and (max-width: 600px) {
    .main-bg {
        position: relative; /* PC版を引き継ぎ */
        display: grid; /* PC版を引き継ぎ */
        grid-template-rows: 4% auto; /* 4:96 */
        grid-template-columns: 50% auto; /* 50:50 */
    }

    .main-bg-text {
        grid-row: 2; /* 2行目 */
        grid-column: 1; /* 1列目 */
        align-self: start; /* PC版を引き継ぎ(上端揃え) */
        justify-self: center; /* 中央揃え */
        transform: none;
    }
}

行は4:96、列は50:50でグリッドを引き、行は2本目、列は1本目のところにテキストを置く。
そしてグリッドコンテナの中を中央寄せになるように設定すればオッケー!
transformは消しておく。

さあ、モバイル版はこれでうまくいくか!?
WindowsPCでchromeのデベロッパーツールのモバイル表示ではクリア!!

ではiPhone実機では……?

右に寄ってるぅ~~~

なんでだよ!!

なんでですか?わかりません。

justify-self: start;にすると、テキストの左端がメインビジュアルの左端に来ます。これはわかる。

justify-self: end;にすると、テキストの左端がメインビジュアルの中央に来ます。ん???
メインビジュアルの中央ってことは、2列目、つまり指定したグリッドコンテナの右端……。

ということはこれ、justify-self: center;にすると、指定したグリッドコンテナの中央にテキストの左端が来ているな?中身を中央寄せにしてほしかったんですけど!!

悩んでいたところ、chatGPT様が以下のようにすると解決するかもよと提案してくださいました。

/*        モバイル版         */
@media screen and (max-width: 600px) {
    .main-bg-text {
        grid-row: 2; /* 2列目 */
        grid-column: 1; /* 1列目 */
        justify-self: end; /* 中央揃え */
        transform: none;
        display: flex;
        justify-content: center;
    }
}

これをやったら……な、直った!!更新してもずれない!!すっげ~~~~

chatGPT先生曰く、以下の通りです。

1. iOSで起きた問題の背景

iOSのSafariは、特定の状況下で以下のような動作をすることがあります:

  • グリッドレイアウトの誤認識
    グリッドの指定が複雑な場合、特にgrid-template-rowsgrid-template-columnsに計算式やautoが混在していると、iOSが正確な配置を計算できないことがあります。
2. display: flex; の特性

display: flex;は、以下の理由でより信頼性の高い配置方法です:

フレックスボックスによる中央揃えの確実性
  • 水平方向の中央揃え(justify-content: center;
    justify-content: center; を使うと、コンテナ内の要素が確実にコンテナの水平方向中央に配置されます。
    → iOSの計算ミスが生じにくい。
  • フレックスアイテムの自然なサイズ管理
    子要素がデフォルトでフレックスコンテナ内の利用可能なスペースに合わせてサイズを自動調整します。
グリッドにない「動的な調整」
  • グリッドは基本的に固定されたセルに基づいて配置されるため、セルのサイズ計算にミスが生じると、要素が期待通りに表示されません。
  • 一方、フレックスボックスは “利用可能なスペースに対して要素を動的に揃える” 性質があり、計算の誤差が生じにくいのです。
3. なぜこれで解決できたのか
  • justify-content: center; が、意図する位置に要素を配置するための最短ルートを提供。
  • iOS特有のバグを回避
    グリッドレイアウトで問題が起きていたのは、iOSの処理中に特定のスタイルが正しく計算されなかった可能性があります。しかし、フレックスボックスを使うと、iOSは単純な計算で済むため、問題が発生しません。

どこまで信じていいかもわからんし、私にはまだいまいち理解しきれていないのですが……。

とりあえず不具合を修正できたので良かった。でいいかな。あんまり良くないけど。

最後に

最後に思ったこと。

検証のためにMacとiPadほし~~~~~い!!!誰か~~~~~~~~~!!!!

はあ、iOSクラスはもういらないし、前回のjQueryコードは削除削除っと。

おわり。続き頑張るね。

コメント

タイトルとURLをコピーしました