transform an old layout to flexbox - html

Currently I have this layout.
* {
padding: 0;
margin: 0;
box-sizing: border-box;
}
html,
body {
height: 100%;
min-height: 100%;
}
#wrapper {
height: 100%;
min-height: 100%;
position: relative;
background-color: red;
}
header {
height: 100%;
min-height: 100vh;
position: relative;
background-color: green;
text-align: center;
}
#header-top {
position: fixed;
left: 0;
right: 0;
top: 0;
width: 100%;
outline: 1px dotted red;
background-color: blue;
}
#header-middle {
position: relative;
top: 50%;
transform: translateY(-50%);
background-color: yellow;
outline: 1px dotted red;
}
#header-bottom {
position: absolute;
left: 0;
right: 0;
bottom: 0;
width: 100%;
background-color: grey;
outline: 1px dotted red;
}
<div id="wrapper">
<header>
<div id="header-top">
<p>I am fixed at the top</p>
</div>
<div id="header-middle">
<p>I am vertically centered</p>
</div>
<div id="header-bottom">
<p>I am stuck at the bottom but not fixed</p>
</div>
</header>
</div>
How do I use flexbox here to get the same layout.
The html, body and #wrapper needs to expand visually to surround all the child elements.
The header is to fill the entire viewport.
The #header-top is fixed at the top containing a logo floated to left and navigation floated to right with no explicit height.
The #header-middle is to be vertically centered inside the header.
The #header-bottom is like a sticky footer stuck at the bottom but no fixed.
Fiddle

Use this:
header {
display: flex; /* Magic begins */
flex-direction: column; /* Stack vertically */
height: 100%; /* As tall as the containing block */
justify-content: space-between; /* Distribute the flex items */
}
* {
padding: 0;
margin: 0;
}
html, body, header {
height: 100%;
}
header {
display: flex;
flex-direction: column;
justify-content: space-between;
background-color: green;
text-align: center;
}
header > div {
outline: 1px dotted red;
}
#header-top {
background-color: blue;
}
#header-middle {
background-color: yellow;
}
#header-bottom {
background-color: grey;
}
<header>
<div id="header-top">
<p>I am fixed at the top</p>
</div>
<div id="header-middle">
<p>I am vertically centered</p>
</div>
<div id="header-bottom">
<p>I am stuck at the bottom but not fixed</p>
</div>
</header>

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>

Horizontal Split with Text Below and Above the Split

I want to create a page which is split by a box above a horizontal line and one below the horizontal line. Just above and below the line I want to have a text. I came up with a solution with flex and 4 divs where I adjust the height of each div to around 30%-20%-20%-30%. However when going responsive this sometimes keeps the text crossing the horizontal line. I want to guarantee that the above text stays above and the below text stays below.
Here my solution is - https://codepen.io/tobwun/pen/VwWRGWY
body,
html {
height: 100%;
width: 100%;
}
.m {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
text-align: center;
color: white;
font-weight: bold;
font-size: 2em;
}
.d1 {
background-color: pink;
width: 100%;
height: 30%;
}
.d2 {
background-color: pink;
width: 100%;
height: 20%;
}
.d3 {
background-color: lightblue;
width: 100%;
height: 20%;
}
.d4 {
background-color: lightblue;
width: 100%;
height: 30%;
}
<body>
<div class="m">
<div class="d1">
</div>
<div class="d2">
ABOVE TEXT
</div>
<div class="d3">
</div>
<div class="d4">
BELOW TEXT
</div>
</div>
</body>
I was wondering if it would be possible with two divs and some padding? With the first one the text on the bottom and the second one the text on top.. If this by design is not recommended to be done with flexbox I am also open for another solution.
Thanks for any help!
Why not just use two elements, and use align-items and justify-content to place them as you want ?
body,
html {
height: 100%;
width: 100%;
}
.m {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
color: white;
font-weight: bold;
font-size: 2em;
text-align:center;
}
.top, .bottom{
width: 100%;
height: 50%;
display:flex;
justify-content:center;
}
.top {
background-color: pink;
align-items:flex-end;
padding-bottom:0.5em;
}
.bottom {
background-color: lightblue;
align-items:flex-start;
padding-top:0.5em;
}
<body>
<div class="m">
<div class="top">
ABOVE TEXT
</div>
<div class="bottom">
BELOW TEXT
</div>
</div>
</body>
Easiest way to solve this is to use position: absolute;.
top: 50%; will put the element below the vertical center line.
bottom: 50%; will put the element above the vertical center line.
body {
margin: 0;
min-height: 100vh;
}
.top-text {
position: absolute;
bottom: 50%;
}
.bottom-text {
position: absolute;
top: 50%;
}
.top-text,
.bottom-text {
left: 0;
right: 0;
}
/* for styling purpose only */
body {
background: linear-gradient(darkblue 0% 50%, darkred 50% 100%);
color: white
}
.top-text,
.bottom-text {
text-align: center;
font-size: 2em;
border: 1px solid white;
padding: 5px;
}
<div class="top-text">Top</div>
<div class="bottom-text">Bottom</div>

