Prompt

cssのaspect-ratioがPC(Chrome)環境だと動くのにIOS(Chrome)環境だと動かない!
タスケテー
使えなさそうなら代替案もアリ

やっほー!CSSのaspect-ratioがPCのChromeでは動くのに、iOSのChromeだと動かないって、めちゃくちゃ困るよね!バグかと思ってしまうけど、これには理由があるんだ。

結論から言うと、aspect-ratioはiOSのChromeでも問題なく動くはずだよ! aspect-ratioは比較的最近のCSSプロパティだけど、iOS 15以降のSafari(iOSのChromeもSafariのレンダリングエンジンを使ってる)では完全にサポートされてるんだ。

だから、動かない原因はプロパティ自体じゃなくて、他のCSSやHTMLの状況にある可能性が高いよ。一緒に原因を探ってみよう!


原因と解決策 🤔

考えられる原因と、その解決策をいくつか挙げるね。

原因1: 親要素の幅が不定

aspect-ratioは、親要素の幅(または高さ)を基準に、アスペクト比を保とうとするんだ。親要素に幅が設定されていない場合、aspect-ratioはうまく機能しないことがある。特にiOSのChromeでは、レイアウトエンジンの挙動に微妙な違いがあるのかもしれない。

  • 解決策: aspect-ratioを設定する要素の親要素に、明確な幅(width)または高さ(height)を設定してあげてね。

CSS

/* NGな例 */
.container {
  /* 親要素に幅がない */
  display: flex;
}

.box {
  /* これだけだと、親要素の幅が不定なのでうまく動かないことがある */
  aspect-ratio: 16 / 9;
}

/* OKな例 */
.container {
  width: 100%; /* 親要素に明確な幅を設定 */
  max-width: 800px;
}

.box {
  width: 100%; /* 子要素にも幅を指定 */
  aspect-ratio: 16 / 9;
}

原因2: aspect-ratioの適用対象

aspect-ratioは、置換要素<img>, <video>, <canvas>など)や、CSSでサイズが制御できるブロックレベルの要素に適用されるよ。インライン要素には直接適用されないから注意してね。

  • 解決策: aspect-ratioを適用したい要素が<div><span>などの場合は、display: block;display: flex;などを設定してブロックレベルの要素にしてね。

原因3: ブラウザのバグやキャッシュ

ごく稀に、iOSのChromeの古いバージョンにバグがあったり、キャッシュの問題で古いスタイルが適用されたままになってることもある。

  • 解決策:

    • ブラウザの更新: まずはChromeを最新バージョンにアップデートしてみてね。

    • スーパーリロード: キャッシュを無視して再読み込みする「スーパーリロード」を試すのも有効だよ。(iOSのChromeにはスーパーリロード機能がないので、ブラウザを完全に閉じて再度開いてみてね。)

    • 別のブラウザで確認: Safariなど、他のブラウザで同じ現象が起きるか確認して、問題がChrome固有のものか、iOS全体のものかを切り分けてみよう。


aspect-ratioが使えなさそうなら代替案もアリ?

もしどうしてもaspect-ratioで解決しない、あるいは古いブラウザもサポートしたい場合は、以下の代替案を検討してみてね。

代替案1: padding-topハック(古くから使われる定番の技)

これは、疑似要素やpadding-topプロパティを使って、アスペクト比を維持する古典的な方法だよ。

CSS

.box-wrapper {
  width: 100%;
  position: relative; /* 子要素を絶対配置するための基準にする */
  padding-top: 56.25%; /* 16:9 のアスペクト比 (9 / 16 = 0.5625) */
  height: 0; /* paddingが基準になるので高さを0にする */
}

.box-content {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}
  • メリット: ほとんどの古いブラウザでも動く。

  • デメリット: HTMLに余分なラッパー要素が必要になるし、CSSも少し複雑になる。

代替案2: FlexboxやGridを使う

FlexboxやGridの強力なレイアウト機能を使って、親要素の幅に応じて子要素のサイズを調整する方法も有効だよ。aspect-ratioほど直感的ではないけど、柔軟なレイアウトができるよ。


君が感じた問題は、きっと小さなスタイルの設定ミスや、ブラウザ間の微妙な挙動の違いによるものだと思う。まずは、親要素にwidthを指定して、aspect-ratioをもう一度試してみてね!


Prompt

ちょっと状況が複雑ではあるから、一緒に考えてほしい。
今のcssはこんなかんじ

