How can I fix flex 50% layout issue in Safari? - html

I have a small example of flex layout and I have some problem with Safari (Version 10.1.2 (12603.3.8))
So there is a content and inside of it there are four boxes, with the layout of 2x2. At the bottom there is a footer section.
I would like to place the boxes inside the content div to fill its height by 50% height and width. But in Safari it seems that it ignores the footer section and it places the boxes to align to the full page.
So here it what I want to achieve and it works in chrome:
And this is what it looks like in Safari:
I managed to try it in High Sierra where there is a newer Safari (Ver. 11) and it WORKS. So it must be a bug, but can we handle this in Safari 10? Thank you!
Here it is my code
HTML:
* {
box-sizing: border-box;
}
body, html {
width: 100%;
height: 100%;
margin: 0;
}
.wrapper {
display: flex;
flex-direction: column;
height: 100%;
}
.content {
display: flex;
flex-wrap: wrap;
width: 100%;
height: 100%;
background: white;
border: 1px solid tomato;
}
.box {
width: 50%;
height: 50%;
background: skyblue;
border: 1px solid black;
}
.footer {
opacity: 0.7;
flex: 0 0 auto;
height: 100px;
background: plum;
}
<div class="wrapper">
<div class="content">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
<div class="footer"></div>
</div>

Since content is a flex column item you don't use height to make it fill its parent, you use flex-grow.
Remove the height on content and add flex-grow: 1
.content {
flex-grow: 1; /* added */
display: flex;
flex-wrap: wrap;
background: white;
border: 1px solid tomato;
}
Also no need for width: 100%, it does that by default
Stack snippet
* {
box-sizing: border-box;
}
body, html {
width: 100%;
height: 100%;
margin: 0;
}
.wrapper {
display: flex;
flex-direction: column;
height: 100%;
}
.content {
flex-grow: 1;
display: flex;
flex-wrap: wrap;
background: white;
border: 1px solid tomato;
}
.box {
width: 50%;
background: skyblue;
border: 1px solid black;
}
.footer {
opacity: 0.7;
flex: 0 0 auto;
height: 100px;
background: plum;
}
<div class="wrapper">
<div class="content">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</div>
<div class="footer"></div>
</div>

Related

Make content scroll horizontally within nested flex containers with position sticky

I have the following layout (see snippet below).
This is the expected behavior.
The problem is:
Once the extra-large-content is simulated (by removing the comment on the extra-large-content CSS rule), it breaks the layout.
I would like the extra-large-content to scroll horizontally while staying inside column-3.
Is this even possible?
(the code is also available here https://codepen.io/Ploddy/pen/NWXOgMG?editors=1100)
body {
height: 1920px;
margin: 0;
}
.container {
display: flex;
border: 1px solid #ccc;
margin: 1rem;
}
.container > * {
border: 1px solid #ccc;
position: sticky;
top: 0;
align-self: flex-start;
flex-grow: 1;
margin: 1rem;
}
#column-3 {
height: 300px;
}
#extra-large-content {
background-color: lightgreen;
/*width: 3000px;*/
}
<div class="container">
<div>
column-1
</div>
<div class="container">
<div>
column-2
</div>
<div id="column-3">
column-3
<div id="extra-large-content">
extra-large content
</div>
</div>
</div>
</div>
This should work nicely for you. Essentially, I just specified width's on the .container elements. In theory, you could put overflow-x: scroll; on the .container, however, this would break your sticky positioning.
Edit ~ OP wants the extra-large content to scroll horizontally, not the entire column-3.
Set overflow-x: scroll; on the new parent wrapper of the div that has the 3000px static width.
body {
height: 1920px;
margin: 0;
}
.container:first-child {
max-width: 100%;
}
.container:first-child > div:first-child {
width: 40%;
}
.container:nth-child(2) {
width: 60%;
}
.container:nth-child(2) > div:first-child {
margin: 1em 0em 1em 1em;
}
.container {
display: flex;
border: 1px solid #ccc;
margin: 1rem;
}
.container>* {
border: 1px solid #ccc;
position: sticky;
top: 0;
align-self: flex-start;
flex-grow: 1;
margin: 1rem;
}
.wrapper {
display: flex;
flex-direction: column;
width: 40%;
}
#column-3 {
background-color: salmon;
}
#extra-large-content {
height: 300px;
width: 3000px;
background-color: lightgreen;
}
.xl-content-wrapper {
overflow-x: scroll;
}
<div class="container">
<div>column-1</div>
<div class="container">
<div>column-2</div>
<div class="wrapper">
<div id="column-3">column-3</div>
<div class="xl-content-wrapper">
<div id="extra-large-content">extra-large content</div>
</div>
</div>
</div>
</div>
The issue comes from using flexbox.
Switching to grid fixes the problem.
body {
height: 1920px;
margin: 0;
}
#primary-container {
position: relative;
display: flex;
margin: 1rem;
}
#secondary-container {
position: relative;
display: grid;
grid-template-columns: max-content 1fr;
align-items: start;
}
#column-3 {
display: grid;
grid-auto-rows: min-content;
height: 200px;
}
#content-wrapper {
overflow: auto;
}
#extra-large-content {
width: 3000px;
background-color: lightgreen;
}
.sticky {
position: sticky;
top: 0;
align-self: flex-start;
}
.border {
border: 1px solid #ccc;
}
<div id="primary-container" class="border">
<div class="sticky">
column1
</div>
<div id="secondary-container" class="border">
<div class="sticky">
column2
</div>
<div id="column-3" class="sticky border">
column3
<div id="content-wrapper">
<div id="extra-large-content">
extra-large content
</div>
</div>
...
</div>
</div>
</div>

