web-dev-qa-db-ja.com

CSS右マージンがオーバーフロースクロールのあるDiv内で機能しない

2つのdivを作成しようとしています。内側のdivは外側のdivより大きく、外側のdivはoverflow:scrollを持ち、内側のdivはmargin:25pxを持ちます。だから私はこれをします:

#outer {
    width: 200px;
    height: 100px;
    overflow: scroll;
}
#inner {
    width: 400px;
    height: 200px;
    margin: 25px;
}

...

<div id="outer">
    <div id="inner">

    </div>
</div>

内側のdivのマージンが予想どおり25pxである代わりに、3つの側面に25pxのマージンがありますが、右側にはありません。これは私の意見では非常に直感に反しています。

内側のdiv + 50pxを含めるのに十分な幅のある中央のdivを追加すると、正しく見えるようになりますが、これは面倒な回避策のようです。

JSFiddleの私の例を参照してください: http://jsfiddle.net/d3Nhu/16/

これは、すべての主要なブラウザで同じように発生します。この動作に正当な理由はありますか? CSS仕様によると、これは正しい動作ですか?

注:この例で期待するとおり、overflow:autoの代わりにoverflow:scrollを使用しても違いはありません。

[〜#〜] edit [〜#〜]:私は見ていませんこの動作の回避策について。 (私はすでにそれを見つけました。)特に CSS仕様 に記載されている場合、この動作の理由に関する洞察を探していますどこでも。

41
Sean the Bean

TL; DR:

マージンは、ラッパーを外側に拡張するのではなく、ラッパーから要素を移動するためのものです。

長い説明:

この動作は、ドキュメント内の任意の場所で水平widthに加えてmarginを指定することと一致しています。それを分解するために、overflowプロパティのないラッパーを特定し、marginがラッパー要素を展開しない次のスニペットを検討してください。

body {
    padding: 20px;
}
.outer {
    width: 400px;
    border: 1px solid black;
}
.inner {
    width: 400px;
    height: 40px;
    margin: 0 20px;
    background: grey;
}
<div class="outer">
    <div class="inner">
        
    </div>
</div>

ご覧のとおり、marginによってラッパーのサイズが拡張されず、要素がオーバーフローし続けただけです。この動作は、CSS 2.1仕様に記載されているビジュアルフォーマットモデルの詳細に記載されています。

" ビジュアルフォーマッティングモデルの詳細 "の " ブロックレベル、通常のフローで置き換えられていない要素 "セクションからの抜粋:

次の制約は、他のプロパティの使用された値の間で保持する必要があります。

'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' =包含ブロックの幅

[...]

上記のすべてに「自動」以外の計算値がある場合、値は「過剰制約」されていると呼ばれ、使用される値の1つがその計算値と異なる必要があります。包含ブロックの 'direction'プロパティの値が 'ltr'の場合、指定された 'margin-right'の値は無視され、等式がtrueになるように値が計算されます。 'direction'の値が 'rtl'の場合、これは代わりに 'margin-left'に発生します。

この抜粋は非常に密集しているので、簡単に言えば、borderpaddingの幅は無視してみましょう。どちらも0なので、widthmargin-left、およびmargin-right

これで、固定のwidthmargin-leftおよびmargin-rightの値が得られたため、値は「過剰制約」されています。この例では、方向がデフォルトでltrであるため、margin-rightは強制的に補正されます。

方向の影響を確認するために、ラッパー要素にdir="rtl"属性を追加してみましょう。

body {
    padding: 20px;
}
.outer {
    width: 400px;
    border: 1px solid black;
}
.inner {
    width: 400px;
    height: 40px;
    margin: 0 20px;
    background: grey;
}
<div class="outer" dir="rtl">
    <div class="inner">
        
    </div>
</div>

これで、要素は左側にオーバーフローしています。このdir="rtl"属性がoverflow: scrollの例に同じ影響を与えるかどうかを見てみましょう。

#outer {
    border: 1px solid #00F;
    width: 200px;
    height: 100px;
    overflow: scroll;
}
#inner {
    border: 1px solid #F0F;
    margin: 25px;
    width: 400px;
    height: 200px;
}
<div id="outer" dir="rtl">
    <div id="inner">
    
    </div>
</div>

はい、そうです。マージンが右側ではなく左側に欠けている。

しかし、なぜoverflow: scrollにマージンが含まれていないのですか?

主に仕様がそうすべきではないと言っているからです。 overflowプロパティのCSS 2仕様を見てみましょう。

視覚効果 」の「 オーバーフローとクリッピング 」セクションからの抜粋:

オーバーフローが発生するたびに、 'overflow'プロパティは、ボックスがパディングエッジに切り取られるかどうかを指定し、切り取られる場合は、切り取られたコンテンツにアクセスするためにスクロールメカニズムが提供されるかどうかを指定します。

「切り取られたコンテンツ」が具体的にどのように表示されているかをご覧ください。 「コンテンツ」の説明については、CSS 2仕様の次の図を参照してください。

ボックスモデル 」の「 ボックスサイズ 」セクションのグラフィック:

box model

ご覧のとおり、margincontentとは別のものです。ただし、この時点では、パディングとボーダーがスクロール領域に含まれていることに注意する必要があります。そのため、仕様に「コンテンツ」と記載されている場合、ボーダーボックスを参照している、または少なくとも、それが解釈されたようです。 。

display: inline-blockが機能する理由

基本的に、マージンはinline-block要素で異なる動作をします。マージンはブロックレベルではなくコンテンツレベルであり、「過剰制約」の概念がないためです。

54

追加 display:inline-block;#inner div

これを見てください フィドル

18
Keith

したがって、ここでの回答は実際には問題を解決しません! (機能しない理由については非常に詳細ですが)

解決策が必要でした。これは将来の読者のためのものです。 display:flex;と疑似:: after要素の組み合わせを使用して、divの存在を偽って必要なマージンを提供します。

.wrapper {
  display: flex;
  width: 400px;
  height: 100%;
  padding: 40px;
  background: lightGrey;
}

.lists_container {
  display: flex;
  flex-direction: row;
  justify-content: flex-start;
  overflow: auto;
  position: relative;
  background: grey;
  padding: 40px;
  margin: 40px;
  width: 100%;
}

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 250px;
  max-width: 500px;
  height: 100px;
  margin: 50px 0;
  padding: 20px;
  background: orange;
  margin-right: 30px;
}

.card.last::after {
  content: '';
  position: absolute;
  right: -100px;
  width: 40px;
  height: 100%;
  background: red;
}
<div class="wrapper">

  <div class="lists_container">

    <div class="card">
    </div>

    <div class="card">
    </div>

    <div class="card last">
    </div>

  </div>

</div>
4
Jquestions