1. ホーム
  2. css

[解決済み】Chrome / Safariでフレックス親の高さが100%充填されない。

2022-04-19 22:06:55

質問

縦長のメニューを特定の高さで表示させたいのですが。

各子供は親の高さを満たし、テキストは中央揃えにすること。

子供の数はランダムなので、動的な値で作業する必要があります。

Div .container にはランダムな数の子要素 ( .item ) は、常に親の高さを満たす必要があります。これを実現するために、フレックスボックスを使用しました。

テキストが中央に配置されたリンクを作成するために、私は display: table-cell というテクニックがあります。しかし、テーブルディスプレイを使用すると、高さを100%にする必要があります。

私の問題は .item-inner { height: 100% } がwebkit(Chrome)で動作しない。

  1. この問題を解決する方法はありますか?
  2. あるいは、すべての .item は、親の高さを埋め、テキストを中央に縦書きで配置するのですか?

サンプルはこちら jsFiddle, FirefoxとChromeでご覧ください。

.container {
  height: 20em;
  display: flex;
  flex-direction: column;
  border: 5px solid black
}
.item {
  flex: 1;
  border-bottom: 1px solid white;
}
.item-inner {
  height: 100%;
  width: 100%;
  display: table;
}
a {
  background: orange;
  display: table-cell;
  vertical-align: middle;
}
<div class="container">
  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>

  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>

  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>
</div>

解決方法は?

解決方法

ネストされたフレックスコンテナを使用します。

パーセンテージの高さをなくす。テーブルのプロパティをなくす。を廃止する。 vertical-align . 絶対位置指定を避ける。 ずっとフレックスボックスで我慢してください。

適用 display: flex をフレックスアイテム( .item ) を作成し、フレックスコンテナにします。これにより、自動的に align-items: stretch であり、その子( .item-inner ) を親の高さいっぱいまで拡大する。

重要 このメソッドが動作するように、フレックスアイテムから指定された高さを削除してください。 子要素に高さが指定されている場合(例えば height: 100% を無視します。 align-items: stretch を親から受け取った。このとき stretch を使用するには、子供の高さが auto (詳しい説明 ).

これを試してみてください(HTMLに変更はありません)。

.container {
    display: flex;
    flex-direction: column;
    height: 20em;
    border: 5px solid black
}

.item {
    display: flex;                      /* new; nested flex container */
    flex: 1;
    border-bottom: 1px solid white;
}

.item-inner {
    display: flex;                      /* new; nested flex container */
    flex: 1;                            /* new */

    /* height: 100%;                    <-- remove; unnecessary */
    /* width: 100%;                     <-- remove; unnecessary */
    /* display: table;                  <-- remove; unnecessary */  
}

a {
    display: flex;                      /* new; nested flex container */
    flex: 1;                            /* new */
    align-items: center;                /* new; vertically center text */
    background: orange;

    /* display: table-cell;             <-- remove; unnecessary */
    /* vertical-align: middle;          <-- remove; unnecessary */
}
<div class="container">
  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>

  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>

  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>
</div>

jsFiddleデモ


説明

<ブロッククオート

私の問題点は .item-inner { height: 100% } は動作しません。 webkit (Chrome)です。

従来の仕様の実装に準拠しない方法で高さのパーセンテージを使用しているため、動作しません。

10.5 コンテンツの高さ height プロパティ

パーセンテージ

高さをパーセントで指定します。パーセンテージは、生成されたボックスの高さを基準に計算されます。 を含むブロック。含むブロックの高さがない場合 明示的に指定され、この要素が絶対位置でない場合、この値は次のように計算されます。 auto .

オート

高さは、他のプロパティの値に依存します。

つまり、インフローの子で高さのパーセンテージが機能するためには、親である は、高さが設定されています。

あなたのコードでは、トップレベルのコンテナには高さが定義されています。 .container { height: 20em; }

第3レベルのコンテナには、高さが定義されています。 .item-inner { height: 100%; }

しかし、その間にある第2レベルのコンテナ-は .item - はありません。 は高さが定義されています。Webkit はこれをミッシングリンクとみなします。

.item-inner はChromeに伝えています。 よこせ height: 100% . Chrome は親を探します ( .item ) を参照し、応答する。 100%って何?何も見えません (を無視する)。 flex: 1 ルールがあります)。その結果、それは height: auto (コンテンツの高さ)の仕様に従ったものです。

一方、Firefoxでは、親のフレックスハイトを子のパーセンテージハイトの参照先として受け入れるようになりました。IE11とEdgeも同様にフレックスハイトを受け付けます。

また、Chromeは flex-grow を適切な親参照として使用することができます。 と一緒に使用された場合 flex-basis (任意の数値が使えます ( auto は不可)を含む flex-basis: 0 ). しかし、この記事を書いている時点では、この解決策はSafariでは失敗します。

#outer {
  display: flex;
  flex-direction: column;
  height: 300px;
  background-color: white;
  border: 1px solid red;
}
#middle {
  flex-grow: 1;
  flex-basis: 1px;
  background-color: yellow;
}
#inner {
  height: 100%;
  background-color: lightgreen;
}
<div id="outer">
  <div id="middle">
    <div id="inner">
      INNER
    </div>
  </div>
