Reputation: 16291
As an exercise, I am working on using Flex Box to implement the following layout:
┌───────────────────────────────┐
│ header │
└───────────────────────────────┘
┌─────┐ ┌───────────────────────┐
│ nav │ │ main │
│ │ │ │
└─────┘ └───────────────────────┘
┌───────────────────────────────┐
│ footer │
└───────────────────────────────┘
My initial thought was to use:
body {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
but I’m not sure what to do about the rest. Currently I use:
header,footer {
width: 100%;
}
nav {
flex-basis: 0;
flex-grow: 1;
}
main {
flex-basis: 0;
flex-grow: 4;
}
with a bit of extra fine tuning.
This works, but it seems contrived.
An alternative solution would be to wrap the nav
and main
element inside a div
, but I am trying to avoid that as it reduces flexibility.
The question is, what is the most appropriate way to have a layout with one element on some rows, and multiple elements on others?
Upvotes: 0
Views: 1244
Reputation: 12068
The point is in flex-basis
which needs to be defined, i.e. different from the initial value of auto
, in order to enable wrapping of additional elements, if the prefered way is doing it without the additional parent element, which is perfectly fine:
$('button:first-of-type').click(function(){
$('<div>3</div>').insertAfter('.insertAfter');
});
$('button:last-of-type').click(function(){
$('div:not(.first)').toggleClass('flexBasis');
});
body {
display: flex;
flex-wrap: wrap;
}
body > * {text-align: center}
header, footer {
flex-basis: 100%;
background: #f88;
}
nav {
flex-basis: 20%;
background: lightgreen;
}
main {
flex-basis: 80%;
background: lightblue;
}
.first {
flex-basis: 33.33%;
background: lightgray;
}
div {
flex: 1; /* not enough */
background: gray;
}
.flexBasis {
flex: 1 25%; /* enough */
}
.insertAfter ~ div {color: #fff; background: #000}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Add</button>
<button>Toggle flex-basis</button>
<header>Header</header>
<nav>Nav</nav>
<main>Main</main>
<div class="first">1</div>
<div class="first">1</div>
<div class="first">1</div>
<div>2</div>
<div>2</div>
<div>2</div>
<div class="insertAfter">2</div>
<footer>Footer</footer>
Upvotes: 2
Reputation: 5648
Two thing you should add:
1) Make the body display:flex
to turn it into a flex container
2) Use the flex
shorthand to indicate the flex grow and basis to the header and footer. By making the basis 100vw, you make does flex items 100% of the viewport width
flex: 1 100vw;
Hope this helps :)
body {
display:flex;
flex-direction: row;
flex-wrap: wrap;
background: red;
margin:0;
}
header,footer {
width: 100%;
background: blue;
flex: 1 100vw;
}
nav {
flex-basis: 0;
flex-grow: 1;
background: green;
}
main {
flex-basis: 0;
flex-grow: 4;
background: pink;
}
<body>
<header> </header>
<nav> </nav>
<main> </main>
<footer> </footer>
</body>
Upvotes: 0