3 divs in a container div, make one of them expand if another is cancelled out - css

I have 3 divs in a parent div which looks like this:
<div id="maincontent>
<div class="left"></div>
<div class="mainbody"></div>
<div class="right"></div>
</div>
The website is 1000px wide.
What I need is to keep the .mainbody div at a minimum of 570px, but have it expand if one of the other 2 divs is removed from the page, which are each given 215px width.
All 3 divs are also floated left.
I tried using min-width and max-width on .mainbody but it doesn't really work. Any other ideas?
My current CSS:
#maincontent {
width: 100%;
overflow: hidden;
}
.left, .right, .mainbody {
float: left;
}
.left, .right {
width: 215px;
}
.mainbody {
width: 570px;
}

CSS Only Solution 1
This assumes the question was accurate in stating "if one of the other 2 divs is removed from the page."
See this fiddle which uses the following code, the key part of which is the :first-child and :last-child change based off your html structure change that you mention. When the left is deleted, the mainbody becomes the first-child and when the right is deleted the mainbody becomes the last-child, so you reset the width if such occurs.
Key CSS
.mainbody {
width: 570px;
float: left;
}
.mainbody:first-child,
.mainbody:last-child {
width: 785px;
}
.left,
.right {
width: 215px;
float: left;
}
CSS Only Solution 2
This accounts for the div remaining, but having no content and being zero width (which is apparently what the situation actually is).
There is a CSS only solution (see this fiddle), but it requires one to restructure the HTML order of the elements and to adjust how they are floated.
Needed HTML Structure (mainbody is last)
<div id="maincontent1">
<div class="left"></div>
<div class="right"></div>
<div class="mainbody"></div>
</div>
Key CSS
.mainbody {
min-width: 570px;
overflow: hidden; /* this triggers expansion between left/right */
}
.left {
width: 215px; /* this is assumed to be zero if no content in div */
float: left;
}
.right {
width: 215px; /* this is assumed to be zero if no content in div */
float: right;
}

Just ad and event to the function. .click(), .ready() etc
if($('.right').is(':visible') == false){
$('.mainbody').width(785+'px');
}
else{ }
or use .size() / .length()

Related

Responsive layout: middle content of centered div with fixed width must become the right column without overflowing