Stretch columns in two columns layout with shared header using flexbox

I'm using flexbox to create a two-columns layout with a header row.
* {
box-sizing: border-box;
position: relative;
}
.container {
border: 2px solid gray;
display: flex;
flex-wrap: wrap;
height: 300px;
}
.header {
flex-basis: 100%;
border: 2px solid magenta;
height: 50px;
line-height: 50px;
text-align: center;
}
.column1 {
flex-basis: 150px;
/* height: calc(100% - 50px); */
border: 2px solid green;
}
.column2 {
/* height: calc(100% - 70px); */
flex: 1;
border: 2px solid orange;
}
<div class='container'>
<div class='header'>it's a header</div>
<div class='column1'>column 1</div>
<div class='column2'>column 2</div>
</div>
Feel free to see the full example here.
As you can see in the example there is a gap between columns and header. My aim is to stretch columns vertically to fill whole empty space in the container.
I can achieve it by setting height property like calc(100% - <header-height>). Is it the correct way?
I just tried to use "flex" style and set align-items: stretch to the container and align-self: stretch to columns but without success. Did I probably miss something trying to implement it this way?
I think specifying flex-direction as column is appropriate in this case.
The second row is itself a flex element with the flex-direction: row. You can fill the rest of the remaining space using flex: 1, which is equivalent to flex-grow: 1.
* {
box-sizing: border-box;
}
.container {
border: 2px solid gray;
display: flex;
flex-direction: column;
flex-wrap: wrap;
height: 300px;
}
.header {
border: 2px solid magenta;
height: 50px;
line-height: 50px;
text-align: center;
}
.subcontainer {
display: flex;
flex-direction: row;
flex: 1;
}
.column1 {
flex-basis: 150px;
border: 2px solid green;
}
.column2 {
flex: 1;
border: 2px solid orange;
}
<div class='container'>
<div class='header'>it's a header</div>
<div class="subcontainer">
<div class='column1'>column 1</div>
<div class='column2'>column 2</div>
</div>
</div>
Do it like shown below
* {
box-sizing: border-box;
}
body,
html {
height: 100%;
}
.container {
border: 2px solid gray;
display: flex;
flex-direction: column;
height: 100%;
}
.header {
width: 100%;
border: 2px solid magenta;
height: 50px;
line-height: 50px;
text-align: center;
}
.body-container {
display: flex;
width: 100%;
flex: 1;
}
.column1 {
width: 50%;
border: 2px solid green;
}
.column2 {
width: 50%;
border: 2px solid orange;
}
<div class='container'>
<div class='header'>it's a header</div>
<div class="body-container">
<div class='column1'>column 1</div>
<div class='column2'>column 2</div>
</div>
</div>

