mrclean208 mrclean208 - 3 months ago 37
Sass (Sass) Question

Flexbox odd Behavior on iOS Mobile Browsers and OS X Safari

I am new to Flexbox because for my job I have to support back to IE8, so I have never really bothered with it until this project.

I am trying to figure out how to make a grid of "cards" have the same heights. These cards contain varying amounts of text inside of them, as well as an image. Since I am using AngularJS the complexity of JavaScript solutions to make this work is more than I have time for, thus I chose flexbox.

This is my relevant code for the card-wrapper (let me know if you need more):

.card-grid {
display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */
display: -moz-box; /* OLD - Firefox 19- (buggy but mostly works) */
display: -ms-flexbox; /* TWEENER - IE 10 */
display: -webkit-flex; /* NEW - Chrome */
display: flex; /* NEW, Spec - Opera 12.1, Firefox 20+ */

-ms-flex-wrap: wrap;
-webkit-flex-wrap: wrap;
flex-wrap: wrap;

...

.data-card {
height: auto;
//IE fallback
display: inline-block;
//Modern Browsers
display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */
display: -moz-box; /* OLD - Firefox 19- (buggy but mostly works) */
display: -ms-flexbox; /* TWEENER - IE 10 */
display: -webkit-flex; /* NEW - Chrome */
display: flex; /* NEW, Spec - Opera 12.1, Firefox 20+ */

...

}
}


And here is the relevant angular HTML for the above selectors:

<div class="card-group">
<ol class="cards card-grid invisible grid-row">
<li ng-repeat... class="data-card col xs-6 md-4 lg-3">
<a class="card" href="javascript:void(0)" ... >
...
</a>
</li>
</ol>
</div>


This is a screen shot of what is happening on Chrome and Safari in iOS:
The problem is it shows the first card, then for some reason or another, the second card is on the next line...
The issue I am facing is that, it's showing that first card "Axial" and then the next card "Motor Start" Should be right next to it.

Things I've tried:


  • Putting the wrap property on the item itself, instead of the wrapper, and that just looked awful

  • Defining the width, and using
    flex-grow
    but axial just goes to 100% width, and so the does very last (not depicted) card with nothing next to it.

  • Doing
    wrap-reverse
    but that just reversed the content and gave me the same problem.



Then I popped open Safari on OS X and got this:
Same issue as on iOS

It works on:


  • Chrome (Desktop)

  • Firefox (Desktop)

  • Internet Explorer Edge (Desktop)

  • Chrome (Andriod)



The only places it's not working are on Apple browsers (i.e. Chrome iOS, and Safari Mobile, etc.)

So I am thinking it's a
-webkit-
thing, but that's sort of obvious. I just don't know what I am doing wrong in my code. I am unable to post a fiddle of my working code, because the project is ongoing.

Is there a special property I should be using in for flexbox that I am not using? Thanks ahead of time for any help.

Answer

Okay, I got it licked. So for any of you Googlers out there, the way I fixed this is by changing the CSS to:

.card-grid {
  display: flex;
  display: -webkit-flex;
  flex-wrap: wrap;
  -webkit-flex-wrap: wrap;
  -ms-flex-wrap: wrap;

  .data-card {
    /**
     * Height AUTO is important, because adding flex to the child makes it vertically 
     * stretch by default. So that means height: 100% won't work.
     */
    height: auto;
    //IE fallback
    display: inline-block;
    //Modern Browsers
    display: flex;
    display: -webkit-flex;

    ...

    /**
     * For some unknown reason, it still didn't work until I subracted 1% from
     * the width of each breakpoint I was using.
     */
    @media screen and (min-width: map_get($grid-breakpoints, 'lg')) {
      width: percentage((3 / 12)) - 1%;
    }

    @media screen and (min-width: map_get($grid-breakpoints, 'md')) {
      width: percentage((4 / 12)) - 1%;
    }

    @media screen and (max-width: map_get($grid-breakpoints, 'sm')) {
      width: percentage((6 / 12)) - 1%;
    }
  }
}

This solution still renders fine in Chrome, even with the 1% of the true width subracted. A few things that I discovered were:

  1. Simply putting flex on the parent (to have the children's heights align) was not enough. I read a really great walkthrough on this here.
  2. I was back to square one after I knew I had to keep flex on the parent and the immediate children. It wasn't until I set the widths of the children to 49% that it was fixed. I still don't know why this is, because it's consistent with no box-sizing: content-box instead of what I am using which is box-sizing: border-box. I have a star selector putting border-box on every element, but perhaps I need to manually specify it on the child?
  3. I didn't need all the extra vendor pre-fixes I had added, since in my case, I am using display: inline-block as a fallback when flexbox isn't available. Although, if I wanted to I could have used the below.

    @supports not (flex-wrap: wrap) {
      ...
    }
    

    Then put some code in there. Here's another post on CSS Tricks that talks a little about using flexbox and fallbacks. Although, a different use-case than mine, it was still helpful. This was a good visual reference I'm thinking I'll keep around.

Hope all this information was helpful to someone. I know it saved my bacon.

UPDATE: Adding box-sizing: border-box to the child elements doesn't have any effect. Looks like subracting 1% from the width is the way to go, unless there's something I don't know, which is more than possible.

UPDATE 2: Due to a suggestion from a friend, and this article, I changed the code a little, started using the flex property, with column classes on the HTML as a fallback. Re-included the vendor prefixes in the form of a mixin. I also figured out the reason I was having to subtract percentages was because I had a grid container above the parent that had negative margins and clearfixes. Once this was removed the below CSS worked:

.card-grid {
  @include displayFlex;
  @include flexWrap(wrap);

  .data-card {
    /**
     * Height AUTO is important, because adding flex to the child makes it vertically 
     * stretch by default. So that means height: 100% won't work.
     */
    height: auto;
    //IE fallback
    display: inline-block;
    @include flexboxDisplay;
    @include flex(0 0 auto);

  }
}
Comments