I have a centered div with a width of 700px, with a middle part that must become a right column when viewport is > to some width. I used absolute positioning for that purpose but like this column must be responsive, I don't know its width.
First, I would like to know what is the rule for how behave the width of absolute positioned elements which are out of their relative parent. Absolute positioning should use the width of their relative parent but when the element is out of that parent, the element is shrinked. If there is a word without space, it extends the element accordingly and everything follows. I don't understand how it works and how predict that behavior. It's the same when that element without width is supposed to start overflowing out of its parent.
Then, is there a way to make this column fills the right until it reaches the limit of the window without overflowing (with a little margin-right)? If I fix a big width on that column assuming it will be the max-width that column will achieve in the biggest viewport and use the overflow property to hide what is out of the window, of course, the absolute positioned element is just cut.
I really don't know how to make that responsive because it seems like absolute positioning removes the element from the flow, it is not made for my purpose. Of course, no JS, please. And it must support Internet Explorer since IE8.
The only solution that comes to my mind is to duplicate the content and use display:none/block to switch blocks with media queries but it means redundant code. I tried with a complicated display:table layout until I found that colspan doesn't exist.
(Just so you know, I have a left column too to take into consideration, the reason why I am using a three columns display:table layout. If that's relevant.)
Here is a simplified code:
I didn't put media queries but the aside-on-small-screen is obviously what it should look like on small screens, replacing the aside selector.
main{
overflow:hidden;
}
.colMain{
background-color:green;
margin-left:auto;
margin-right:auto;
position:relative;
width:300px;
}
.aside{
background-color:red;
position:absolute;
top:0px;
left:320px;
}
.aside-on-small-screen{
background-color:red;
}
<main>
<div class="colMain">
<div>stuff</div>
<div class="aside">aside that must extend all the way to the right until it reaches the window limit</div>
<div>stuff</div>
</div>
</main>
Thank you.
Used flexbox and assigned aside a percentage width. The details are in the CSS portion of Snippet.
Flexbox
justify-content: space-between
order
flex-shrink, flex-grow, flex-basis
Relative units of measurement
Viewport width/height vw and vh
Percentage
em
/* Optional Defaults and Resets */
* {
-ms-box-sizing: border-box;
box-sizing: border-box;
}
html {
font: 400 10px/1 Arial;
width: 100%;
height: 100%;
}
/*,
*:before,
*:after {
box-sizing: inherit;
margin: 0;
padding: 0;
border: none;
}*/
body {
font: inherit;
font-size: 160%;
/* background: rgba(0, 0, 0, .2);*/
line-height: 1;
overflow: visible;
width: 100%;
height: 100%;
}
/* Demo Styles */
/* All outlines and backgrounds are for presentational purposes */
/* vw/vh viewport width/height 1vw/vh = 1% of viewport width/height */
main {
overflow: hidden;
/* width: 100vw;
height: 100vh;
background: rgba(0, 0, 255, .2);*/
width: 100%;
height: 100%;
min-height: 35em;
display: table;
}
/* Flexbox layout will automatically keep .aside to the right with the */
/* property justify-content: space-between; which keeps the max amount */
/* of even space between flex-items (which is .stuff and .aside) */
.colMain {
/* display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: space-between; */
background-color: green;
margin-left: auto;
margin-right: auto;
position: relative;
min-width: 99%;
min-height: 99%;
padding: 1em;
display: table-row;
width: 700px;
}
/* Removed absolute positioning in favor of flexbox and a percentage */
/* width. .aside will start dis-proportionally expanding while the viewport */
/* expands. The two columns on the right while begin to shrink in response */
/* to.aside's expansion. All this stretching and shrinking happens when the */
/* elements are at 210px or more (210 is 30% of 700px). This behavior is */
/* accomplished by using flex-shrink, flex-grow, and flex-basis */
.aside {
display: table-cell;
background-color: red;
position: absolute;
top: 1em;
right: 0;
left: 70%;
/* order: 3; */
min-width: 30%;
max-width: 500px;
min-height: 100%;
/* flex-grow: 1;
flex-basis: 210px;*/
outline: 2px solid #7c1b38;
padding: 5px;
}
.aside-on-small-screen {
background-color: red;
}
.stuff {
outline: 2px dotted white;
width: 30%;
max-width: 210px;
min-height: 100%;
position: absolute;
/* flex-shrink: 1;
flex-basis: 210px; */
display: table-cell;
}
#col1 {
left: 1em;
top: 1em;
}
#col2 {
left: 36%;
top: 1em;
}
/*.stuff:first-of-type {
order: 1;
}
.stuff:last-of-type {
order: 2; */
}
/* The HTML shows that the second column (the second .stuff) would be */
/* in-between .aside and the edge of .colMain. Instead of moving it out of */
/* the way in markup (HTML), I used the flexbox property, order. */
<main>
<div class="colMain">
<div id="col1" class="stuff">stuff</div>
<div class="aside">aside that must extend all the way to the right until it reaches the window limit</div>
<div id="col2" class="stuff">stuff</div>
</div>
</main>
There are three problems in one:
First problem.
How to transform a middle content
<div class="wrapper">
<div>stuff</div>
<div class="aside">Middle content</div>
<div>stuff</div>
</div>
in a right column that expends to the right without overflowing out of the window, when the rest of the past column "wrapper" must be a centered column of fixed width.
<div class="colLeft"></div>
<div class="wrapper" style="text-align:center; width:700px;">
<div>stuff</div>
<div>stuff</div>
</div>
<div class="aside">Middle content now to the right</div>
Absolute positioning doesn't help because without fixed sizes (% or px), it is out of the flow and the content of variable width won't adapt to the situation (and overflow).
This can be easily solved with display table.
Second problem.
Display table/table-cell leads to the second problem.
To make three "columns" with display:table-cell, order is really important. That means the "aside" div must be the last element of its column (the wrapper column in my first snippet) in order to make it an independent cell of a row put to the right. If you don't have to worry about this story of middle content and you just have to switch a content at the end of a div to the right or a content at the beginning to the left, it's already over.
You just have to style colLeft, wrapper and aside of my second snippet with display:table-cell and use another global wrapper with display:table and some other styles like table-layout:fixed and width:100% to do the trick. With a media queries for small screen, you just have to hide the colLeft with display:none.
But if you need that middle content to be a middle content nonetheless on small screens and a right column on large screens, it's a different case.
This can be solved with anonymous table objects and table-header/footer/row-group.
With table-header/footer/row-group, you can reorganize your rows so you can put the "aside" at the end to transform it in an independent cell on large screens and place it in the middle with table-row-group on small screens:
.header{
background-color:green;
display:table-header-group;
}
.footer{
background-color:green;
display:table-footer-group;
}
.aside{
background-color:red;
display:table-row-group;
}
<div class="header">stuff</div>
<div class="footer">stuff</div>
<div class="aside">Middle content</div>
Third problem.
The hardest problem is the centered "column" of fixed width. With table-xxx-group, it is forbidden to put a wrapper around the table-header-group and table-footer-group to set a width of 700px because table-group are row elements and the wrapper will automatically becoming a table object, excluding the "aside" that won't be able to insert itself in the middle with its table-row-group style on small screens.
Without putting a wrapper around the "stuff", you won't be able to control the width of the created anonymous cell on large screens because you can't style something anonymous. So it takes a width of 1/3 like each cell.
main{
display:table;
table-layout: fixed;
width:100%;
}
.colLeft{
background-color:yellow;
display:table-cell;
}
.header,.footer{
background-color:green;
/*no display style > it will create an anonymous cell
object around the header/footer elements*/
}
.aside{
background-color:red;
display:table-cell;
}
<main>
<div class="colLeft"></div>
<div class="header">stuff</div>
<div class="footer">stuff</div>
<div class="aside">Middle content now to the right</div>
</main>
The solution is to use table-column-group/table-column. You will be able to style your columns and set a width to the middle column even though it is determined anonymously.
The solution
Small screens
.rowTabled{
display:table;
table-layout: fixed;
width:100%;
}
.header{
background-color:green;
display:table-header-group;
}
.footer{
background-color:green;
display:table-footer-group;
}
.aside{
background-color:red;
display:table-row-group;
}
.colLeft, .colgroup{
display:none;
}
<main>
<div class="colgroup">
<div class="colCol left"></div>
<div class="colCol middle"></div>
<div class="colCol right"></div>
</div>
<div class="rowTabled">
<div class="colLeft"></div>
<div class="header">stuff</div>
<div class="footer">stuff</div>
<div class="aside">asideeeeeeeeeeeex eeeeee eeeeeeeee eeeeeeeeeeeeee</div>
</div>
</main>
Large screens
main{
display:table;
table-layout: fixed;
width:100%;
}
.colgroup{
display:table-column-group;
}
.colCol{
display:table-column;
}
.middle{
background-color:green;
width:100px;
}
.left,.right{
background-color:yellow;
}
.rowTabled{
display:table-row;
}
.colLeft{
display:table-cell;
}
.aside{
background-color:red;
display:table-cell;
}
<main>
<div class="colgroup">
<div class="colCol left"></div>
<div class="colCol middle"></div>
<div class="colCol right"></div>
</div>
<div class="rowTabled">
<div class="colLeft"></div>
<div class="header">stuff</div>
<div class="footer">stuff</div>
<div class="aside">asideeeeeeeeeeeex eeeeee eeeeeeeee eeeeeeeeeeeeee</div>
</div>
</main>