Footer overlapping the content when browser window is shrunk

I need to avoid the overlapping of the div's when the browser window is shrinked vertically in the following piece of code:
`
<html>
<body>
<style>
#box {
display: flex;
flex-direction: column;
align-items: center;
}
#top {
background-color: red;
height: 560px;
width: 400px;
}
#bottom {
background-color: green;
height: 100px;
width: 400px;
position: absolute;
bottom: 0
}
</style>
<div id="box">
<div id="top">
</div>
<div id="bottom">
</div>
</div>
<body>
</html>
`
Why are the div's getting overlapped. is there a way that this overlapping can be avoided and having the same initial structure? The bottom div acts as a footer in the real scenario. Thanks in advance!
Use min-height on the box, remove absolute positioning from the bottom and both div's heights will be kept.
When the margin-top: auto is set on a flex column item, it will push it to the bottom of is parent, which you can see on bigger screens.
body {
margin: 0;
display: flex; /* IE bug fix */
}
#box {
flex-grow: 1; /* fill body's width */
display: flex;
flex-direction: column;
align-items: center;
min-height: 100vh;
}
#top {
background-color: red;
height: 560px;
width: 400px;
border: 1px solid black;
}
#bottom {
margin-top: auto; /* push it to the bottom on big screen */
background-color: green;
height: 100px;
width: 400px;
border: 1px solid black;
}
<div id="box">
<div id="top">
</div>
<div id="bottom">
</div>
</div>
If they at some point they need to shrink, with this sample the red div does, where the height is fixed to full viewport.
It works like that, that the green is given flex-shrink: 0, which prevent it from shrink and keep its set height.
html, body {
margin: 0;
}
#box {
display: flex;
flex-direction: column;
align-items: center;
height: 100vh;
}
#top {
background-color: red;
height: 560px;
width: 400px;
border: 1px solid black;
}
#bottom {
margin-top: auto;
flex-shrink: 0;
background-color: green;
height: 100px;
width: 400px;
border: 1px solid black;
}
<div id="box">
<div id="top">
</div>
<div id="bottom">
</div>
</div>
You need to set position: relative; to parent, in this case to body element, it will solve the issue. When the parent's position is relative, and the child's position is absolute, the child will respect parent and will be positioned relatively to the parent:
body {
position: relative;
}
#box {
display: flex;
flex-direction: column;
align-items: center;
}
#top {
background-color: red;
height: 560px;
width: 400px;
}
#bottom {
background-color: green;
height: 100px;
width: 400px;
position: absolute;
bottom: 0
}
<div id="box">
<div id="top">
</div>
<div id="bottom">
</div>
</div>

Flexbox: scrollable content with sticky footer

