Chrome / Safari がフレックス親の高さを 100% 埋めない 質問する

Chrome / Safari がフレックス親の高さを 100% 埋めない 質問する

特定の高さの垂直メニューを作成したいです。

各子は親の高さを埋め、テキストを中央揃えにする必要があります。

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

Div に.containerはランダムな数の子 ( .item) が含まれており、常に親の高さを満たす必要があります。これを実現するために、flexbox を使用しました。

テキストを中央揃えにしたリンクを作成するために、私は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>

ベストアンサー1

解決

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

パーセンテージの高さを取り除きます。テーブルプロパティを取り除きます。を取り除きますvertical-align。絶対配置を避けます。最初から最後までフレックスボックスに固執します。

display: flexフレックス アイテム ( ) に適用して.item、フレックス コンテナーにします。これにより、 が自動的に設定されalign-items: stretch、子 ( .item-inner) に親の高さ全体を拡張するように指示します。

重要: このメソッドが機能するには、フレックスアイテムから指定された高さを削除してください。子に高さが指定されている場合 (例)、親からの高さheight: 100%は無視されます。デフォルトで機能するには、子の高さが次のように計算される必要があります。align-items: stretchstretchauto (詳しい説明)。

これを試してください(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プロパティ

percentage 高さをパーセンテージで指定します。パーセンテージ
は、生成されたボックスの包含ブロックの高さを基準に計算されます。包含ブロックの高さが明示的に指定されておらず、この要素が絶対配置されていない場合、値は と計算されますauto

auto
高さは他のプロパティの値によって異なります。

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

コードでは、最上位のコンテナーの高さが定義されています。.container { height: 20em; }

3 レベル目のコンテナーには定義された高さがあります。.item-inner { height: 100%; }

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

.item-innerChromeに「をくださいheight: 100%」と伝えています。Chrome は親 ( .item) を参照して、「何の 100% ですか?」と応答します。何も表示されません(flex: 1そこにあるルールを無視します)。結果として、height: auto仕様に従って (コンテンツの高さ) が適用されます。

一方、Firefox では、親の flex の高さを子のパーセント高さの参照として受け入れるようになりました。IE11 と Edge も flex の高さを受け入れます。

また、Chromeは、(任意の数値が機能する)と組み合わせて使用​​​​すると、flex-grow適切な親参照として受け入れます(flex-basisautoしません) 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-heightおよびはmax-height受け入れられないことに注意してください。heightプロパティである必要があります。

詳細はこちら:CSSheightプロパティとパーセンテージ値の操作

2. CSS の相対位置と絶対位置

position: relative親とposition: absolute子の両方に適用します。

height: 100%およびを使用して子のサイズを変更するwidth: 100%か、オフセット プロパティtop: 0right: 0bottom: 0、を使用しますleft: 0

絶対配置では、親の高さを指定しなくてもパーセンテージの高さが機能します。

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

の周りに2つのコンテナが必要ですか?または、あるいは両方buttonを削除しないのはなぜですか?.item.item-innerbutton要素がフレックスコンテナとして機能しないことがある、それらはフレックス項目になることができます。または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. ネストされたフレックスコンテナ(推奨)

パーセンテージの高さを取り除きます。テーブルプロパティを取り除きます。を取り除きますvertical-align。絶対配置を避けます。最初から最後までフレックスボックスに固執します。

display: flexフレックス アイテム ( ) に適用して.item、フレックス コンテナーにします。これにより、 が自動的に設定されalign-items: stretch、子 ( .item-inner) に親の高さ全体を拡張するように指示します。

重要: このメソッドが機能するには、フレックスアイテムから指定された高さを削除してください。子に高さが指定されている場合 (例)、親からの高さheight: 100%は無視されます。デフォルトで機能するには、子の高さが次のように計算される必要があります。align-items: stretchstretchauto (詳しい説明)。

これを試してください(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

おすすめ記事