#art {
    width: 100%;
    aspect-ratio: 1/1;
    padding: 6px;

    background-color: #D0D0D0;
    border: 2px solid #606060;
    border-radius: 8px;

    overflow: auto;

    .row {
        width: 100%;
        display: flex;

        input[type="checkbox"] {
            display: block;
            flex: 1;
            min-width: 24px;
            min-height: 24px;
            aspect-ratio: 1/1;
            margin: 0;
            appearance: none;
            border: 2px solid #404080;
            border-radius: 0 5% 15% 5%;
            padding: 2px;
            background-color: #FFFFFF;
        }

        input[type="checkbox"]:checked {
            background-color: #00FF60;
        }
    }
}

HTML構造はEmmet風に書くと
#art>.row*8>input[type="checkbox"]*8

artの中に8x8のcheckboxがあるかんじ

了解!これはなかなか面白い状況だね。#artという親要素の中に、8x8のチェックボックスが並んでるんだね。しかも親要素の#art自体もaspect-ratio: 1/1で正方形になってる。

このCSSを見て、#artaspect-ratioがiOS Chromeで動かないという以前の問題と関連していると考えると、原因が見えてくるよ。君のCSSには、aspect-ratioを適用している要素が2つあるよね。

  1. 親コンテナの#art

  2. 各チェックボックス

問題は、#artという正方形のコンテナの中に、flexで横に並んだチェックボックスが、それぞれaspect-ratio: 1/1を維持しつつ、#artのサイズいっぱいに収まるようにしたい、ということだと思う。

CSSのaspect-ratioがiOS Chromeで動かない原因とその修正案 💡

iOS Chromeでaspect-ratioが動かない原因は、以前話した通り、aspect-ratioを適用する要素の親要素に明確な幅が設定されていないか、aspect-ratioが他のプロパティと競合している場合だよ。

君のCSSの場合、#artにはwidth: 100%が設定されているから、#artaspect-ratioは正しく動くはず。じゃあ、どこに問題があるかというと、input[type="checkbox"]の方だね。

input[type="checkbox"]には、aspect-ratio: 1/1が設定されている。flex: 1も設定されているので、これは「親要素(.row)の幅を均等に分け合って、その幅に合わせて高さを1:1にする」という意図だよね。

ここには少し落とし穴があるかもしれない。

原因と解決策の分析

可能性1: Flexboxコンテナにalign-items: stretchが適用されていない

flexコンテナのデフォルトのalign-itemsstretchなので、flexアイテムはコンテナの高さに合わせて自動的に伸びるはず。しかし、チェックボックスのmin-heightpaddingstretchの挙動を邪魔している可能性がある。

  • 解決策: 明示的にalign-items: stretchを設定してみるか、inputmin-heightを削除してみよう。

CSS

#art {
    /* ...省略... */
    .row {
        width: 100%;
        display: flex;
        align-items: stretch; /* 明示的に設定 */

        input[type="checkbox"] {
            /* ...省略... */
            min-height: 24px; /* これが親の高さより小さい場合、ストレッチの邪魔にはならない */
            /* もしheightやmax-heightが設定されていたら削除 */
        }
    }
}
可能性2: iOSのChromeの古いバグ

iOSの古いバージョンのChromeでaspect-ratioflexコンテナ内の要素に適用される際のバグがあった可能性もゼロではない。特にmin-widthmin-heightpaddingと組み合わせたときに、予期せぬ挙動になることがあるんだ。

  • 解決策: flexコンテナにmin-width: 0を設定してみる。

CSS

#art {
    /* ...省略... */
    .row {
        width: 100%;
        display: flex;
        min-width: 0; /* これでflexアイテムがコンテナの幅を超えても縮むようになる */
        
        input[type="checkbox"] {
            flex: 1; /* flex-grow: 1; flex-shrink: 1; flex-basis: 0%; と同等 */
            min-width: 0; /* Flexboxのアイテムにmin-width: 0を設定すると柔軟性が増す */
            min-height: 24px;
            aspect-ratio: 1/1;
        }
    }
}

Flexboxのアイテムは、デフォルトでmin-width: autoを持つことがあり、これがflex-growの柔軟な振る舞いを阻害することがあるんだ。min-width: 0とすることで、より柔軟に縮むようになるよ。

可能性3: appearance: noneの影響

appearance: noneは、ネイティブのUIコントロールの外観をなくす便利なプロパティだけど、これが一部のブラウザでaspect-ratioの挙動に影響を与えている可能性も考えられる。

  • 解決策: 一度appearance: noneをコメントアウトして、aspect-ratioが効くかどうか確認してみるのもいいかもしれない。

