Search code examples
cssmobile-safari

How can I flex-stretch elements to full device height on mobile Safari?


I'm creating an accordion-like mobile webpage, trying to use the flex family of CSS properties. In short, I'm getting this:
Map section expanded on mobile browser but I want this: Map section expanded on desktop browser

The page consists solely of a set of <section>s, each of them having a clickable <header> and an <article>:

<body>
<section id="about">
    <header><a href="#about">About</a></header>
    <article>
        This will be about.
    </article>
</section>
<section id="map">
    <header><a href="#map">Map</a></header>
    <article>
        This will be a map.
    </article>
</section>

<section id="talk">
    <header><a href="#talk">Talk</a></header>
    <article>
        This will be talk
    </article>
</section>
</body>

Only one <article> should be displayed at any given time (the rest of them hidden), so:

<style>
...
section:not(:target) article {
    display: none;
}
</style>

So far, so good.
In order to use the full height of the device screen, that is, the height of the expanded section should be deviceheight - height of all the header elements. I've experimented with the flex properties, and I have no problem making it work as desired on my PC screen (using Chrome):

html {
    height: 100%
}

body {
    height: 100%;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    align-content: stretch;
    justify-content: flex-start;
    background: yellow;
}

section:target {
    flex: 1 1 auto;
}

section:not(:target) article {
    display: none;
}

section:not(:target) {
    height: auto;
    flex: 0 1 auto;
}

section {
    border: 1px solid black;
    background-color: green;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    align-content: stretch;
}

header {
    padding: 0.2em;
    background-image: linear-gradient(to bottom, black, rgba(100, 100, 100, 128));
    color: white;
    font-size: 12pt;
    font-weight: bold;
    font-family: "American Typewriter", serif;
    cursor: pointer;
    flex: 0 0 auto;
}

header a {
    color: white;
}

article {
    width: 100%;
    height: 100%;
    display: block;
    background-color: yellowgreen;
    flex: 1 0 auto;
}

This produces something like this, on a desktop PC with Chrome, when the Map section is expanded:
Map section expanded on desktop browser
The Map section takes all available space, just like I intended.

Now, with Mobile Safari, the expanded section does not use all available vertical space, but instead only enough to display its contents:
Map section expanded on mobile browser
As can be seen, the green Map section does not push the Talk header down to the bottom of the screen, instead the yellow body background color comes through.

I thought this would be rectified by specifying height=device-height, but that does not change anything:

<meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width, height=device-height"/>

I'd like the expanded section to use all available space, so that no yellow background color is visible. What am I missing in my CSS rules? I'd like to avoid resorting to JavaScript.

The full code can be fetched from https://gist.github.com/vramdal/4d764aef41bd39e8c96d


Solution

  • It seems Safari lags a little behind Chrome in supporting flex.

    This was simply a matter of using -webkit prefixes. With those in place, and removing height=device-height, I got exactly what I wanted.

    Here's the complete code:

    <!DOCTYPE html>
    <html>
    <head>
        <meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width"/>
        <meta charset="utf-8"/>
        <style type="text/css">
            html {
                height: 100%
            }
    
            body {
                height: 100%;
                margin: 0;
                padding: 0;
                display: flex;
                display: -webkit-flex;
                flex-direction: column;
                -webkit-flex-direction: column;
                align-items: stretch;
                -webkit-align-items: stretch;
                align-content: stretch;
                -webkit-align-content: stretch;
                justify-content: flex-start;
                -webkit-justify-content: flex-start;
                background: yellow;
            }
    
            section:target {
                flex: 1 1 auto;
                -webkit-flex: 1 1 auto;
            }
    
            section:not(:target) article {
                display: none;
            }
    
            section:not(:target) {
                height: auto;
                flex: 0 1 auto;
                -webkit-flex: 0 1 auto;
            }
    
            section {
                transition: flex 500ms ease-out;
                border: 1px solid black;
                background-color: green;
                display: flex;
                display: -webkit-flex;
                flex-direction: column;
                -webkit-flex-direction: column;
                align-items: stretch;
                -webkit-align-items: stretch;
                align-content: stretch;
                -webkit-align-content: stretch;
            }
    
            header {
                padding: 0.2em;
                background-image: linear-gradient(to bottom, black, rgba(100, 100, 100, 128));
                color: white;
                font-size: 12pt;
                font-weight: bold;
                font-family: "American Typewriter", serif;
                cursor: pointer;
                flex: 0 0 auto;
                -webkit-flex: 0 0 auto;
            }
    
            article {
                width: 100%;
                display: block;
                background-color: yellowgreen;
                flex: 1 0 auto;
                -webkit-flex: 1 0 auto;
            }
    
        </style>
    
    
    </head>
    <body>
    <section id="About">
        <header><a href="#About">About</a></header>
        <article>
            This will be about.
        </article>
    </section>
    <section id="map">
        <header><a href="#map">Map</a></header>
        <article>
            This will be a map.
        </article>
    </section>
    
    <section id="talk">
        <header><a href="#talk">Talk</a></header>
        <article>
            This will be talk
        </article>
    </section>
    
    </body>
    </html>