How can I ensure that a div without content will get the height of the parent div?

i am trying to create to divs width the outer container set to 1000px and the inner left and right container to 50% each.
Now i have used this code
.leftNav {
#include span-columns( 5 of 10);
background-color:silver;
color:white;
}
.rightNav {
#include span-columns( 5 of 10);
background-color:silver;
color:white;
}
Now somehow if i don't put anything on left nav the right nav takes full 100% width.
How can i set the leftnav or rightnav to maintain at least 50% width even if they are empty?
thanks.
This "issue" doesn't come from Neat, but from CSS itself. To be shown, an empty element require to have a height.You can use one of the following tricks:
Put in your div
Set a height on your div
Set a padding on your div
Here's another trick I like, if you're not using the :after pseudo-element on these div:
.leftNav:after,
.rightNav:after {
content: '.'; // dot will force its parent to have a height
opacity: 0; // dot is hidden
}
You could use css tables.
Setting display:table-cell on both the left and right divs will ensure that each one gets equal height (ie the height of the greater of the two)
FIDDLE
.container {
width: 100%;
display: table;
}
.left {
width: 50%;
display: table-cell;
background: silver;
}
.right {
width: 50%;
display: table-cell;
background: tomato;
}
<div class="container">
<div class="left"></div>
<div class="right">some text</div>
</div>
You can also do:
.leftNav:after,
.rightNav:after {
content: '';
display: inline-block;
}
Then you don't have to deal with any dots which could be confusing to someone else looking at your code.

Simulating 2 columns for 4 successive divs

