I want to obtain this layout:
<------------ Browser Width 100% ------------>
[left][----- center: fixed width -----][right]
The center column has a fixed pixel width
The left and right columns fill in the remaining viewport width equally
The example below breaks when the viewport width is not wide enough, and getting the correct percentage width is hard because of the fixed width center column.
div {
display: inline-block;
background: #F90;
height: 100px;
width: 20%;
}
.center {
width: 500px;
background: #FF0;
}
<div class="left">left (fill available space)</div>
<div class="center">fixed width</div>
<div class="right">right (fill available space)</div>
Three ways to achieve a fluid / fixed column layout
Method #1 - with display: table
This is one of the easiest methods and has good browser support.
Compatibility: IE8 + and all modern browsers
body gets display: table - this could also be applied to a div wrapper instead.
table-layout: fixed ensures the middle column remains fixed width
the direct div children of body get display: table-cell
the body gets a min-width to ensure the left and right columns do not get too small
the middle column is fixed at your desired width (500px in this example)
the left and right columns inherit the remaining page width
#1 - Working Example
html {
height: 100%;
}
body {
display: table;
height: 100%;
margin: 0;
width: 100%;
table-layout: fixed;
min-width: 800px;
}
body > div {
display: table-cell;
}
.left {
background: #000;
}
.middle {
background: #F00;
width: 500px;
}
.right {
background: #F90
}
<div class="left">
</div>
<div class="middle">
</div>
<div class="right">
</div>
Method #2 - with display: inline-block and width: calc(x - y)
Compatibility: Calc is compatible in IE 9 + and most modern browsers. There are javascript fallbacks available as well.
The direct div children of body are given display: inline-block and vertical-align: top. They will align themselves to the top of the browser window on the same line
The middle column gets its fixed width
The left and right columns are given calc(50% - 250px); this calculates 50% of the page width minus half of the width of the fixed middle column.
box-sizing: border-box incorporates padding and borders into the width and height
#2 - Working Example
Note how the closing and opening divs tags have no gaps between them; this is to prevent an inline gap between elements.
* {
box-sizing: border-box;
}
html,
body {
height: 100%;
margin: 0;
}
body {
min-width: 800px;
}
body > div {
display: inline-block;
width: calc(50% - 250px);
height: 100%;
vertical-align: top;
}
.left {
background: #000;
}
.middle {
background: #F00;
width: 500px;
}
.right {
background: #F90
}
<div class="left"></div><div class="middle"></div><div class="right"></div>
Method #3 - with display: flex
This is a really awesome method, but is not supported with older browsers :(
Compatibility: IE11 and most modern browsers
The body gets display: flex and height: 100vh (100% of the viewport height)
The direct children get flex: 1 and will grow and shrink
The middle column gets its fixed width and flex: 0 0 auto; it will not grow or shrink
Here is a useful guide to Flexbox.
#3 - Working Example
body {
display: flex;
height: 100vh;
margin: 0;
min-width: 800px;
}
body > div {
flex: 1;
}
.left {
background: #000;
}
.middle {
background: #F00;
width: 500px;
flex: 0 0 auto;
}
.right {
background: #F90
}
<div class="left">
</div>
<div class="middle">
</div>
<div class="right">
</div>
Related
In the following HTML, I want to set the height of left and right 100% of the parent element. In addition, the left div has fixed width. The right should use all of the remaining width.
I think because of using display: flex; in the parents div, the width of the left div doesn't stay constant. How can I set fixed width for it and allocate all of the remaining space to the right.
Edit: the calc(100-52px) is the height of the parent. The question is only about setting fixed width of 100px to the left so that it doesn't change on resizing the window.
Here's what I'm trying:
body {
padding: 0;
margin: 0;
}
.parent {
background: red;
display: flex;
height: calc(100vh - 52px);
}
.left {
width: 100px;
background: yellow;
}
.right {
background: orange;
width: 100%;
}
<div class="parent">
<div class="left">the width should be fixed, not flexible</div>
<div class="right">width should be all of the remaining</div>
</div>
parent { display: -webkit-box;display:-webkit-flex;display: -ms-flexbox;display:flex;flex-wrap: wrap; }
.parent > [class*='col-'] { display: flex; flex-direction: column; }
You can use width: calc(100% - 100px) or flex: 1 for the right div.
Percentage values are calculated from the parent element, therefore you need to extract static values from 100% to get the remaining area.
But as you are already using a flex container here, you can just set flex: 1, which is the shorthand for flex-grow: 1, that will allow your container to take all the extra space in the parent container, since no other items are available.
Add a flex declaration to the .left selector:
flex: 0 0 100px;
flex syntax:
none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
So this declaration is stating: "don't grow, don't shrink, define the initial size as 100px"
Read more: flex (MDN)
If right is to stand 52px away from the far right, then a margin will do . Please clarify your question.
body {
padding: 0;
margin: 0;
}
.parent {
background: red;
display: flex;
height: calc(100vh - 52px);
}
.left {
width: 100px;
background: yellow;
}
.right {
flex-grow: 1;
background: orange;
margin-right: 52px;
}
<div class="parent">
<div class="left">the width should be fixed, not flexible</div>
<div class="right">width should be all of the remaining</div>
</div>
Set flex: 0 0 100px; on your .left div (you can remove width: 100px) if you want it to be a constant 100px - so no growing or shrinking.
body {
padding: 0;
margin: 0;
}
.parent {
background: red;
display: flex;
height: calc(100vh - 52px);
}
.left {
flex: 0 0 100px;
background: yellow;
}
.right {
background: orange;
width: 100%;
}
<div class="parent">
<div class="left">the width should be fixed, not flexible</div>
<div class="right">width should be all of the remaining</div>
</div>
see if this helps you, comment if you need any changes
stackblits link for 1 fixed width, 1 relative column
Similar to this question I´m struggling with using CSS grid to create a layout with fixed header and footer containing an middle row, which should use the remaining space of the .static or .dynamic dynamic container. So in this case, both oth them should have a complete height of 200px. Subtracting the 40px (2x 20px for header + footer) the remaining space for the content should be 160px. As you can see at the example, the red reference div on the left is clearly smaller than the whole "sandwich" of div containers. The .dynamic div element is to large and will stretch the whole div container. I want to prohibit this!
Here are a few additional conditions I have to fullfill:
The whole layout should be dynamic, so the .wrapper div later wont have a static height, but will fill 100% of the given height. therefore onlydynamic will be used, since this also uses 100% of the height. The showcase with .static is just there to show that it doesn´t even work with fixed heights.
Neither static nor dynamic should work with overflow to create scrollbars or hidden overflowing content. It should just restrict the dynamic area between .header and .footer to an height.
The containing .content container will expand itself to 100% width and should be treatet as a kind of blackbox: every component should be able to be inserted here. The content will always use 100% of the height and should not strech the ambient parent divs. The content will contain an scrollbar on its own, if the height of the content will be heigher than the dynamically allocated space of the .dynamic container
How am I able to solve this issue with the given description?
Please see the provided example and feel free to adapt it as you need to!
.wrapper {
display: flex;
flex-direction: row;
height: 200px;
max-height: 200px;
width: 100%;
}
.measurement {
height: 200px;
max-height: 200px;
min-height: 200px;
min-width: 3px;
background-color: red;
border: 2px solid blue;
padding: 2px;
margin: 1px;
}
.static,
.dynamic {
display: grid;
grid-template-rows: 20px 1fr 20px;
width: 50%;
border: 2px solid blue;
padding: 2px;
margin: 1px;
}
.static {
height: 200px;
max-height: 200px;
/*should NOT have an overflow/scrollbar but fit to the remaining space*/
}
.dynamic {
height: 100%;
max-height: 100%;
/*should NOT have an overflow/scrollbar but fit to the remaining space*/
}
.content {
height: 100%;
width: 100%;
overflow: auto;
/* Blackbox like content, always expands to 100% width and height */
/* could contain content that is larger than the dynamic-height div and will get scrollbar then */
}
.fixed-height {
background-color: green;
}
<div class="wrapper">
<div class="measurement"></div>
<div class="static">
<div class="fixed-height">TOP</div>
<div class="dynamic-height">
<div class="content">
TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST
</div>
</div>
<div class="fixed-height">BOTTOM</div>
</div>
<div class="dynamic">
<div class="fixed-height">TOP</div>
<div class="dynamic-height">
<div class="content">
TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST
</div>
</div>
<div class="fixed-height">BOTTOM</div>
</div>
</div>
EDIT
As you can see in the image below, the TEST and BOTTOM text is beyond the blue borders. I´m not about the few pixels difference between the borders and the red reference but I'm concerned about the overflow over the bottom border.
This is the expected behaviour: there should be a scrollbar inside the content area, no overflow and no scrollbar inside dynamic div
You need to merge the div.content with the div.dynamic-height and set the max-height: 100% property to your .dynamic-height class.
.content doesn't need an height, it's setted by the definition of the grid row.
.wrapper {
display: flex;
flex-direction: row;
height: 200px;
max-height: 200px;
width: 100%;
}
.measurement {
height: 200px;
max-height: 200px;
min-height: 200px;
min-width: 3px;
background-color: red;
border: 2px solid blue;
padding: 2px;
margin: 1px;
}
.static,
.dynamic {
display: grid;
grid-template-rows: 20px 1fr 20px;
width: 50%;
border: 2px solid blue;
padding: 2px;
margin: 1px;
}
.static {
height: 200px;
max-height: 200px;
/*should NOT have an overflow/scrollbar but fit to the remaining space*/
}
.dynamic {
height: 100%;
max-height: 100%;
/*should NOT have an overflow/scrollbar but fit to the remaining space*/
}
.content {
width: 100%;
overflow: auto;
/* Blackbox like content, always expands to 100% width and height */
/* could contain content that is larger than the dynamic-height div and will get scrollbar then */
}
.fixed-height {
background-color: green;
}
.dynamic-height {
max-height: 100%;
}
<div class="wrapper">
<div class="measurement"></div>
<div class="static">
<div class="fixed-height">TOP</div>
<div class="dynamic-height content">
TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST
</div>
<div class="fixed-height">BOTTOM</div>
</div>
<div class="dynamic">
<div class="fixed-height">TOP</div>
<div class="content dynamic-height">
TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST<br>TEST
</div>
<div class="fixed-height">BOTTOM</div>
</div>
</div>
I'm trying to center an element in the middle of the page. I can center it just fine, but if I resize the page vertically until the view height is smaller than the centered element, the element goes offscreen vertically without a scrollbar. You can see a demonstration of the issue here:
http://codepen.io/mse/pen/BWayXV
* {
padding: 0;
margin: 0;
}
html, body {
height: 100%;
}
.outer {
text-align: center;
position: relative;
top: 50%;
transform: translateY(-50%);
}
.inner {
display: inline-block;
width: 400px;
height: 800px;
background: grey;
}
<div class="outer">
<div class="inner"></div>
</div>
I should mention that I have tried a couple of other methods of vertical centering, including flexbox, and I'm still running into the same issue. Is there a way to solve this problem with this method of vertical centering, or is there at least a vertical centering method that does not have this issue?
Try this
* {
padding: 0;
margin: 0;
}
html, body {
height: 100%;
}
.outer {
display:flex;
justify-content:center;
align-items:center;
}
.inner {
background: #ccc;
width: 400px;
height: 600px
}
<div class="outer">
<div class="inner"> I'm a block-level element centered vertically within my parent.</div>
</div>
More info: https://css-tricks.com/centering-css-complete-guide/
CSS VH center generator: http://howtocenterincss.com/
This should work
* {
padding: 0;
margin: 0;
}
html, body {
height: 100vh;
}
.outer {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.inner {
width: 400px;
height: 800px;
background: grey;
}
<div class="outer">
<div class="inner"></div>
</div>
You can try to limit the size of your inner element. If you define size by a fixed px amount it will start scrolling as soon as the screen becomes smaller than that px amount. If you are ok with changing the height of the inner element you could use vh or you can implement #media queries to decrease the size on smaller screens. Here#s an example:
.inner { height: 100vh; /* 100 view height percentage*/}
Note: The viewport-percentage lengths are relative to the size of the initial containing block and affected by the presence of scrollbars on the viewport.
I asked a question today about good and bad practises in CSS/HTML/jQuery and when it is appropriate to use jQuery to set container dimensions. I got some good answers
So, understanding that jQuery is not the best option, I decided to ask maybe some of you can give some input about this "problem"
So, I have a page put together with php. I have one header for all of my pages and content is being changed with php (I am saying this only to let you guys know that wrapping header and div in one container is not an option):
include ("header.php");
include ("$lang/$section.php");
include ("footer.php");
I have a header with fixed hight (100px + 100px margin-bottom) and after that I have a div which on screens smaller than 768px(height) I want to be no longer than the remaining space. If the screen is larger, I want my div to be
max-height: 420px;
with
padding: 100px 0;
Inside of this div I have 3 floated columns. I need them to fill the space in the parent div.
What I would usually do is- use jQuery and calculate screen height and subtract header height and all the margins and paddings. But as I've learned today, that is not a good practise.
So, to wrap it up: I NEED THE DIV TO FILL THE SPACE BETWEEN HEADER AND BOTTOM OF THE SCREEN FOR VIEWPORT HEIGHT SMALLER THAN 768px. MAX-HEIGHT FOR THIS DIV IS 420px. With jQuery it is super easy but I can't figure out the clean css way.
Maybe some of you have an idea?
Here is my fiddle, so you guys don't have to type out all of the code.
Thank you in advance!
You can use calc() and vh (viewport height).
calc() browser support: http://caniuse.com/#search=calc
vh browser support: http://caniuse.com/#search=vh
So we use calc(100vh - 200px) being 100vh the height of the viewport and 200px the height of the header.
Also, we add a media query so that when the screen is bigger than 768px height we limit the height to 420px.
Try this:
header { height: 100px; background: #ccc; margin-bottom: 100px; box-sizing: border-box; }
section { width: 100%; height: calc(100vh - 200px); padding: 50px 0; background: yellow; box-sizing: border-box; }
.col1, .col2, .col3 { float: left; width: 33%; }
.colPadding { padding: 25px; background: blue; }
.cb { width: 100%; height: 1px; clear: both; }
body {
margin: 0;
}
#media screen and (min-height: 768px) {
section {
max-height: 420px;
}
}
<header>
This is my header with 100px bottom margin
</header>
<section>
<div class="col1">
<div class="colPadding">
section with padding: 50px 0; and max-height: 420px;
</div>
</div>
<div class="col2">
<div class="colPadding">
Column 2
</div>
</div>
<div class="col3">
<div class="colPadding">
Column 3
</div>
</div>
<div class="cb"></div>
</section>
Gave it a shot with CSS3 flex-box model and screen media queries. Here is my fiddle.
I used 300px instead of 764px for the fiddle. (you can change it if you want, I just used 300px so that it's easier to test)
Applied CSS
* { box-sizing: border-box; } /* force sizing based on border */
body {
display: flex; /* flex for body since wrapping header and section is not allowed */
flex-flow: column wrap;
}
header {
height: 100px;
background: #ccc;
margin-bottom: 100px;
flex: 0 0 auto; /* make header size fixed */
}
section {
width: 100%;
max-height: 420px;
padding: 50px 0;
background: yellow;
/* to occupy remaining space */
flex: 1 1 auto;
/* for columns inside to occupy full width */
display: flex;
flex-flow: row wrap;
/* for immediate children to stretch to max height possible */
align-items: stretch;
}
.col1, .col2, .col3 {
float: left;
/* to occupy remaining width */
flex: 1 0 auto;
}
.colPadding {
padding: 25px;
background: blue;
}
.cb {
width: 100%;
height: 1px;
clear: both;
}
/* Custom CSS */
/* style to apply when the screen is less than or equal to 300px (you can change this to 768px) */
#media screen and ( max-height: 300px ){
body {
height: 100vh; /* for body to have a size of the full screen */
}
header {
margin: 0px; /* remove margin bottom */
}
section {
padding: 0px; /* remove margin bottom and top/bottom padding */
margin: 0px;
}
}
More on CSS3 flex-box here.
How can I achieve the following structure without using tables or JavaScript? The white borders represent edges of divs and aren't relevant to the question.
The size of the area in the middle is going to vary, but it will have exact pixel values and the whole structure should scale according to those values. To simplify it, I'd need a way to set "100% - n px" width to the top-middle and bottom-middle divs.
I'd appreciate a clean cross-browser solution, but in case it's not possible, CSS hacks will do.
Here's a bonus. Another structure I've been struggling with and end up using tables or JavaScript. It's slightly different, but introduces new problems. I've been mainly using it in jQuery-based windowing system, but I'd like to keep the layout out of the script and only control the size of one element (the middle one).
New way I've just stumbled upon: css calc():
.calculated-width {
width: -webkit-calc(100% - 100px);
width: -moz-calc(100% - 100px);
width: calc(100% - 100px);
}
Source: css width 100% minus 100px
You can use nested elements and padding to get a left and right edge on the toolbar. The default width of a div element is auto, which means that it uses the available width. You can then add padding to the element and it still keeps within the available width.
Here is an example that you can use for putting images as left and right rounded corners, and a center image that repeats between them.
The HTML:
<div class="Header">
<div>
<div>This is the dynamic center area</div>
</div>
</div>
The CSS:
.Header {
background: url(left.gif) no-repeat;
padding-left: 30px;
}
.Header div {
background: url(right.gif) top right no-repeat;
padding-right: 30px;
}
.Header div div {
background: url(center.gif) repeat-x;
padding: 0;
height: 30px;
}
While Guffa's answer works in many situations, in some cases you may not want the left and/or right pieces of padding to be the parent of the center div. In these cases, you can use a block formatting context on the center and float the padding divs left and right. Here's the code
The HTML:
<div class="container">
<div class="left"></div>
<div class="right"></div>
<div class="center"></div>
</div>
The CSS:
.container {
width: 100px;
height: 20px;
}
.left, .right {
width: 20px;
height: 100%;
float: left;
background: black;
}
.right {
float: right;
}
.center {
overflow: auto;
height: 100%;
background: blue;
}
I feel that this element hierarchy is more natural when compared to nested nested divs, and better represents what's on the page. Because of this, borders, padding, and margin can be applied normally to all elements (ie: this 'naturality' goes beyond style and has ramifications).
Note that this only works on divs and other elements that share its 'fill 100% of the width by default' property. Inputs, tables, and possibly others will require you to wrap them in a container div and add a little more css to restore this quality. If you're unlucky enough to be in that situation, contact me and I'll dig up the css.
jsfiddle here: jsfiddle.net/RgdeQ
Enjoy!
You can make use of Flexbox layout. You need to set flex: 1 on the element that needs to have dynamic width or height for flex-direction: row and column respectively.
Dynamic width:
HTML
<div class="container">
<div class="fixed-width">
1
</div>
<div class="flexible-width">
2
</div>
<div class="fixed-width">
3
</div>
</div>
CSS
.container {
display: flex;
}
.fixed-width {
width: 200px; /* Fixed width or flex-basis: 200px */
}
.flexible-width {
flex: 1; /* Stretch to occupy remaining width i.e. flex-grow: 1 and flex-shrink: 1*/
}
Output:
.container {
display: flex;
width: 100%;
color: #fff;
font-family: Roboto;
}
.fixed-width {
background: #9BCB3C;
width: 200px; /* Fixed width */
text-align: center;
}
.flexible-width {
background: #88BEF5;
flex: 1; /* Stretch to occupy remaining width */
text-align: center;
}
<div class="container">
<div class="fixed-width">
1
</div>
<div class="flexible-width">
2
</div>
<div class="fixed-width">
3
</div>
</div>
Dynamic height:
HTML
<div class="container">
<div class="fixed-height">
1
</div>
<div class="flexible-height">
2
</div>
<div class="fixed-height">
3
</div>
</div>
CSS
.container {
display: flex;
}
.fixed-height {
height: 200px; /* Fixed height or flex-basis: 200px */
}
.flexible-height {
flex: 1; /* Stretch to occupy remaining height i.e. flex-grow: 1 and flex-shrink: 1*/
}
Output:
.container {
display: flex;
flex-direction: column;
height: 100vh;
color: #fff;
font-family: Roboto;
}
.fixed-height {
background: #9BCB3C;
height: 50px; /* Fixed height or flex-basis: 100px */
text-align: center;
display: flex;
flex-direction: column;
justify-content: center;
}
.flexible-height {
background: #88BEF5;
flex: 1; /* Stretch to occupy remaining width */
text-align: center;
display: flex;
flex-direction: column;
justify-content: center;
}
<div class="container">
<div class="fixed-height">
1
</div>
<div class="flexible-height">
2
</div>
<div class="fixed-height">
3
</div>
</div>
The usual way to do it is as outlined by Guffa, nested elements. It's a bit sad having to add extra markup to get the hooks you need for this, but in practice a wrapper div here or there isn't going to hurt anyone.
If you must do it without extra elements (eg. when you don't have control of the page markup), you can use box-sizing, which has pretty decent but not complete or simple browser support. Likely more fun than having to rely on scripting though.
Maybe I'm being dumb, but isn't table the obvious solution here?
<div class="parent">
<div class="fixed">
<div class="stretchToFit">
</div>
.parent{ display: table; width 100%; }
.fixed { display: table-cell; width: 150px; }
.stretchToFit{ display: table-cell; vertical-align: top}
Another way that I've figured out in chrome is even simpler, but man is it a hack!
.fixed{
float: left
}
.stretchToFit{
display: table-cell;
width: 1%;
}
This alone should fill the rest of the line horizontally, as table-cells do. However, you get some strange issues with it going over 100% of its parent, setting the width to a percent value fixes it though.
We can achieve this using flex-box very easily.
If we have three elements like Header, MiddleContainer and Footer. And we want to give some fixed height to Header and Footer. then we can write like this:
For React/RN(defaults are 'display' as flex and 'flexDirection' as column), in web css we'll have to specify the body container or container containing these as display: 'flex', flex-direction: 'column' like below:
container-containing-these-elements: {
display: flex,
flex-direction: column
}
header: {
height: 40,
},
middle-container: {
flex: 1, // this will take the rest of the space available.
},
footer: {
height: 100,
}
what if your wrapping div was 100% and you used padding for a pixel amount, then if the padding # needs to be dynamic, you can easily use jQuery to modify your padding amount when your events fire.
I had a similar issue where I wanted a banner across the top of the screen that had one image on the left and a repeating image on the right to the edge of the screen. I ended up resolving it like so:
CSS:
.banner_left {
position: absolute;
top: 0px;
left: 0px;
width: 131px;
height: 150px;
background-image: url("left_image.jpg");
background-repeat: no-repeat;
}
.banner_right {
position: absolute;
top: 0px;
left: 131px;
right: 0px;
height: 150px;
background-image: url("right_repeating_image.jpg");
background-repeat: repeat-x;
background-position: top left;
}
The key was the right tag. I'm basically specifying that I want it to repeat from 131px in from the left to 0px from the right.
In some contexts, you can leverage margin settings to effectively specify "100% width minus N pixels". See the accepted answer to this question.