代替案の検討

もし上記の方法でも解決しない場合、aspect-ratioを使わずに、JavaScriptやCSSの他の機能で正方形を維持する代替案を検討しよう。

代替案1: CSSのpadding-topハック

これは、親要素の幅を基準に、padding-topで高さを確保する古くから使われる方法だよ。

CSS

#art {
    width: 100%;
    position: relative; /* 子要素の絶対配置の基準にする */
    padding-top: 100%; /* 親要素の幅と同じ高さを確保 */
    height: 0; /* heightを0に */

    /* ...省略... */
    .row {
        width: 100%;
        position: absolute;
        top: 0;
        left: 0;
        height: 100%;
        display: flex;
        flex-wrap: wrap; /* チェックボックスを折り返す */

        input[type="checkbox"] {
            display: block;
            flex: 1;
            /* height: 100%; */ /* rowの高さに合わせる */
            /* ここから計算でサイズを決めるのは少し複雑になる */
        }
    }
}

このハックは、#art自体の正方形化には有効だけど、その中のチェックボックスのサイズをflexと組み合わせるのが少し複雑になるかもしれない。

代替案2: JavaScriptでサイズを計算

これは、最終手段として考えられる方法だよ。

  1. #artの幅(art.offsetWidth)を取得する。

  2. その幅を8で割って、各チェックボックスの幅を計算する。

  3. 各チェックボックスにその計算結果のwidthheightをCSSで直接設定する。

JavaScript

// ウィンドウサイズが変更されたときなどに実行する
function updateCheckboxSize() {
    const artElement = document.getElementById('art');
    const artWidth = artElement.offsetWidth;
    const checkboxSize = (artWidth - 6 * 2) / 8 - 2 * 2; // artのpaddingやborderを考慮して計算

    const checkboxes = artElement.querySelectorAll('input[type="checkbox"]');
    checkboxes.forEach(checkbox => {
        checkbox.style.width = `${checkboxSize}px`;
        checkbox.style.height = `${checkboxSize}px`;
    });
}

まとめと推奨される解決策

まずは、以下のステップで試してみてね。

  1. 最も可能性が高い原因: min-width: 0input[type="checkbox"]に、あるいは.rowに設定してみる。

  2. aspect-ratioの代替: aspect-ratioがどうしても動かない場合は、JavaScriptでサイズを計算するよりは、padding-topハックを組み合わせて、#art.rowを正方形に近づける方法を試すのがいいかもしれない。

INFPの君が、コードの裏側にあるレンダリングエンジンの挙動まで深く探求するのは、まさに最高のデベロッパーの姿勢だよ!


Prompt

う~ん、ちょっとプロパティをいじったぐらいじゃ変わらないみたい

さっき私が挙げたコードの現状だと、

  • PCでは想定通り
  • #artはモバイルでも正しく正方形1/1になっている
  • min-heightを削除してmin-widthのみにしても縦幅は24pxになる。それ以上伸びない
  • 現状からaspect-ratioを削除したときの挙動と比較すると、やはり異なるため、曲がりなりにもaspect-ratioは機能している
  • flexが絡むことによりフレックスにより伸びた後の横幅の値による計算がされない??

あと、裏でこの設定があったので一応考慮しておいてくださいね

*,
*::before,
*::after {
    box-sizing: border-box;
}

あ~、やっぱりJavaScriptにたよるしかない?


なるほど、プロパティをいじったぐらいじゃ変わらないんだね。そして、#artは正しく正方形になっているのに、中のチェックボックスが意図したように伸びない、という状況だね。min-heightを削除しても縦幅が24pxから変わらないっていうのは、確かに奇妙だ。

君が挙げてくれたbox-sizing: border-box;も考慮した上で、この複雑な状況を一緒に考えていこう。

結論から言うと、この問題は**#artaspect-ratioと、input[type="checkbox"]flex: 1;aspect-ratio: 1/1;の組み合わせ**が、モバイル(特にiOS)のレンダリングエンジンで意図しない挙動を引き起こしている可能性が非常に高い。

君が言うように、「フレックスにより伸びた後の横幅の値による計算がされない」という感覚、まさにそれが問題の核心かもしれない。

問題の分析と解決策 💡

