フレックスボックスでスクロール可能な水平レイアウトに配置しようとしているアイテムのリストがあります。
コンテナ内の各アイテムには左と右のマージンがありますが、最後のアイテムの右マージンは縮小されています。
これを阻止する方法、または良い回避策はありますか?
ul {
list-style-type: none;
padding: 0;
margin: 0;
display: flex;
height: 300px;
overflow: auto;
width: 600px;
background: orange;
}
ul li {
background: blue;
color: #fff;
padding: 90px;
margin: 0 30px;
white-space: nowrap;
flex-basis: auto;
}
<div class="container">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
</div>
最後のマージンは崩れていません。無視されています。
overflow
プロパティはcontentにのみ適用されます。パディングやマージンには適用されません。
これは、仕様でそれが言うことです:
このプロパティは、要素のボックスをオーバーフローしたときに、ブロックコンテナー要素のコンテンツをクリップするかどうかを指定します。
CSSボックスモデル を見てみましょう。
ソース: W3C
overflow
プロパティは、コンテンツボックス領域に制限されています。コンテンツがコンテナからオーバーフローする場合、overflow
が適用されます。ただし、overflow
は、パディングやマージンの領域には入りません(もちろん、次のような内容がある場合を除きます)。
潜在的な問題#1の問題は、フレックスまたはグリッドのフォーマットコンテキストの範囲外にあるように見えることです。たとえば、標準のブロックレイアウトでは、最後のマージンが崩れているように見えません。ですから、仕様で何を言っているかに関係なく、overflow
はマージン/パディングをカバーすることが許可されています。
div {
height: 150px;
overflow: auto;
width: 600px;
background: orange;
white-space: nowrap;
}
span {
background: blue;
color: #fff;
padding: 50px;
margin: 0 30px;
display: inline-block;
}
<div class="container">
<span>Item 1</span>
<span>Item 2</span>
<span>Item 3</span>
<span>Item 4</span>
</div>
したがって、問題は代わりに「過剰制約」されている要素に関連している可能性があります。
次の制約は、他のプロパティの使用された値の間で保持する必要があります。
margin-left
+border-left-width
+padding-left
+width
+padding-right
+border-right-width
+margin-right
=包含ブロックの幅
width
がauto
ではなく、border-left-width
+padding-left
+width
+padding-right
+border-right-width
(およびmargin-left
またはmargin-right
のうち、auto
以外のいずれか)がより大きい場合包含ブロックの幅、およびmargin-left
またはmargin-right
のauto
値は、以下のルールではゼロとして扱われます。上記のすべてに
auto
以外の計算値がある場合、値は「過剰制約」されていると言われ、使用される値の1つは計算値とは異なります。包含ブロックのdirection
プロパティの値がltr
の場合、指定されたmargin-right
の値は無視され、等式が真になるように値が計算されます。 =direction
の値がrtl
の場合、代わりにmargin-left
が発生します(強調を追加)
したがって、 CSS Visual Formatting Model によると、要素は「過剰に制約されている」可能性があり、その結果、右マージンが破棄されます。
マージンやパディングの代わりに、最後の要素で右borderを使用します。
li:last-child {
border-right: 30px solid orange;
}
ul {
list-style-type: none;
padding: 0;
margin: 0;
display: flex;
height: 100px; /* adjusted for demo */
overflow: auto;
width: 600px;
background: orange;
}
ul li {
background: blue;
color: #fff;
padding: 90px;
margin: 0 30px;
white-space: nowrap;
flex-basis: auto;
}
li:last-child {
border-right: 30px solid orange;
}
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
別のソリューションでは、マージンやパディングの代わりにpseudo-elementsを使用します。
フレックスコンテナー上の疑似要素は、フレックスアイテムとしてレンダリングされます。コンテナの最初のアイテムは::before
で、最後のアイテムは::after
です。
ul::after {
content: "";
flex: 0 0 30px;
}
ul {
list-style-type: none;
padding: 0;
margin: 0;
display: flex;
height: 100px; /* adjusted for demo */
overflow: auto;
width: 600px;
background: orange;
}
ul li {
margin: 0 30px;
background: blue;
color: #fff;
padding: 90px;
white-space: nowrap;
flex-basis: auto;
}
ul::after {
content: "";
flex: 0 0 30px;
}
ul::before {
content: "";
flex: 0 0 30px;
}
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
あなたの問題自体はマージンではありません。これは、要素の表示可能なコンテンツのみの寸法を記入するスクロールバーです。
それを解決する1つのハックは、マージンを占める目に見える要素を作成することです
このソリューションは、最後の子の疑似を使用してこれを処理します
ul {
list-style-type: none;
padding: 0;
margin: 0;
display: flex;
height: 300px;
overflow: auto;
width: 600px;
background: orange;
}
ul li {
background: blue;
color: #fff;
padding: 90px;
margin: 0 30px;
white-space: nowrap;
flex-basis: auto;
position: relative;
}
li:last-child:after {
content: "";
width: 30px;
height: 1px;
position: absolute;
left: 100%;
top: 0px;
}
<div class"container">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
</div>
width
コンテナにはoverflow
とdiv
を設定でき、flex
ではなくul
ではなくdisplay: inline-flex
を設定できます。フレックスボックスのサイズが内部のアイテムに基づいて計算され、すべてのパディングとマージンが問題なく適用されるようにします。
.container {
width: 600px;
overflow: auto;
}
.container ul {
list-style: none;
padding: 0;
margin: 0;
display: inline-flex;
background: orange;
}
.container li {
padding: 60px;
margin: 0 30px;
white-space: nowrap;
background: blue;
color: #fff;
}
<div class="container">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
</div>