0

I have bumped into this, while solving another issue.
I have the following, basic, layout:

+-----+-----------------+
|     |                 |
|  c  |c   +------+     |
|  o  |o   | item |     |
|  l  |l   |      |     |
|     |    +------+     |
|  1  |2                |
+-----------------------+

col 1 and col 2 are created via CSS Grid. Now, I am striving to center item (both horizontally and vertically) inside the col 2.

#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 {
  background: #7FFF00;
  
  width: 9%;
  padding-top: 9%;
  border-radius: 50%;
  
  margin: auto;
}

.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>

Code above on JSFiddle

My code is working as I expect it to (item saves it's aspect ratio and being centered vertically and horizontally), when tested in Chrome 62.0 and Safari 11.0. Though when I've got to Firefox (56.0) - the aspect ratio is changed on window resizing. I have tried another centering technique - using grid (JSFiddle) (the result is the same Firefox won't preserve aspect ratio).

Now, commenting out (JSFiddle) the flex part from css, will make Firefox preserve aspect ratio, though item is not centered vertically anymore.

My questions are:

  1. Is this a known issue (bug) in Firefox, or something wrong with my code?
  2. What is the proper fix/workaround to center item vertically and horizontally, inside col 2, while preserving aspect ratio (preferably using flex)?
  • @LGSon The [question](https://stackoverflow.com/questions/46548987/a-grid-layout-with-responsive-squares) that is linked as being duplicated, does not tackle different browser behaviour/implementation of _'Percentage margins and paddings on grid items'_ explicitly (though the problem itself is similar to one here). So this question does not seem to be a duplicate, to me. Am I missing something? –  Oct 23 '17 at 07:43
  • 1
    You missed that it is a duplicate, as its answer solves your question, and it does that by tackle different browsers behavior by using percent on the pseudo element, which is not part of the Flexbox, hence doesn't suffer from it. – Asons Oct 23 '17 at 07:57
  • 1
    Do note, a duplicate does not mean both _questions_ are the same, it means an _answer_ in one solves both – Asons Oct 23 '17 at 08:10
  • JSFiddle from the @LGSon comment above (originally jsfiddle.net/67uz5j3p/9) was moved to [another fiddle](https://jsfiddle.net/mfo4qk9dv2ua5iksttbnqx64c/bo0xb5uo/3/) –  Apr 14 '20 at 07:06

1 Answers1

2

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 of 9%, but nothing else
  • the ::before pseudo-element will have a width of 100% and a padding-top of 100%, 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>
Terry
  • 63,248
  • 15
  • 96
  • 118
  • Is there a reason you have added `height: 0` to `#circle::before`. I haven't noticed any changes after removing it, so I'm wondering if it must be there at all? –  Oct 21 '17 at 07:55
  • 1
    @FilippW. That’s just a safeguard against content within the element, so you can safely remove it if you know you’re always declaring an empty content attribute. – Terry Oct 21 '17 at 08:46