</div>


4つのソリューション

1. すべての親要素に高さを指定する

信頼できるクロスブラウザの解決策は、すべての親要素に高さを指定することです。これにより、Webkit ベースのブラウザが仕様違反と見なすリンク切れを防ぐことができます。

なお min-heightmax-height は受け付けられません。必ず height プロパティを使用します。

詳しくはこちら CSSを使った作業 height プロパティとパーセント値

2. CSS 相対配置と絶対配置

適用 position: relative を親に、そして position: absolute を子へ送る。

で子のサイズを指定します。 height: 100%width: 100% または、オフセットプロパティを使用します。 top: 0 , right: 0 , bottom: 0 , left: 0 .

絶対位置決めでは、親に高さの指定がなくても高さの割合が機能します。

3. 不要なHTMLコンテナを削除する(推奨)

の周りに2つのコンテナが必要なのでしょうか? button ? を削除してはどうでしょう。 .item または .item-inner それとも両方?しかし button 要素はフレックスコンテナとして失敗することがあります。 フレックスアイテムになる可能性があります。を作ることを検討します。 button の子である .container または .item というように、不要なマークアップを削除しています。

以下はその例です。

.container {
    height: 20em;
    display: flex;
    flex-direction: column;
    border: 5px solid black
}

a {
    flex: 1;
    background: orange;
    border-bottom: 1px solid white;
    display: flex;                   /* nested flex container (for aligning text) */
    align-items: center;             /* center text vertically */
    justify-content: center;         /* center text horizontally */
}
<div class="container">
    <a>Button</a>
    <a>Button</a>
    <a>Button</a>
</div>

4. ネストされたFlexコンテナ(推奨)

パーセンテージの高さをなくす。テーブルプロパティを廃止する。以下のものを削除します。 vertical-align . 絶対位置指定を避ける。 ずっとフレックスボックスで我慢してください。

適用 display: flex をフレックスアイテム( .item ) を作成し、フレックスコンテナにします。これにより、自動的に align-items: stretch であり、その子( .item-inner ) を親の高さいっぱいまで拡大する。

重要 このメソッドが動作するように、フレックスアイテムから指定された高さを削除してください。 子要素に高さが指定されている場合(例えば height: 100% を無視します。 align-items: stretch を親から受け取る。このとき stretch を使用するには、子供の高さが auto (詳しい説明 ).

これを試してみてください(HTMLに変更はありません)。

.container {
    display: flex;
    flex-direction: column;
    height: 20em;
    border: 5px solid black
}

.item {
    display: flex;                      /* new; nested flex container */
    flex: 1;
    border-bottom: 1px solid white;
}

.item-inner {
    display: flex;                      /* new; nested flex container */
    flex: 1;                            /* new */

    /* height: 100%;                    <-- remove; unnecessary */
    /* width: 100%;                     <-- remove; unnecessary */
    /* display: table;                  <-- remove; unnecessary */  
}

a {
    display: flex;                      /* new; nested flex container */
    flex: 1;                            /* new */
    align-items: center;                /* new; vertically center text */
    background: orange;

    /* display: table-cell;             <-- remove; unnecessary */
    /* vertical-align: middle;          <-- remove; unnecessary */
}
<div class="container">
  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>

  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>

  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>
</div>

jsFiddle