center a div inside another div vertically [duplicate]

This question already has answers here:
Flexbox: center horizontally and vertically
(14 answers)
How can I vertically center a div element for all browsers using CSS?
(48 answers)
How can I vertically align elements in a div?
(28 answers)
Closed 2 years ago.
Lets say I have this simple html page:
<div class="main">
<div class="header">
<h1>HEADER</h1>
</div>
<div class="content">
<div class="box">
</div>
</div>
</div>
My header is fixed and the content should be beneath it and with height 100% of what ever left of the body.
I've already done that with this style:
*{
margin-left: 0;
margin-top: 0;
}
body,
html {
height: 100%;
width: 100%;
margin: 0;
}
.header {
background-color: red;
text-align: center;
position: fixed;
width: 100%;
}
.content {
background-color: antiquewhite;
padding-top: 38px;
}
h1 {
margin-bottom: 0;
}
.main {
display: flex;
flex-direction: column;
height: 100vh;
}
.content {
flex: 1;
}
.box {
width: 150px;
height: 150px;
background-color: yellow;
}
Here's how the page looks for now: https://elbargho.github.io/sudoku/centerdiv.html
now I'm trying to center the box div horizontally and vertically in relative to the full body - the header size
what I've tried to do:
margin-top: 50% - for some reason the box went all the way down to the bottom
setting the position of content div to relative, and of box div to absolute - the content div overlapped the fixed header
You can set content class as
.content {
/* flex: 1; */
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
}
*{
margin-left: 0;
margin-top: 0;
}
body,
html {
height: 100%;
width: 100%;
margin: 0;
}
.header {
background-color: red;
text-align: center;
position: fixed;
width: 100%;
}
.content {
background-color: antiquewhite;
padding-top: 38px;
}
h1 {
margin-bottom: 0;
}
.main {
display: flex;
flex-direction: column;
height: 100vh;
}
.content {
/*flex: 1; */
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
}
.box {
width: 150px;
height: 150px;
background-color: yellow;
}
<div class="main">
<div class="header">
<h1>HEADER</h1>
</div>
<div class="content">
<div class="box">
</div>
</div>
</div>
This is probably what you need. Documented in the code.
* {
margin-left: 0;
margin-top: 0;
}
body,
html {
height: 100%;
width: 100%;
margin: 0;
}
/* Modified */
.header {
background-color: red;
text-align: center;
/* position: fixed; */
position: sticky;
width: 100%;
}
.content {
background-color: antiquewhite;
padding-top: 38px;
}
h1 {
margin-bottom: 0;
}
/* Modified */
.main {
display: flex;
flex-direction: column;
height: 100vh;
align-items: center;
}
/* Modified */
.content {
/*flex: 1;*/
display: flex;
align-items: center;
height: inherit;
}
.box {
width: 150px;
height: 150px;
background-color: yellow;
}
<div class="main">
<div class="header">
<h1>HEADER</h1>
</div>
<div class="content">
<div class="box">
</div>
</div>
</div>
Here solution:
.content {
display: flex;
flex: 1;
justify-content: center;
align-items: center;
}
One way is to use CSS Transform.
.box {
position: relative;
top: 50%;
transform: translateY(-50%);
/* horizontal center */
margin: 0 auto;
}
Check out this website for all CSS centering help:
http://howtocenterincss.com/

CSS creating nested div box for parent div causes overlapping [duplicate]

This question already has answers here:
CSS: Width in percentage and Borders
(5 answers)
Closed 3 years ago.
I want to create a bar to go along the top of a box on a website that I am working on.
This is the desired outcome
Here's my code, I keep getting this overlap
.page {
display: flex;
flex-wrap: wrap;
position: relative;
}
.section {
border: 2px solid #FBA7FF;
width: 85%;
height: 30%;
margin: 1vw;
padding: 1vw;
display: flex;
align-items: center;
position: relative;
z-index: 1;
}
.section h1 {
position: relative;
}
.section_header {
border: 4px solid #FBA7FF;
position: absolute;
top: 0;
left: 0;
width: 100%;
bottom: 95%;
}
<div class='page'>
<div class='section'>
<div class="section_header"></div>
<h1>sample text</h1>
</div>
</div>
So far I've got the parent div with position: relative and the child element with position: absolute then setting top and left to 0 width to 100% and bottom to 95% to attempt the desired effect yet it creates an overlap.
I can see that 0 is within the div and doesn't take into account the border which is perhaps why this is happening.
* {
box-sizing: border-box;
margin: 0;
}
.page {
display: flex;
flex-wrap: wrap;
position: relative;
}
.section {
width: 100%;
display: inline-block;
text-align: center;
}
.section_header {
width: 100%;
background: #FBA7FF;
display: block;
height: 70px;
margin-bottom: 20px;
}
<div class='page'>
<div class='section'>
<div class="section_header"></div>
<h1>sample text</h1>
</div>
</div>
Remove the position:absolute and use flex-direction:column;
* {
margin: 0;
padding: 0;
}
.page {
display: flex;
flex-wrap: wrap;
flex-direction: column;
min-height: 100vh;
background: lightgrey;
position: relative;
}
.section {
border: 2px solid #FBA7FF;
width: 85%;
margin: 1vh auto;
height: 30%;
background: lightgreen;
display: flex;
flex-direction: column;
flex: 1;
align-items: center;
}
.section_header {
height: 50px;
width: 100%;
background: orange;
}
<div class='page'>
<div class='section'>
<div class="section_header"></div>
<h1>sample text</h1>
</div>
</div>