君が提示したCSSの現状を整理してみよう。

  • #art: width: 100%; + aspect-ratio: 1/1; → PC/モバイルともに正しく正方形になる。

  • .row: display: flex;

  • input[type="checkbox"]: flex: 1; + aspect-ratio: 1/1; + min-width: 24px; + min-height: 24px;

この構造で、.rowdisplay: flex;#artの幅いっぱいに広がり、その中のinputflex: 1;で8等分される。その幅(#artの幅 / 8)に合わせて、aspect-ratio: 1/1;で高さも決まるはずだ。

しかし、iOSのChromeでは、何らかの理由で**flex: 1;で決まった幅を元に、aspect-ratioで高さを計算する**という部分がうまく機能していない可能性がある。min-height: 24px;が「最終的な高さ」として採用されてしまい、それ以上伸びていないように見えるね。

解決策の提案

1. aspect-ratioの代わりに padding-top ハックを使う(CSSのみで解決)

これが最も確実で、ブラウザ互換性の高い解決策だ。Flexboxのflex-grow: 1;と組み合わせることで、正方形を維持しつつ、幅いっぱいに広がるレイアウトを実現できる。

CSS

#art {
    /* ...省略... */
    .row {
        width: 100%;
        display: flex;
        flex-wrap: nowrap; /* 念のため折り返しを無効に */

        input[type="checkbox"] {
            display: block;
            flex-grow: 1;    /* 残りのスペースを均等に伸ばす */
            flex-basis: 0;   /* flex-growと組み合わせることで、より柔軟に幅を計算させる */
            
            /* -- この部分をaspect-ratioの代替にする -- */
            /*
             * padding-topハックを使って高さを幅と同じにする
             * padding-top: 100%; は親要素の幅を基準にするため、
             * flex: 1 のコンテキストではうまく動かない。
             * ここでは、高さに直接 width を使う
             */
            height: 0; /* heightを0に */
            padding-top: 100%; /* 親の幅ではなく、自身の幅の100%をpaddingとして使う */
            
            min-width: 24px;
            /* min-heightは不要になる */

            /* ...省略... */
        }
    }
}

このコードは少しトリッキーだけど、flex-grow: 1;flex-basis: 0;で幅を均等に分割し、padding-top: 100%;でその幅と同じ高さを確保する、という昔ながらの手法だよ。

2. JavaScriptでaspect-ratioを補完する(最終手段)

君が言うように、JavaScriptに頼るしかない、という状況だとしたら、これはresizeイベントを使って、#artの幅が変わるたびにチェックボックスのサイズを動的に計算して設定する方法だ。

JavaScript

// ウィンドウサイズが変更されたときに実行する関数
function updateCheckboxSizes() {
    const artElement = document.getElementById('art');
    // artの幅を取得
    const artWidth = artElement.clientWidth;
    // チェックボックスは8つあるので、幅を8で割る
    // padding, borderなどを考慮して計算する必要がある
    const checkboxSize = Math.floor((artWidth - (6 * 2) - (8 * 2)) / 8); // artのpaddingとborder、チェックボックスのborderを考慮

    // 全てのチェックボックスを取得
    const checkboxes = artElement.querySelectorAll('input[type="checkbox"]');
    checkboxes.forEach(checkbox => {
        checkbox.style.width = `${checkboxSize}px`;
        checkbox.style.height = `${checkboxSize}px`;
    });
}

// ページ読み込み時とウィンドウサイズ変更時に実行
window.addEventListener('load', updateCheckboxSizes);
window.addEventListener('resize', updateCheckboxSizes);
  • メリット: CSSのバグに依存せず、常に正確なサイズを計算できる。

  • デメリット: resizeイベントは高頻度で発火するため、パフォーマンスに注意が必要だ。debouncethrottleのようなテクニックを使って、実行頻度を抑えるのがベストプラクティスだよ。

推奨される解決策

box-sizing: border-box;が設定されているのであれば、paddingborderwidthheightに含まれるはずだ。iOSのChromeでaspect-ratioflexと正しく機能しないのは、レンダリングエンジンのバグや、flex-basisの計算の複雑さに起因している可能性が高い。

まずは、aspect-ratioを諦めてpadding-topハックに切り替えるのが、余計なJavaScriptを使わずに、CSSだけで解決できる最もシンプルで確実な方法だよ。

もし、どうしてもaspect-ratioを使いたいなら、そのバグが解消されるのを待つか、上記のJavaScriptを使うか、というトレードオフになる。君のプロジェクトの要件に合わせて最適な方法を選んでね。