Flex display acts differently in Chrome and Safari

Background: In a tool that my team is working on, we are implementing header

which is programmatically output from the screen to an event listener. After writing the first implementation, it worked as expected, but only in Chrome.

I use display:flex

for #wrapper

as well as for items #content

.

<div id="wrapper">
  <header>Header Content</header>
   ...
      <section id="content">
        <div id="subcontent">
          <div id="tool">
            <div id="tool-container"></div>
            <svg id="svgTool" height="100%" width="100%" class="svgTool style-scope test-tool"></svg>
          </div>
        </div>
      </section>
   ...
</div>

      

some of the css:

...
#wrapper {
  width:100%;
  height:100vh;
  position:relative;
  display:flex;
  flex-direction:column;
  margin-left:auto;
  margin-right:auto;
  min-height:100%;
}

#content {
  display: flex;
  flex-direction: column;
  height: 100%;
}
...

      

Using some simple JavaScript, I customize the margin-top

element header

on click of a button (for this example).

Problem: While Chrome works as expected, Safari does not. I suspect it must have something to do with how the Safari website version interprets the elements with display: flex

. edit: or maybe it has something to do with how Safari works with vh

units?

In Chrome, the title will move up and down without affecting the element <svg>

. In Safari, adjusting the margin-top

title will cause the element to svg

create a space at the bottom of the screen equal to the change in header

margin-top

.

JSBin: This JSbin works identical to the current implementation of our tool. Open it in both Chrome and Safari to see the discrepancy.

http://jsbin.com/kaxiqig/edit?html,css,output

sidenote: firefox also works as expected

+3


source to share


1 answer


Instead of a real fix for what appears to be a bug, a simple workaround is to switch the height main

while you also switch the position of the header. Basically, it seems like Safari pulls main

up with the title when it goes up, so we'll just make it taller so that it expands again to the bottom of the screen.

The default height main

is calc(100vh - 80px)

, so we can just change the other half of the calc expression to get our new value. Exactly how you change it depends on how tall the header is in your application. Let's say that in this case, the title is usually 100px high. Since the title is translated as margin-top: -75px

, we can simply change our calc expression to calc(100vh - 25px)

for the new height.

While I originally suggested switching minimum-height

to main

, I noticed that we also get an ugly error when doing this where the minimum height change is not quite correct, even if we add a suitable transition property, leaving a white gap at the bottom of the screen for a second. This way we can just animate the actual one height

, which gives a nice smooth result.

In your CSS, I added this line:



main {
  transition: height .5s;
}

      

The new slide function becomes:

function slide() {
  if (document.querySelector('header').style.marginTop !== "-75px") {
    document.querySelector('header').style.transition = ".5s";
    document.querySelector('header').style.marginTop = "-75px";
    document.querySelector('main').style.height = "calc(100vh - 25px)";
  } else {
    document.querySelector('header').style.marginTop = "0";
    document.querySelector('main').style.height = "";
  }
}

      

If your title will change in height, you can instead switch the class to main

and revise the calc expression that uses the class with different media queries, or you can improve the function to find the height of the viewport first and then subtract the height of the post-transition title to find new height to apply to main

.

+1


source







All Articles