How to make center area full viewport height minus dynamic height areas (flexbox)

How to do this without using fixed heights anywhere. This way, the <div> area is scrollable and the sections each take up the full visible height. But the nav elements are fixed.
One way to do this is calc(100vh - dynamic heights) but looking for a non-hardcoded way of doing it.
* {
position: relative;
box-sizing: border-box;
margin: 0;
padding: 0;
}
html, body {
height: 100%;
overflow: hidden;
}
body, header, section, footer {
display: flex;
}
body, div {
flex-direction: column;
}
section {
flex: 1;
background: red;
border: 1px solid pink;
}
footer {
height: 200px; /* just for demo purposes */
width: 100%;
background: yellow;
}
header {
width: 100%;
height: 50px; /* just for demo purposes */
background: orange;
}
div {
overflow-y: scroll;
display: flex;
flex: 1;
}
<header>
</header>
<div>
<section>
</section>
<section>
</section>
<section>
</section>
</div>
<footer>
</footer>
This is how I would do it
* {
position: relative;
box-sizing: border-box;
margin: 0;
padding: 0;
}
html,
body,
section {
min-height: 100vh; /* make the body and sections the height of the viewport */
overflow: hidden;
}
body { /* only the body needs to be flex - you don't want everything to be otherwise you will have ie / safari problems with nested flex */
display: flex;
flex-direction: column;
}
.main {
/* min-height: 100px; - you can add a min height here if you want so you don't get a situation where this middle section doesn't show up */
flex-grow: 1; /* grow the main to be the rest of the height */
background: red;
border: 1px solid pink;
position: relative;
}
.scroll { /* add a scrollable div for your sections */
position: absolute;
left: 0;
right: 0;
bottom: 0;
top: 0;
overflow:auto;
}
footer {
height: 200px; /* this can be removed if you want */
width: 100%;
background: yellow;
}
header {
width: 100%;
height: 50px; /* this can be removed if you want */
background: orange;
}
<header>
</header>
<div class="main">
<div class="scroll">
<section>
</section>
<section>
</section>
<section>
</section>
</div>
</div>
<footer>
</footer>
After comments:
* {
position: relative;
box-sizing: border-box;
margin: 0;
padding: 0;
}
html,
body {
min-height: 100vh;
/* make the body the height of the viewport */
overflow: hidden;
}
body {
/* only the body needs to be flex - you don't want everything to be otherwise you will have ie / safari problems with nested flex */
display: flex;
flex-direction: column;
}
.main {
/* min-height: 100px; - you can add a min height here if you want so you don't get a situation where this middle section doesn't show up */
flex-grow: 1;
/* grow the main to be the rest of the height */
background: red;
border: 1px solid pink;
position: relative;
}
.scroll {
/* add a scrollable div for your sections */
position: absolute;
left: 0;
right: 0;
bottom: 0;
top: 0;
height:100%;
overflow:auto;
}
section {
border: 1px solid blue;
box-sizing:border-box;
min-height:100%;
}
footer {
height: 200px;
/* this can be removed if you want */
width: 100%;
background: yellow;
}
header {
width: 100%;
height: 50px;
/* this can be removed if you want */
background: orange;
}
<header>
</header>
<div class="main">
<div class="scroll">
<section>
</section>
<section>
</section>
<section>
</section>
</div>
</div>
<footer>
</footer>
You can simplify that code a little, and the 2 key settings are flex: 1 on the div (which you already have) and flex-shrink: 0 on section.
The flex: 1 makes the div to fill available space without take its own content into account, and the flex-shrink: 0 will prevent the section's to shrink-to-fit.
I also changed from 100% on height to 100vh, so one doesn't need to repeat it down the line.
Tested with success on Chrome, Firefox, Edge and IE11, and I also removed some unnecessary properties, like width: 100%, and all fixed height's.
Fiddle demo
Stack snippet
* {
position: relative;
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
height: 100vh;
}
body, div {
display: flex;
flex-direction: column;
}
div {
flex: 1;
overflow: auto;
}
section {
flex-shrink: 0;
height: 100%;
padding: 10px;
background: red;
border: 1px solid pink;
}
footer {
padding: 10px;
background: yellow;
}
header {
padding: 10px;
background: orange;
}
<header>
A header which<br>
has 2 line of text
</header>
<div class="content">
<section>
1
</section>
<section>
2
</section>
<section>
3
</section>
</div>
<footer>
A footer which<br>
has more lines of<br>
text than the<br>
header has and<br>
it size nicley
</footer>