J'ai une liste d'éléments que j'essaie d'organiser dans une disposition horizontale déroulante avec flexbox.
Chaque élément du conteneur a une marge gauche et droite, mais la marge droite du dernier élément est réduite.
Existe-t-il un moyen d'arrêter cela ou une bonne solution de contournement?
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>
La dernière marge n'est pas effondrée. Il est ignoré.
La propriété overflow
s'applique uniquement au contenu . Elle ne s'applique pas au rembourrage ni aux marges.
Voici ce qu'il dit dans la spécification:
11.1.1 Débordement: la propriété
overflow
Cette propriété spécifie si le contenu d'un élément de conteneur de bloc est découpé lorsqu'il déborde de la boîte de l'élément.
Jetons maintenant un œil au CSS Box Model :
source: W3C
La propriété overflow
est limitée à la zone de zone de contenu. Si le contenu déborde de son conteneur, alors overflow
s'applique. Mais overflow
n'entre pas dans les zones de remplissage ou de marge (sauf, bien sûr, s'il y a plus de contenu qui suit).
Le problème avec le problème potentiel n ° 1 est qu'il semble s'effondrer en dehors d'un contexte de formatage de flex ou de grille. Par exemple, dans une disposition de bloc standard, la dernière marge ne semble pas se réduire. Il est donc possible que overflow
soit autorisé à couvrir les marges/rembourrages, indépendamment de ce qu'il indique dans la spécification.
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>
Par conséquent, le problème est peut-être plutôt lié à des éléments qui sont "trop contraints".
10.3.3 Éléments de niveau bloc non remplacés dans un flux normal
Les contraintes suivantes doivent tenir parmi les valeurs utilisées des autres propriétés:
margin-left
+border-left-width
+padding-left
+width
+padding-right
+border-right-width
+margin-right
= largeur du bloc conteneurSi
width
n'est pasauto
etborder-left-width
+padding-left
+width
+padding-right
+border-right-width
(plus l'un desmargin-left
oumargin-right
qui ne sont pasauto
) est plus grande que la largeur du bloc conteneur, puis toutes les valeursauto
pourmargin-left
oumargin-right
sont, pour les règles suivantes, traitées comme nulles.Si tous les éléments ci-dessus ont une valeur calculée autre que
auto
, les valeurs sont dites "sur-contraintes" et l'une des valeurs utilisées aura être différent de sa valeur calculée. Si la propriétédirection
du bloc conteneur a la valeurltr
, la valeur spécifiée demargin-right
est ignoré et la valeur est calculée de manière à rendre l'égalité vraie. Si la valeur dedirection
estrtl
, ceci arrive àmargin-left
au lieu(pas d'italique dans l'original)
Ainsi, selon le CSS Visual Formatting Model , les éléments peuvent être "sur-contraints" et, par conséquent, une marge droite est rejetée.
Au lieu de marge ou de remplissage, utilisez une bordure droite sur le dernier élément:
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>
Une autre solution utilise un pseudo-éléments au lieu des marges ou du remplissage.
Les pseudo-éléments d'un conteneur flexible sont rendus sous forme d'éléments flexibles. Le premier élément du conteneur est ::before
et le dernier élément est ::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>
Votre problème n'est pas la marge en soi. Il s'agit de la barre de défilement dimensionnant uniquement le contenu visible de l'élément.
Un hack pour le résoudre serait de créer un élément visible qui occupe la marge
Cette solution gère cela en utilisant un pseudo sur le dernier enfant
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>
Vous pouvez définir width
et overflow
sur le conteneur div
et définir display: inline-flex
plutôt que flex
sur le ul
, de sorte que la taille de la boîte flexible sera calculée en fonction des éléments à l'intérieur, et tout le rembourrage et la marge s'appliqueront sans aucun problème.
.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>