I have 4 successive divs:
<div class="container">
<div class="child">A</div>
<div class="child">B</div>
<div class="child">C</div>
<div class="child">D</div>
</div>
Assuming each child div has varying content, of different heights, and a margin added for clarity, it displays as follows:
Without changing the HTML in any way (no adding classes to the divs, no adding intermediary column divs), I would like to achieve this layout:
The order in which the divs are placed does not matter much.
I've tried things along the lines of:
.child { width: 50%; }
.child:nth-child(even) { float: left; }
.child:nth-child(odd) { float: right; }
But the alignnments are off. Does any CSS wizard have an idea?
Does this work?
DEMO
.container {
width:220px; /* (child width)x2 + (child margin)x4 */
}
.child {
margin:5px;
background-color:#FF0080;
width:100px;
}
.child:nth-child(even) {
float: left;
}
.child:nth-child(odd) {
float: right;
}
Well you could use CSS columns, which has good partial support across browsers (primarily prefixed though), but full support is not so great.
Give them a try:
.container {
-webkit-column-width: 250px;
-moz-column-width: 250px;
column-width: 250px;
width: 520px;
background: yellow;
}
.child {
background: red;
margin-bottom: 10px;
display: inline-block;
width: 100%;
}
Take a look at this jsfiddle for a demonstration: http://jsfiddle.net/xwwe3/ (complete with My First Colours to demonstrate what is happening).
The columns are set to 250px wide, which I found the .child didn't obey until given display: inline-block; width: 100%;. Then the width of .container is set to 520px to give the columns a gutter width of 10px with two columns (250 * 2 + 10 = 520)
So depending on whether you think the support is acceptable for your use case is up to you. Tweaking the heights of the .child elements does make some weird stuff happen, but I'd suggest you read up further on CSS columns and try and work out what is going there.
Alternatively, jQuery masonry is a popular way of achieving this.

HTML/CSS Div placing

Yo. There's a tendency in placing divs to follow each other vertically, but what i'm trying to accomplish right now is to is basically to place a number of divs (two) inside a parent div like so:
<div id='parent'><div id='onediv'></div> <div id='anotherone'></div> </div>
And i'd like to place 'anotherone' just to the right of 'onediv'. Sadly, float:right is pretty much ruining the layout with the divs popping out of their parent divs and whatnot. Any suggestions are welcome.
Edit: It might be worth noting that the parent div and 'anotherone' has no height elements at all, with 'onediv' planned to be thought as the "height support" div, allowing the contents of 'anotherone' to make the parent div larger at will.
Edit again: Here's the CSS for the specified stuff:
.parent
{
width: 90%;
margin: 0 auto;
border:solid black 1px;
}
.firstchild
{
width: 20%;
margin: 5px;
border: solid black 1px;
height: 180px;
}
.secondchild
{
width: 60%;
border:solid black 1px;
margin: 5px;
}
You can float both inner divs and give the outer div an overflow so that it grows with the inner divs.
Example:
#parent {
overflow: hidden;
}
#parent div {
width: 50%;
float: left;
}
Try this:
<div id="parent">
<div id="onediv" style="float:left;"></div>
<div id="anotherone" style="float:left;"></div>
<div style="clear:both;"></div>
</div>
I think this is what you want (note the re-ordering of DOM elements):
<div id="parent">
<div id="anotherone"></div>
<div id="onediv"></div>
</div>
/*CSS*/
#anotherone{
float:right;
width:50%;
}
#onediv{
float:left;
width:50%;
}
Note, if this is what you want, IE6 will still mess it up. ;-)
You certainly need to specify a width as indicated in #Kevin's answer to get the layout you described, simply specifying float left/right will not have the desired effect. Try specifying the width in pixels rather than a percentage. Failing that or if that's not appropriate for you, I think you possibly need to specify the width of the outer div (through css if you like).
#onediv { float: left; width: 50%; } #anotherone { float: right; width: 50%; }
Just use the <span> tag. Its the equivalent of except it doesn't start a new row.

Split Div Into 2 Columns Using CSS