I want to make a box (flex-item in this case) which always stays in the middle of it's container. In that box, there is a header, footer and content section. If the size of the content grows too big in height, I want the content section to be scrollable. The header and footer should always be visible and the box should always stay in it's container.
Here is what I have been able to write:
HTML
<div class="flex-container">
<div class="flex-item">
<header>Header</header>
<div class="content">
A
<br>B
<br>C
<br>D
<br>E
<br>F
<br>G
<br>H
<br>I
<br>J
<br>K
</div>
<footer>Footer</footer>
</div>
</div>
CSS
body {
margin: 120px;
}
.flex-container {
display: flex;
width: 200px;
height: 200px; /* We can assume that the container's height is hardcoded in this example, but the end solution should work even if this value is changed*/
border: 1px solid black;
justify-content: center;
}
.flex-item {
box-sizing: border-box;
width: 150px;
border: 5px solid blue;
align-self: center;
background-color: red;
display: flex;
flex-flow: column;
max-height: 100%;
}
.content {
/* It should be possible to scroll this element when it get too big in height*/
background-color: grey;
flex: 1;
}
The code is hosted on JSFiddle: https://jsfiddle.net/9fduhpev/3/
To explain the same thing visually, here is the current situation:
Here is what I want:
Use overflow-y: auto;.
Read this: http://www.w3schools.com/cssref/css3_pr_overflow-y.asp
body {
margin: 120px;
}
.flex-container {
display: flex;
width: 200px;
height: 200px;
border: 1px solid black;
justify-content: center;
}
.flex-item {
box-sizing: border-box;
width: 150px;
border: 5px solid blue;
align-self: center;
background-color: red;
display: flex;
flex-flow: column;
max-height: 100%;
}
.content {
background-color: grey;
flex: 1;
overflow-y: auto;
}
<div class="flex-container">
<div class="flex-item">
<header>Header</header>
<div class="content">
A
<br>B
<br>C
<br>D
<br>E
<br>F
<br>G
<br>H
<br>I
<br>J
<br>K
<br>L
</div>
<footer>Footer</footer>
</div>
</div>
I suggest you give it overflow: auto. With that it will be scrollable when needed.
body {
margin: 20px;
}
.flex-container {
display: flex;
width: 200px;
height: 200px;
border: 1px solid black;
justify-content: center;
}
.flex-item {
box-sizing: border-box;
width: 150px;
border: 5px solid blue;
align-self: center;
background-color: red;
display: flex;
flex-flow: column;
max-height: 100%;
}
.content {
background-color: grey;
flex: 1;
overflow: auto;
}
<div class="flex-container">
<div class="flex-item">
<header>Header</header>
<div class="content">
A
<br>B
<br>C
<br>D
<br>E
<br>F
<br>G
<br>H
<br>I
<br>J
<br>K
<br>L
</div>
<footer>Footer</footer>
</div>
</div>
I would do something like this:
.content {
height: 100%;
overflow:auto;
background-color: grey;
flex: 1;
}
https://jsfiddle.net/9fduhpev/4/

Max Height not working on flexing child with overflow

I have an element with 2 children.
I'm trying to have:
div grow as much as it needs based on 1 of its children
the other always fit the parents height
Thus, I want to avoid setting a height on the parent.
The problem arises when trying to handle overflow of the second child.
Here's the code:
.banner {
display: flex;
background-color: lightblue;
overflow: auto;
border: 4px solid black;
//max-height: 120px; // 1) IF I'M NOT SET THE SCROLL WON'T WORK
}
.constant {
color: white;
flex: 0 0 auto;
width: 200px;
// height: 150px; 2) DISABLED FOR NOW
border: 4px solid yellow;
background-color: olive;
border: 2px solid red;
}
.container {
display: flex;
text-align: center;
}
.main {
max-height: 100%; // 3) I SHOULD STOP MYSELF FROM GROWING MORE THAN MY PARENT
flex: 1;
overflow-y: scroll;
border: 2px solid white;
display: flex;
flex-direction: row-reverse;
align-items: flex-end;
flex-wrap: wrap;
}
.main div {
text-align: center;
width: 200px;
height: 80px;
}
.main-side {
flex: 0 0 auto;
color: white;
background-color: grey;
border: 2px solid yellow;
}
html {
box-sizing: border-box;
}
*,
*:before,
*:after {
box-sizing: inherit;
background-repeat: no-repeat !important;
min-width: 0px;
min-height: 0px;
}
<div class="banner">
<div class="container">
<div class="main">
<div style="background-color:coral;">A</div>
<div style="background-color:lightgoldenrodyellow;">B</div>
<div style="background-color:khaki;">C</div>
<div style="background-color:pink;">D</div>
<div style="background-color:lightgrey;">E</div>
<div style="background-color:lightgreen;">F</div>
</div>
<div class="main-side">I've a fixed size</div>
</div>
<div class="constant">I can grow...and my parent should grow if I grow</div>
</div>
If I set a fixed height on .banner everything works out, but I would like to avoid doing so if possible.
jsfiddle
Thank you.