Why doesn't percentage padding / margin work on flex items in Firefox and Edge?
2018 Update
The flexbox specification has been updated.
4.2. Flex Item Margins and Paddings
Percentage margins and paddings on flex items, like those on block
boxes, are resolved against the inline size of their containing block,
e.g. left/right/top/bottom percentages all resolve against their
containing block’s width in horizontal writing modes.
Original Answer - applies to FF and Edge versions released before 2018
From the flexbox specification:
Authors should avoid using percentages in paddings or margins on flex items entirely, as they will get different behavior in different browsers.
Here's some more:
4.2. Flex Item Margins and Paddings
Percentage margins and paddings on flex items can be resolved against either:
- their own axis (left/right percentages resolve against width, top/bottom resolve against height), or,
- the inline axis (left/right/top/bottom percentages all resolve against width)
A User Agent must choose one of these two behaviors.
Note: This variance sucks, but it accurately captures the current state of the world (no consensus among implementations, and no consensus within the CSSWG). It is the CSSWG’s intention that browsers will converge on one of the behaviors, at which time the spec will be amended.
Flex elements ignore percent padding in Firefox
See https://lists.w3.org/Archives/Public/www-style/2015Sep/0038.html
Grid/Flex Percentages
- The group tried to work through how vertical percentage margins
and paddings are defined.
- Note: Top and bottom margins in CSS have traditionally
resolved against the containing block width instead of its
height, which has some useful effects but is generally
surprising. Existing layout modes must of course continue
to do so.- Previous group resolution had been for option 2 (below), but
Google felt they had new information regarding abspos
behavior that merited reconsideration.- The discussion came down to three potential solutions:
- Option 1: Always resolve percents against the width.
- Option 2: Grid and flex resolve against height, and
abspos items always resolve against the width.- Option 3: Grid and flex, including their abspos items,
resolve against the height. Abspos elsewhere
continue to resolve against the width.- In a straw poll the group was pretty evenly divided between
options 1 and 3.- Microsoft would object to option 1 and Google to option 3,
so the discussion reached an impasse and will be continued
privately during the F2F in hopes of reaching a conclusion.
See https://lists.w3.org/Archives/Public/www-style/2015Sep/0113.html,
Flexbox % Follow-Up
- [...] there was still no conclusion.
The current Flexbox spec warns about this:
Percentage margins and paddings on flex items can be resolved
against either:
- their own axis (left/right percentages resolve against width, top/bottom resolve against height)
- the inline axis (left/right/top/bottom percentages all resolve against width)
A User Agent must choose one of these two behaviors.
Note: This variance sucks, but it accurately captures the current
state of the world (no consensus among implementations, and no
consensus within the CSSWG). It is the CSSWG’s intention that browsers
will converge on one of the behaviors, at which time the spec will be
amended to require that.
Authors should avoid using percentages in paddings or margins on flex items entirely, as they will get different behavior in
different browsers.
However, more recently the CSS WG resolved (with some controversy):
Both flexbox and grid items top and bottom margin and padding percent resolves against the available inline direction.
See the updated editor's draft.
Percentage padding / margin on grid item ignored in Firefox
I found a solution:
I had to add a wrapper to the cell with a 'width: 100%' rule and it finally works on Firefox 52!
#grid{ display: grid; grid-gap: 8px; grid-template-columns: 100px 100px;}.cell{ width: 100%;}.inner{ background-color: red; padding-bottom: 50%;}
<div id="grid"> <div class="cell"> <div class="inner"></div> </div> <div class="cell"> <div class="inner"></div> </div> <div class="cell"> <div class="inner"></div> </div> <div class="cell"> <div class="inner"></div> </div></div>
Collapsing margin on Flexbox grid in Edge and Firefox
Margin using percent doesn't work cross browsers on flex items, so if your margin's is more related to the viewport, use viewport units (vh
or vw
), else you can combine px
with CSS calc()
(i.e. width: calc(33.333% - 20px)
) to match an equal gutter between the items.
Updated codepen
body { padding: 1.5%; background-color: #333;}
.container { //background-color: black; max-width: 964px; margin: 0 auto; display: -webkit-box; display: -moz-box; display: -ms-flexbox; display: -webkit-flex; display: flex; -webkit-box-flex-flow: row wrap; -moz-box-flex-flow: row wrap; -webkit-flex-flow: row wrap; -ms-flex-flow: row wrap; flex-flow: row wrap;}
.item { position: relative; width: 97%; color: #fff; background-color: #4286f4; padding: 0 20px 40px; margin: 1.5vh; box-sizing: border-box;}
@media only screen and (min-width:420px){ .item { width: 47%; }}
@media only screen and (min-width:768px){ .item { width: 30.333%; }}
a { position: absolute; bottom: 20px; left: 20px;}
<div class="container"> <div class="item item-1"> <h2>Item one</h2> <p>Pellentesque convallis turpis nec enim consequat, vitae pellentesque purus tempus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Duis blandit elit vel lacus gravida, nec imperdiet ligula ornare.</p> <a href="#">Read more</a> </div> <div class="item item-2"> <h2>Item two</h2> <p>Pellentesque convallis turpis nec enim consequat, vitae pellentesque purus tempus.</p> <a href="#">Read more</a> </div> <div class="item item-3"> <h2>Item three</h2> <p>Pellentesque convallis turpis nec enim consequat, vitae pellentesque purus tempus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae.</p> <a href="#">Read more</a> </div> <div class="item item-4"> <h2>Item four</h2> <p>Pellentesque convallis turpis nec enim consequat.</p> <a href="#">Read more</a> </div> <div class="item item-5"> <h2>Item five</h2> <p>Pellentesque convallis turpis nec enim consequat.</p> <a href="#">Read more</a> </div> <div class="item item-6"> <h2>Item six</h2> <p>Pellentesque convallis turpis nec enim consequat.</p> <a href="#">Read more</a> </div></div>
Firefox: Item inside flexbox container does not preserve aspect ratio
Browser behavior on percentage-based vertical margins/paddings in a nutshell
It is not a bug per se, but probably due to browser's different implementation how percentage-based vertical spacings (top and bottom margins/paddings) should be calculated in flex or grid layout contexts:
Percentage margins and paddings on grid items can be resolved against either:
- their own axis (left/right percentages resolve against width, top/bottom resolve against height), or,
- the inline axis (left/right/top/bottom percentages all resolve against width)
A User Agent must choose one of these two behaviors.
There is no consistency of choosing either resolution strategy: as you can see, Chrome and Safari will choose strategy #2, while IE, Edge, and Firefox will go for strategy #1 (which explains your bug). W3C also noted that:
Note: This variance sucks, but it accurately captures the current state of the world (no consensus among implementations, and no consensus within the CSSWG). It is the CSSWG’s intention that browsers will converge on one of the behaviors, at which time the spec will be amended to require that.
Authors should avoid using percentages in paddings or margins on grid items entirely, as they will get different behavior in different browsers.
The solution
What you can do is simply to define the circle itself as a pseudo-element. In this approach:
- the outer
#circle
element has a width of9%
, but nothing else - the
::before
pseudo-element will have a width of100%
and a padding-top of100%
, this will force it to a 1:1 aspect ratio as desired
Your updated CSS will look like this:
#circle {
width: 9%;
margin: auto;
}
#circle::before {
background: #7FFF00;
border-radius: 50%;
width: 100%;
height: 0;
padding-top: 100%;
content: '';
display: block;
}
See proof-of-concept below (or in this fiddle):
#content { display: grid; grid-template-columns: minmax(13rem, 15%) minmax(85%, 100%); position: absolute; top: 0; left: 0; right: 0; bottom: 0; width: 100%; height: 100%;}
#circle { width: 9%; margin: auto;}
#circle::before { background: #7FFF00; border-radius: 50%; width: 100%; height: 0; padding-top: 100%; content: ''; display: block;}
.menu { background: #D2691E; grid-row-start: 1; grid-row-end: 1;}
.circle-area { background: #191970; grid-row-start: 1; grid-row-end: 1; grid-column-start: auto; grid-column-end: span 2; display: flex; align-items: center; justify-content: center; width: 100%; height: 100%;}
<body> <div id='content'> <div class='menu'></div> <div class='circle-area'> <div id='circle'></div> </div> </div></body>
FlexBox - container width not expanding when using percent margin
As Michael Coker commented, Authors should avoid using percentages in paddings or margins on flex items entirely, as they will get different behavior in different browsers. (CSS Flexbox margins)
When using percent we often relate that to the viewport width, so with that in mind, viewport units vw
/vh
can be a good option, since it works similar (responsive).
Stack snippet made of your Codepen sample
.page { display: flex; /*border: 5px solid orange;*/}
.container { display: flex; border: 5px solid orange;}
.item_left { flex: 1; margin-right: 25vw;}
.item_right { display: flex; flex: 1;}
<div class="page"> <div class="container"> <div class="item_left">Left</div> <div class="item_right">Right</div> </div></div>
margin-top/bottom % not works in firefox
Please try this code.
It's due to display:flex
is not working well with %
in Firefox. So here you need to used display:block
to container1
div.
Use this code when you are using
%
in margin-bottom.
<div class="container1" style="display: block; flex-direction: column;">
<div class="div1" style="height: 100px; margin-bottom: 1%; background-color: green;"> This is div 1 </div>
<div class="div2" style="height: 100px; background-color: blue"> This is div 2 </div>
</div>
Please try this code when you are using PX not % in margin-bottom.
<div class="container1" style="display: flex; flex-direction: column;">
<div class="div1" style="height: 100px; margin-bottom: 10px; background-color: green;"> This is div 1 </div>
<div class="div2" style="height: 100px; background-color: blue"> This is div 2 </div>
</div>
Related Topics
Angular 8 Material Dialog Close Button With X Top Right
How to Divide a Page in Three Vertical Sections
How to Make Sure This Stays Centered, Even When Zoomed Out or In
Wrapping Text Inside Input Type="Text" Element Html/Css
How to Change Pressed Item Background Color in Ion-List on Ionic
Next.Js Background-Image CSS Property Cant Load the Image
Loading Images from External Folder to Component Angular 2
How to Allow Http Content Within an Iframe on a Https Site
How to Prevent Line-Break in a Column of a Table Cell (Not a Single Cell)
Create an Object for Google Chrome
Change Background Color of Iframe Issue
How to Prevent Desktop Browser (Chrome, Safari) from Zooming a Webpage
Displaying Comma Separated String in Angular 6
Placing Two Divs on Top of Each Other Without Using Position:Absolute