I have been attempting to split a div into two columns using CSS, but I have not managed to get it working yet. My basic structure is as follows:
<div id="content">
<div id="left">
<div id="object1"></div>
<div id="object2"></div>
</div>
<div id="right">
<div id="object3"></div>
<div id="object4"></div>
</div>
</div>
If I attempt to float the right and left divs to their respective positions (right and left), it seems to ignore the content div's background-color. And other code that I have tried from various websites doesn't seem to be able to translate to my structure.
Thanks for any help!
This works good for me. I have divided the screen into two halfs: 20% and 80%:
<div style="width: 20%; float:left">
#left content in here
</div>
<div style="width: 80%; float:right">
#right content in there
</div>
When you float those two divs, the content div collapses to zero height. Just add
<br style="clear:both;"/>
after the #right div but inside the content div. That will force the content div to surround the two internal, floating divs.
Another way to do this is to add overflow:hidden; to the parent element of the floated elements.
overflow:hidden will make the element grow to fit in floated elements.
This way, it can all be done in css rather than adding another html element.
None of the answers given answer the original question.
The question is how to separate a div into 2 columns using css.
All of the above answers actually embed 2 divs into a single div in order to simulate 2 columns. This is a bad idea because you won't be able to flow content into the 2 columns in any dynamic fashion.
So, instead of the above, use a single div that is defined to contain 2 columns using CSS as follows...
.two-column-div {
column-count: 2;
}
assign the above as a class to a div, and it will actually flow its contents into the 2 columns. You can go further and define gaps between margins as well. Depending on the content of the div, you may need to mess with the word break values so your content doesn't get cut up between the columns.
The most flexible way to do this:
#content::after {
display:block;
content:"";
clear:both;
}
This acts exactly the same as appending the element to #content:
<br style="clear:both;"/>
but without actually adding an element. ::after is called a pseudo element. The only reason this is better than adding overflow:hidden; to #content is that you can have absolute positioned child elements overflow and still be visible. Also it will allow box-shadow's to still be visible.
For whatever reason I've never liked the clearing approaches, I rely on floats and percentage widths for things like this.
Here's something that works in simple cases:
#content {
overflow:auto;
width: 600px;
background: gray;
}
#left, #right {
width: 40%;
margin:5px;
padding: 1em;
background: white;
}
#left { float:left; }
#right { float:right; }
If you put some content in you'll see that it works:
<div id="content">
<div id="left">
<div id="object1">some stuff</div>
<div id="object2">some more stuff</div>
</div>
<div id="right">
<div id="object3">unas cosas</div>
<div id="object4">mas cosas para ti</div>
</div>
</div>
You can see it here: http://cssdesk.com/d64uy
Make children divs inline-block and they will position side by side:
#content {
width: 500px;
height: 500px;
}
#left, #right {
display: inline-block;
width: 45%;
height: 100%;
}
See Demo
You can use flexbox to control the layout of your div element:
* { box-sizing: border-box; }
#content {
background-color: rgba(210, 210, 210, 0.5);
border: 1px solid #000;
padding: 0.5rem;
display: flex;
}
#left,
#right {
background-color: rgba(10, 10, 10, 0.5);
border: 1px solid #fff;
padding: 0.5rem;
flex-grow: 1;
color: #fff;
}
<div id="content">
<div id="left">
<div id="object1">lorem ipsum</div>
<div id="object2">dolor site amet</div>
</div>
<div id="right">
<div id="object3">lorem ipsum</div>
<div id="object4">dolor site amet</div>
</div>
</div>
Best way to divide a div vertically --
#parent {
margin: 0;
width: 100%;
}
.left {
float: left;
width: 60%;
}
.right {
overflow: hidden;
width: 40%;
}
Pure old school CSS
I know this post is old, but if any of you still looking for a simpler solution.
#container .left,
#container .right {
display: inline-block;
}
#container .left {
width: 20%;
float: left;
}
#container .right {
width: 80%;
float: right;
}
If you don't care old browser and need a simple way.
#content {
display: flex;
}
#left,
#right {
flex: 50%;
}
Floats don't affect the flow. What I tend to do is add a
<p class="extro" style="clear: both">possibly some content</p>
at the end of the 'wrapping div' (in this case content). I can justify this on a semantic basis by saying that such a paragraph might be needed. Another approach is to use a clearfix CSS:
#content:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
#content {
display: inline-block;
}
/* \*/
* html #content {
height: 1%;
}
#content {
display: block;
}
/* */
The trickery with the comments is for cross-browser compatibility.
This is best answered here Question 211383
These days, any self-respecting person should be using the stated "micro-clearfix" approach of clearing floats.
Make font size equal to zero in parent DIV.
Set width % for each of child DIVs.
#content {
font-size: 0;
}
#content > div {
font-size: 16px;
width: 50%;
}
*In Safari you may need to set 49% to make it works.
Divide a division in two columns is very easy, just specify the width of your column better if you put this (like width:50%) and set the float:left for left column and float:right for right column.

Resources