There are many examples on this topic here, but what I am after is something that I cannot seem to find the answer to.
I want to create a two column page:
Left column for Navigation (Fixed Width), Right column for content (Responsive). The variation I am after is that I want the Nav to appear on the left for desktop and beneath the content on mobile.
I have the code 'working' kind of, but it's the responsive width of the right column that is the issue.
My code is below, Any guidance would be really valued.
.CF:after { content:"."; display:block; height:0; clear:both; visibility:hidden; }
.CF { display:inline-block; }
.CF { display:block; }
.content {max-width: 1300px; margin: 0 auto; padding: 0 25px; display:block; }
.information {display:block; background: lime;}
.menu {display:block; background: lightblue;}
#media all and (min-width: 992px) {
.content {padding: 0 50px; }
.information {display:block; float: right; width: auto; }
.menu {width: 250px; float:right; }
}
<div class="content CF">
<article class="information">
Article Information
</article>
<nav class="menu">
Menu
</nav>
</div>
I would use flexbox to solve this.
Below the menu is at the left side when the width of the screen is more than 991 pixels. Otherwise it is below the article.
I have assigned colors for visibility only.
.content {
display: flex;
background: blue;
}
.menu {
width: 100px;
background: red;
}
.information {
background: green;
flex-grow: 1;
}
#media all and (max-width: 991px) {
.content {
flex-wrap: wrap;
}
.menu {
order: 2;
}
.information {
order: 1;
min-width: 100%;
}
}
<div class="content">
<nav class="menu">
Menu
</nav>
<article class="information">
Article Information
</article>
</div>
I would suggest looking at CSS Grid or Flexbox for layout. Support for Grid is good.
Example using Grid...
codepen
.content {
max-width: 1300px;
margin: 0 auto;
padding: 0 25px;
display: block;
grid-template-columns: 250px 1fr;
}
.information {
background: lime;
order: 2;
}
.menu {
background: lightblue;
}
#media all and (min-width: 992px) {
.content {
display: grid;
padding: 0 50px;
}
}
<div class="content CF">
<article class="information">
Article Information
</article>
<nav class="menu">
Menu
</nav>
</div>
You've already had two great answers but just to add a few extra options, here are 5 different ways of achieving the same thing:
Example 1: Floats, Widths and Margins
The most compatible method, works on pretty much all browsers. Its also got the smallest CSS footprint.
#example1 .fixedColumn {
width: 180px;
float: left;
}
#example1 .flexibleColumn {
margin-left: 200px;
}
/* gratuituous styling */
.fixedColumn { background-color: #e84c1b; padding: 10px;} .flexibleColumn { background-color: #039be4; padding: 10px;} body { margin: 0; }
<div id="example1">
<div class="fixedColumn">
Fixed Column
</div>
<div class="flexibleColumn">
Flexible Column
</div>
</div>
Example 2: CSS calc()
Compatible with IE9+. Its a solid alternative if you don't need backwards compatibility.
#example2.calc {
overflow: hidden;
}
#example2.calc .fixedColumn {
width: 180px;
float: left;
}
#example2.calc .flexibleColumn {
width: calc(100% - 220px); /*200px for the fixed column and 20 for the left and right padding */
float: left;
}
/* gratuituous styling */
.fixedColumn { background-color: #e84c1b; padding: 10px;} .flexibleColumn { background-color: #039be4; padding: 10px;} body { margin: 0; }
<div id="example2" class="calc">
<div class="fixedColumn">
Fixed Column
</div>
<div class="flexibleColumn">
Flexible Column
</div>
</div>
Example 3: Display as Table
Another solid contender for backwards compatibility works pretty much across the board, but still feels like a bodge making things behave like a table.
#example3.table {
display: table;
width: 100%;
}
#example3.table .fixedColumn {
width: 180px;
display: table-cell;
}
#example3.table .flexibleColumn {
display: table-cell;
}
/* gratuituous styling */
.fixedColumn { background-color: #e84c1b; padding: 10px;} .flexibleColumn { background-color: #039be4; padding: 10px;} body { margin: 0; }
<div id="example3" class="table">
<div class="fixedColumn">
Fixed Column
</div>
<div class="flexibleColumn">
Flexible Column
</div>
</div>
Example 4: Flexbox
Great for modern browsers that support it; simple and intuitive.
#example4.flex {
display: flex;
}
#example4.flex .fixedColumn {
width: 180px;
}
#example4.flex .flexibleColumn {
flex: 1;
}
/* gratuituous styling */
.fixedColumn { background-color: #e84c1b; padding: 10px;} .flexibleColumn { background-color: #039be4; padding: 10px;} body { margin: 0; }
<div id="example4" class="flex">
<div class="fixedColumn">
Fixed Column
</div>
<div class="flexibleColumn">
Flexible Column
</div>
</div>
Example 5: Grid
Out of all the techniques here Grid was supported by browsers last. But its a great option if you have the option to use it.
#example5.grid {
display: grid;
grid-template-columns: 200px 1fr;
}
#example5.grid .fixedColumn {
grid-column: 1;
}
#example5.grid .flexibleColumn {
grid-column: 2;
}
/* gratuituous styling */
.fixedColumn { background-color: #e84c1b; padding: 10px;} .flexibleColumn { background-color: #039be4; padding: 10px;} body { margin: 0; }
<div id="example5" class="grid">
<div class="fixedColumn">
Fixed Column
</div>
<div class="flexibleColumn">
Flexible Column
</div>
</div>
Related
I have the following layout:
a wrapper that get all the width of the browser
a wrapper-right(menu) that is always close to the browser right
header that has a max width and is centered
content align with header
When the resolution is below a specific step(32rem) and wrapper_right get close to the header I want the header to get a smaller width, so the wrapper_right doesn't go over it.
The problem is that the header doesn't remain align to the left to the content, being set to left,right auto.
I try to use margin-left:80px, but doesn't work properlly.
If the resolution goes below 27rem I want the wrapper_right to be hidden, and header back to normal.
OBS. 27rem, 32rem are just for example, to be visible in the code box. I can modify the html code if is necessary.
.wrapper {
height: 6rem;
position: relative;
width: 100%;
background-color: red;
display: inline-block;
}
.header {
margin: 1.5rem auto 0;
max-width: 30rem;
background-color: blue;
}
#media (max-width: 32em) {
.header {
max-width: calc(30rem - 80px);
}
}
.wrapper-right {
background: green;
height: 100%;
position: absolute;
right: 0;
top: 0;
width: 80px;
}
.content {
max-width: 30rem;
margin: 0 auto;
background-color: orange;
}
<div class="wrapper">
<div class="header">
<div> lorem ipsum></div>
<div> lorem ipsum></div>
<div> lorem ipsum></div>
</div>
<div class="wrapper-right">menu</div>
</div>
<div class="content">content</div>
Is this what you're after?
https://codepen.io/panchroma/pen/PxKBBV
The important bits in the CSS are:
lines 36-40 where we're scaling the width of .header at viewports below 40rem
lines 42 - 50 where we're hiding .wrapper-right, and restoring .header to full-width
As an FYI, your CSS has a class titled .l-header but I couldn't see where you were going with this.
Hope this helps!
HTML
As originally posted
CSS
.wrapper {
height: 6rem;
position: relative;
width: 100%;
background-color: red;
display: inline-block;
}
.header {
margin: 1.5rem auto 0;
max-width: 30rem;
background-color: blue;
}
#media (max-width: 32em) {
.l-header {
max-width: calc(30rem - 80px);
}
}
.wrapper-right {
background: green;
height: 100%;
position: absolute;
right: 0;
top: 0;
width: 80px;
}
.content {
max-width: 30rem;
margin: 0 auto;
background-color: orange;
}
#media (max-width: 40rem) {
.header{
width:calc(75vw - 80px);
}
}
#media (max-width: 27rem) {
.wrapper-right{
display:none;
}
.header{
width:100%;
}
}
Version 2
Based on your comments, here's version 2
https://codepen.io/panchroma/pen/VVMJxM
The important bits are that I added the .header-wrapper. Then we're changing the left and right padding on .header-wrapper at various viewports to keep the header and content divs aligned.
Good luck!
HTML
<div class="wrapper">
<div class="header-wrapper">
<div class="header">
<div> lorem ipsum></div>
<div> lorem ipsum></div>
<div> lorem ipsum></div>
</div>
</div>
<div class="wrapper-right">menu</div>
</div>
<div class="content">content</div>
CSS
/* note that I'm using normalize.css in the CSS setings */
/* https://necolas.github.io/normalize.css/ */
.wrapper {
height: 6rem;
position: relative;
width: 100%;
background-color: red;
display: inline-block;
margin-right:80px;
}
.header {
margin: 1.5rem auto 0;
max-width: 30rem;
background-color: blue;
position:relative;
z-index:5;
}
.wrapper-right {
background: green;
height: 100%;
position: absolute;
right: 0;
top: 0;
width: 80px;
}
.content {
max-width: 30rem;
margin: 0 auto;
background-color: orange;
}
#media (max-width: 40rem) {
.header-wrapper {
/* add padding-right to make room for .wrapper-right */
/* have used 81px instead of 80px so we can be certain */
/* that the div isn't extending under .wrapper-right */
padding-right:81px;
/* add padding-left to keep .header and .content aligned */
/* logic is that the space to the left of .content */
/* is the half of the window width - width of .content */
padding-left:calc(50vw - 15rem);
}
}
/* at viewports below 27rem, hide .wrapper-right and return .header to full width */
#media (max-width: 27rem) {
.wrapper-right{
display:none;
}
.header-wrapper{
padding:0;
}
}
I have these two different layouts illustrated in the code below. My issue is that I can't replicate these layouts without changing the markup. I was wondering if there was some fancy flexbox way I can accomplish exactly this while only using one html scheme. Note: the container will need to have a dynamic height. The solution doesn't necessarily have to use flexbox as long as the desired layout is achieved.
main {
width: 750px;
max-width: 100%;
margin: auto;
border: solid 1px black;
display: flex;
flex-wrap: wrap;
}
.a {
background: red;
width: 40%;
}
.b {
background: blue;
width: 60%;
}
.c {
background: green;
}
.a-mobile {
background: red;
width: 40%;
}
.b-mobile {
background: blue;
width: 60%;
}
.c-mobile {
background: green;
width: 100%;
}
<h2>Desktop</h2>
<main>
<div class="a">a</div>
<div class="b">b
<div class="c">c</div>
</div>
</main>
<h2>Mobile</h2>
<main>
<div class="a-mobile">a-mobile</div>
<div class="b-mobile">b-mobile</div>
<div class="c-mobile">c-mobile</div>
</main>
display:grid will be useful for this kind of layout:
but this is still experimental and(2020) can be tested in few browsers, see also http://caniuse.com/#search=grid
A tutorial among others https://css-tricks.com/snippets/css/complete-guide-grid/
main {
display: grid;
grid-template-columns: 30% auto;
}
.a {
background: red;
grid-row-end: span 2
}
.b,
.c {
background: green;
}
.c {
background: lightblue
}
#media screen and (max-width: 700px) {/* value setted for the demo */
.a {
grid-row-end: span 1/* reset optionnal in this very case */
}
.c {
grid-column-end: span 2
}
}
<main>
<div class="a"> break point set at 700px for demo</div>
<div class="b"> i don't move much myself :)</div>
<div class="c"> see in full page to see me aside the red box and below the green one</div>
</main>
codepen to play with
Here's the float-flexbox method I described in the comments. Not particularly fond of it, but it does exactly what you asked for.
It's hacky and, from my POV, goes in the same category as Bootstrap 3's .clearfix::before|after hack — {display:table; content: " ";} — it is a practical solution to a real layout problem, usable until a better, cleaner one will have better browser support and render this one obsolete.
main {
width: 750px;
max-width: 100%;
margin: auto;
border: solid 1px black;
display: flex;
flex-wrap: wrap;
margin-bottom: 1em;
color: white;
}
.a {
background: red;
flex-basis: 40%;
}
.b {
background: blue;
flex-basis: 60%;
}
.c {
background: green;
flex-basis: 100%;
}
#media (min-width: 800px) {
main {
display: block;
overflow: hidden;
}
.a {
float: left;
min-width: 40%;
}
.b,.c {
padding-left: 40%;
}
.a,.c {
padding-bottom: 32768px;
margin-bottom: -32768px;
}
}
<main>
<div class="a">a<br />a<br />a<br/>a</div>
<div class="b">b</div>
<div class="c">c</div>
</main>
<main>
<div class="a">a</div>
<div class="b">b<br />b<br />b<br/>b</div>
<div class="c">c</div>
</main>
<main>
<div class="a">a</div>
<div class="b">b</div>
<div class="c">c<br />c<br />c<br/>c</div>
</main>
Another solution, it's independent of flex box, and does not need fixed height.
Flexbox does not do a good job of adjusting to two dimensional layouts!
html {
height: 100%;
}
body {
height: 100%;
}
main {
width: 750px;
max-width: 100%;
margin: auto;
border: solid 1px black;
height: 100%;
}
.a {
background: red;
width: 40%;
height: 100%;
float: left;
}
.b {
background: blue;
width: 60%;
height: 50%;
float: left;
}
.c {
background: green;
width: 60%;
height: 50%;
float: left;
}
#media (max-width: 800px) {
.a {
width: 40%;
height: 50%;
}
.c {
width: 100%;
}
}
<h2>Desktop and Mobile</h2>
<main>
<div class="a">a</div>
<div class="b">b</div>
<div class="c">c</div>
</main>
I have equal height columns with centered content:
http://codepen.io/anon/pen/BzKwgE
<div class="cont">
<div class="item item-first">
<p>First</p>
</div>
<div class="item item-second">
<p>Second Second Second Second Second Second Second Second Second Second Second Second Second Second Second Second Second </p>
</div>
<div class="item item-third">
<p>Third</p>
</div>
</div>
* {
box-sizing: border-box;
}
.cont {
width: 70%;
display: table;
}
.item {
display: table-cell;
vertical-align: middle;
text-align: center;
padding: 20px;
width: 33%;
}
.item-first {
background: blue;
}
.item-second {
background: green;
}
.item-third {
background: blue;
}
This is working great. However I also need my columns to have a 16x9 aspect ratio. In rare cases there will be a lot of content, in which case its OK to change the aespect ratio.
Ive got this working below however it stops the content being vertically centered:
http://codepen.io/anon/pen/pbyWMj
* {
box-siing: border-box;
}
.cont {
width: 70%;
display: table;
}
.item {
display: table-cell;
vertical-align: middle;
text-align: center;
padding: 20px;
width: 33%;
}
.item:before {
padding-bottom: 56.25%; // 16:9 ratio
display: block;
content: '';
float: left;
width: 1px;
}
.item-first {
background: blue;
}
.item-second {
background: green;
}
.item-third {
background: blue;
}
I can see that this is happening due to the padding hack. Is there a way to have equal height columns, vertically centered content, and the 16x9 aspect ratio?
Im supporting IE9. Ideally it would look the same, but a usable fallback is also acceptable.
You can use inline-block and vertical-align on the elements inside each item. Try this:
.item {
display:table-cell;
vertical-align:middle;
text-align: center;
width: 33%;
}
.item:before {
padding-bottom: 56.25%;
display: inline-block;
content: '';
width: 0;
vertical-align:middle;
margin-right:-4px;
}
.item p {
display:inline-block;
vertical-align:middle;
padding:20px;
}
Codepen Update
I try to have a row with 3 divs.
The middle div should be responsive with a mex-width, remaining space left and write should be filled in with a color.
I know I could solve this using an wrapper with auto-margin left and right but I need to have the center div transparent and not showing the wrapper background color.
I tried to solve this using a display table but did not manage to do this.
<div id="table">
<div id="row">
<div id="left"></div>
<div id="middle">Row 1</div>
<div id="right"></div>
</div>
<div style="clear:both;"></div>
<div id="row">
<div id="left"></div>
<div id="middle">Row 2</div>
<div id="right"></div>
</div>
<div style="clear:both;"></div>
</div>
with css
#table {
width:100%;
display:table;
}
#row {
width:100%;
display:table-row;
margin-bottom:10px;
}
#left {
width:auto;
display:table-cell;
background-color: #FF0000;
}
#middle {
display:table-cell;
width:auto;
max-width: 100px;
height:50px;
background-color: #eeeeee;
}
#right {
width:auto;
display:table-cell;
background-color: #FF0000;
}
http://jsfiddle.net/thepofo/kdJHh/2/
Ideas are welcome.
The hacky way
http://jsfiddle.net/coma/rFg2L/2/
.foo {
overflow: hidden;
}
.foo > div {
position: relative;
margin: 0 auto;
max-width: 100px;
}
.foo > div:before,
.foo > div:after {
content: "";
position: absolute;
top: 0;
bottom: 0;
width: 999999px;
background-color: red;
}
.foo > div:before {
right: 100%;
}
.foo > div:after {
left: 100%;
}
The flexbox way (http://caniuse.com/#search=flex)
http://jsfiddle.net/coma/YYm32/
.foo {
display: -webkit-box;
-webkit-box-orient: horizontal;
display: -moz-box;
-moz-box-orient: horizontal;
display: box;
box-orient: horizontal;
}
.foo > div {
-webkit-box-flex: 1;
-moz-box-flex: 1;
box-flex: 1;
}
.foo > div:nth-child(2) {
max-width: 100px;
}
.foo > div:first-child,
.foo > div:last-child {
background-color: red;
}
Bonus track
You don't need to add extra markup to clear your floats: http://jsfiddle.net/coma/Lqc2H/
This may or may not be enough to work for you, but how about setting the div to 33% width of the wrapper.
<div class="wrap">
<div class="left"> </div>
<div class="middle">Lorem ipsum dolor...</div>
<div class="right"> </div>
</div>
.wrap>div {
float:left;
width: 33%;
}
.middle {
max-width: 200px;
outline:1px solid;
}
fiddle here
Otherwise, you might want to consider media queries for specific widths.
What I want to do is have a <div> with a container class and a fixed width, holding a <div> with the block class to prevent other content encroaching on any uneven blank space, then two columns (<div>'s) side-by-side inside the block, and to be 50% of the width of the block.
When I create this, I get what appears to be a margin after the first block, which I do not want. I want the block to pack up tight, no margins.
I have an example here of what I have so far, and here if the code:
<html>
<head>
<title>Columns</title>
<style>
div {
margin: 0;
padding: 0;
}
.container {
background: #DDD;
width: 1200px;
margin: 0 auto;
padding: 2% 0;
}
.block {
background: #555;
width: 100%;
display: block;
}
.col {
width: 49%;
display: inline-block;
background: #333;
}
</style>
</head>
<body>
<div class="container">
<div class="block">
<div class="col left">
<h1>Left</h1>
</div>
<div class="col right">
<h1>Right</h1>
</div>
</div>
</div>
</body>
</html>
Your problem is being causes by inline-block, using this makes a space appear inbetween.
Try using float:left to get around this:
See on jsFiddle
.col {
width: 50%;
float: left;
box-sizing: border-box;
background: #333;
}
Note that I added, box-sizing:border-box; this means when you use padding it will be included in the width, not on top of it. Effectively enabling the use of it without an extra inner div.
Remember to include a clear fix afterwards also to "clear" the floats.
CSS
.clear {
clear:both;
}
HTML
<div class="block">
<div class="col left">
<h1>Left</h1>
</div>
<div class="col right">
<h1>Right</h1>
</div>
<div class="clear"></div>
</div>
Try replacing these classes:
.block {
background: none repeat scroll 0 0 #555555;
display: block;
overflow: auto;
width: 100%;
}
.col {
width: 49%;
float: left;
background: #333;
}
.container {
background: #DDD;
width: 900px;
margin: 0 auto;
padding: 30px 30px 30px 30px;
}
.block {
background: #555;
width: 100%;
display: block;
}
.block:after {
content: "";
display: table;
clear: both;
}
.col {
width: 50%;
float: left;
background: #333;
}