I've done the layout for my website which seems to be working fine, but I wanted to make sure I didn't overcomplicated it or used rubbish technique.
So this is how it works, within the DIV I have another div that is a table, and within it I have another 3 divs that are table-cells
<div id="container-main">
<div id="columns-3">
<div class="main-col-left-s"></div>
<div class="main-col-center-s"></div>
<div class="main-col-right-s"></div>
<hr>
<div class="main-col-left-s"></div>
<div class="main-col-center-s"></div>
<div class="main-col-right-s"></div>
</div>
</div>
Each column contains various elements (something like pinterest website).
Now, when I resize, after reaching certain width, I want only 2 colums to be visible, and later only one. While stacking from 3 to 1 is not difficult as it'll happen automatically, the issue was from 3 to 2 columns, so what I did is I gave the middle column display: none property when screen gets to small, so it's not shown (and on the backend side I assume data will be transferred to visible column if the current one is hidden).
Is this solution rubbish and there is far better one, or it'll do?
I do not want to have situation when in one row I have 2 columns and in the next one only one, so this CAN'T happen:
ǀdataǀdataǀ
ǀdataǀ ǀ
-----------
ǀdataǀdataǀ
ǀdataǀ ǀ
but it should always be:
ǀdataǀdataǀ
ǀdataǀdataǀ
-----------
ǀdataǀdataǀ
ǀdataǀdataǀ
Thanks for clarifying your question. Basically, a css-only solution is possible and recommended. It'd be easy to achieve with CSS3 and the new Flexible Box Model, however, browser support is not evenly implemented -even major browsers. So, if you want to support at least all major browsers I'd suggest you stick to the Traditional Box Model which is what my answer is based on.
The solution is quite straight forward:
One block div that serves as the container element
Multiple divs (inside the container div) displayed inline-block which would be your "table cells"
The html structure would be something like below:
<div class="container">
<div class="box"></div>
<div class="box"></div>
</div>
which would be styled in the following manner...
div.container{
width:100%;
display:block;
font-size:0;
}
div.box{
width:30%;
font-size:40px;
margin:20px 0 0 2.5%;
display:inline-block;
}
This will display 3 boxes aligned horizontally (in one row) in a responsive manner.The font-size:0 declaration is a work-around for the inline-block font spacing issue, you can read more about it if you google it, there are other ways to approach this problem.
Now, in order to display only 2 boxes in one row when the screen width is limited, you can use media queries, as below...
#media all and (max-width:950px){
div.box{
width:47%;
margin:20px 0 0 2%;
}
of course...you can change the max-width constraint to something else. Finally, I've put together a fiddler below in order to add some visuals...
div.container{
width:100%;
height:100%;
padding-bottom:40px;
display:block;
background-color:#eee;
font-family:Arial;
font-size:0;
}
div.box{
color:#666;
background-color:#fff;
width:30%;
font-size:40px;
font-weight:bold;
margin:20px 0 0 2.5%;
line-height:200px;
display:inline-block;
border-radius:6px;
box-shadow:0 4px 5px #ccc;
text-align:center;
*display:inline;
zoom:1;
}
#media all and (max-width:950px){
div.box{
width:47%;
margin:20px 0 0 2%;
}
}
<div class="container">
<div class="box">1</div>
<div class="box">2</div>
<div class="box">3</div>
<div class="box">4</div>
<div class="box">5</div>
<div class="box">6</div>
<div class="box">7</div>
<div class="box" style="height:150px">8</div>
<div class="box">9</div>
<div class="box">10</div>
<div class="box">11</div>
</div>
Notice in the example above that intentionally set the height of box 8
You need to use media queries. Try something like this in your css file:
.main-col-left-s, .main-col-center-s, .main-col-right-s {
width: 100%;
}
#media (min-width: 600px) {
.main-col-left-s, .main-col-center-s, .main-col-right-s {
width: 50%;
}
}
#media (min-width: 960px) {
.main-col-left-s, .main-col-center-s, .main-col-right-s {
width: 33.33%;
}
}
you can also use the float: left property of css, for your table cells, that makes what you wished for
Related
I am one of those using tables for everything, but now when some table attributes has been deprecated I feel obligated to switch to divs CSS so I have a simple layout table I need to change to divs and I cannot make it to work as I need.
The 3 column layout must have: left column 200px width and 100% height, right column must be also 200px width and 100% height but the middle column I will put content there so it must be 100% width that means if the screen is 1200px it will take 200px to left column 200px to left column and middle content column will auto-be 800px and so on, also with 100% height.
Here is what I did but cannot make it to work:
<style type="text/css">
.table {display:table;width:100%;min-width:1000px;height:200px;}
.row {display:table-row;}
.columna {display:table-cell;background:#666666;width:200px; float:left; margin-left:0px; height:100%;}
.columnb {display:table-cell;background:#cccccc;width:100%;height:100%;}
.columnc {display:table-cell;background:#666666;width:200px;float:right;margin-right:0px;height:100%;}
</style>
<div class="table">
<div class="row">
<div class="columna">a left column</div>
<div class="columnb">b middle column</div>
<div class="columnc">c right column</div>
</div>
</div>
For some reason I cannot understand the middle column is not using the correct height, its bigger I don´t know why. Also I cannot make it to respect the 100% height neither.
Any ideas?
EDIT
here is a demo Fiddle
https://jsfiddle.net/4xcg1eng/
The only way I can fix it is with div inside divs, almost the same crap as using tables but tables are even easier. I think those saying divs are best are wrong
I have created a working model using the display:table property.
html, body {
height:100%;
}
.table {
display:table;
width:100%;
height:100%;
}
.row {
display:table;
width: 100%;
height: 100%;
}
.columna {
background:#666666;
display: table-cell;
text-align: center;
vertical-align:middle;
width: 200px;
}
.columnb {
background:#cccccc;
display: table-cell;
text-align: center;
vertical-align:middle;
}
.columnc {
background:#666666;
width:200px;
display: table-cell;
text-align: center;
vertical-align:middle;
}
<div class="table">
<div class="row">
<div class="columna">a left column</div>
<div class="columnb">b middle column</div>
<div class="columnc">c right column</div>
</div>
</div>
But I would recommend you look at using a grid layout similar to bootstrap. If you are used to working in tables, the grid system should resonate a little with you.
Did some edits to it in a fiddle here and got it working, let me know if this is what you were looking for :)
https://jsfiddle.net/fe0ftxh0/
The CSS looks like this now
<style type="text/css">
.table {width:100%;height:200px;}
.columna {background:#666666;width:20%;float:left;height:100%;}
.columnb {background:#cccccc;width:60%;float:left;height:100%;}
.columnc {background:#666666;width:20%;float:left;height:100%;}
</style>
I updated your fiddle here with a working solution:
https://jsfiddle.net/4xcg1eng/17/
You can achieve exactly what you are looking for without using display:table. The trick is the order in which you float your elements. Your markup needs to specify column a and column c above column b.
<div class="table">
<div class="row">
<div class="columna">a left column</div>
<div class="columnc">c right column</div>
<div class="columnb">b middle column</div>
</div>
</div>
specify column a to float left, column c to float right, and add left and right margins equal to the widths of columns a and c to column b.
your css gets much simpler:
.table { height: 200px;}
.row {height: 100%; }
.columna {background:#666666; width:200px; float:left; height:100%;}
.columnb {background:#cccccc; height:100%; margin-left: 200px; margin-right: 200px;}
.columnc {background:#666666; width:200px; float:right; height:100%;}
You do not need to specify 100% width for divs -- they are automatically 100% width unless you specify otherwise.
I agree that using floating DIVs to do column-style layout is hard to wrap your head around if you are used to table layout. But once you get used to it, it will free you from the being constrained by the table grid, especially when you need to reconfigure your layout for various sized screens.
You may want to consider using the flexible box model to achieve what you are after. This is the kind of situation it is well suited for.
What I am trying to do is create 2 or more text boxes, side by side rather than stacked vertically.
I have tried using floats, which is fine for 2 boxes side by side, but isn't good for 3. Also, floats make the page look messy on mobile.
Is there any other way to do this?
You can use the CSS property display: inline-block but you should also use Media Queries to adjust the width of the inline boxes depending on the screen size of the device reading the page.
You can also use a framework such as Twitter Bootstrap which has a build in responsive framework based on a grid system.
.box-container{
display:inline-block;
width:450px;
}
.box{
display:block;
width:33%;
float:left;
background:#000;
color:#fff;
margin-left:0.3%;
text-align:center;
}
<div class="box-container">
<div class="box">box</div>
<div class="box">box</div>
<div class="box">box</div>
</div>
You might even don't media queries:
Fiddle 1
.box {
display: inline-block;
width: 180px;
height: 180px;
background: #ddd;
}
And Fiddle 2 with floats.
And just the size of result window: what's wrong with it? What is currently not working properly and what are you trying to achieve (both on desktop and mobile)?
How can we create a 3-column layout, Fluid - Fixed - Fluid, as shown in the picture below. Is there more than one option? If so, what are the pros and cons of each?
Note: Feel free to add more answers if they are different to the three I've already posted. Also, I know this has been asked before, but I can't find anywhere with all three answers that is up to date.
Options
There are three four ways of doing this, all using different CSS and having different levels of complexity and browser compatibility. In all three four, we start with three divs which create our three columns.
Method 1 - Most compatible, longest code.
Method 2 - Medium compatible, medium code.
Method 3 - Least compatible, shortest code.
All three four will produce what we want, as shown in the screenshot below:
EDIT:
There is a Method 4, suggested by vals, which uses the CSS Flexbox Model. See his answer for details.
Method 1 - Extra Inner div
Insert an extra div inside the left and right fluid columns.
Pros: This method has the best compatibility, even back to IE6.
Cons: We have to insert an extra div, and the CSS is the longest of all three methods.
Working Fiddle
HTML:
<div class="wrap">
<div class="fluid left">
<div class="inner">
Fluid Box
</div>
</div>
<div class="fixed">
Fixed Box
</div>
<div class="fluid right">
<div class="inner">
Fluid Box
</div>
</div>
</div>
CSS:
.wrap {
overflow:hidden;
}
.wrap div {
height:300px;
float:left;
}
.fixed {
background-color:lightblue;
width:500px;
}
.fluid {
background-color:orange;
width:50%;
}
.left {
margin-left:-250px;
}
.left .inner {
margin-left:250px;
}
.right {
margin-right:-250px;
}
.right .inner {
margin-right:250px;
}
Method 2 - Use box-sizing CSS Styling
If you are willing to use some CSS3, you can set the left and right fluid columns to have box-sizing:border-box;. This lets use take the margin from the Method 1's inner divs, and place it as padding in the outer divs, without interfering with their widths. box-sizing isn't supported by all older browsers though.
Pros: The code is cleaner, because we don't have an extra inner div. The CSS is slightly cleaner as well.
Cons: Browser compatibility. We are going to lose IE6 and IE7.
Working Fiddle
HTML:
<div class="wrap">
<div class="fluid left">
Fluid Box
</div>
<div class="fixed">
Fixed Box
</div>
<div class="fluid right">
Fluid Box
</div>
</div>
CSS:
.wrap {
overflow:hidden;
}
.wrap div {
height:300px;
float:left;
}
.fixed {
background-color:lightblue;
width:500px;
}
.fluid {
background-color:orange;
width:50%;
-webkit-box-sizing:border-box;
-moz-box-sizing:border-box;
box-sizing:border-box;
}
.left {
margin-left:-250px;
padding-left:250px;
}
.right {
margin-right:-250px;
padding-right:250px;
}
Method 3 - Use calc() for width
Following the trend, we can use a method which involves even newer CSS, for even cleaner but less backward-compatible code. If we calculate the width of the left and right fluid columns using width:calc(% - px), we don't need box-sizing, or extra divs.
Pros: The CSS is even cleaner and shorter than in method 2.
Cons: Browser compatibility. Not only do we lose older versions of IE, we lose all but the very newest versions of most mobile browsers..
Working Fiddle
HTML:
<div class="wrap">
<div class="fluid">
Fluid Box
</div>
<div class="fixed">
Fixed Box
</div>
<div class="fluid">
Fluid Box
</div>
</div>
CSS:
.wrap div {
height:300px;
float:left;
}
.fixed {
background-color:lightblue;
width:500px;
}
.fluid {
background-color:orange;
width:-webkit-calc(50% - 250px);
width:-moz-calc(50% - 250px);
width:calc(50% - 250px);
}
Summary
Method 1 - Most compatible, longest code.
Method 2 - Medium compatible, medium code.
Method 3 - Least compatible, shortest code.
Method 4 - Flex Model
Similar to Method 3 in AndyM's post, this method relies on CSS3 and will only work in modern browsers. However, as it's name would suggest, it's flexible, and easy to implement. We use three new CSS properties: display:flex; flex-grow:;, and flex-basis:;.
We add the first to #wrap, which tells the browser that the items inside are going to be laid out using the flex model. The second two tell the browser whether or not an item will grow (is flexible), and what is the initial width.
Pros: The CSS is clean and short, and very easy to change later. Unlike Method 2 & 3, the fixed width only needs to be declared once.
Cons: Browser compatibility. This has just slightly better compatibility than calc(), but not by much. We can use it now, but we lose basically all but the newest versions of most mobile browsers, and of Internet Explorer.
Working Fiddle
HTML:
<div class="wrap">
<div class="fluid">
Fluid Box
</div>
<div class="fixed">
Fixed Box
</div>
<div class="fluid">
Fluid Box
</div>
</div>
CSS:
.wrap {
display: flex;
height:300px;
}
.fixed {
background-color:lightblue;
flex-grow: 0; /* Does this box grow? 0 means no. */
flex-basis: 500px;
}
.fluid {
background-color:orange;
flex-grow: 1;
flex-basis: 0px;
}
I've edited this to make the example as close as possible to the examples in Methods 1-3, for easier comparison of the methods. All kudos to vals for the initial post, I had never heard of this method. - AndyM
Original Fiddle
I have DIV with flexible width set e.g. min-width:800px and max-width:1400px. In this DIV, there are many boxes with fix width 200px and display:inline-block. So depending on parent DIV width, these boxes fill the entire space.
My problem is the blank space on the right side which is caused by variable width of the parent div. Sometimes this blank space is small and looks fine, but with different widths of the parent div, this blank space is almost 200px.
I don't know, if I described my problem in enough detail, I hope this picture will help to describe my actual situation:
And this is what I would like to have:
This auto-margin could be easily achieved by using TABLE. However, I don't know the exact number of columns, since it depends on user's screen resolution. So I can't use table and rather stick with CSS.
Anyone has an idea how to solve this ? Thank you in advance for your comments and answers.
EDIT: I don't need support of IE6. I would like to support IE7, but IE7 is optional as I know there are limitations so I will probably use fixed width of "div.wrapper" in IE7
EDIT2 I need to handle multiple rows of these boxes, so they don't exceed the "div.wrapper" box and wrap correctly in multiple lines of boxes, not just in one long line.
EDIT3 I don't know the number of "columns" as this is very variable depending on user's screen resolution. So on big screen there could be 7 boxes in one row, and on small screens there could be just 4 boxes in one row. So I need solution that doesn't set fixed number of boxes in one row. Instead, when the boxes don't fit in one row, they should just wrap to a next row.
This is as close as IE7-compatible CSS can get: http://jsfiddle.net/thirtydot/79mFr/
If this still isn't right, it's time to look at using JavaScript and hopefully also jQuery. If you define your requirements properly, it should be trivial to get this perfect with JavaScript.
HTML:
<div id="container">
<div></div>
<div></div>
..
<span class="stretch"></span>
</div>
CSS:
#container {
border: 2px dashed #444;
text-align: justify;
-ms-text-justify: distribute-all-lines;
text-justify: distribute-all-lines;
min-width: 800px;
max-width: 1400px
}
#container > div {
margin-top: 16px;
border: 1px dashed #f0f;
width: 200px;
height: 200px;
vertical-align: top;
display: inline-block;
*display: inline;
zoom: 1
}
.stretch {
width: 100%;
display: inline-block;
font-size: 0;
line-height: 0
}
The extra span (.stretch) can be replaced with :after.
This still works in all the same browsers as the above solution. :after doesn't work in IE6/7, but they're using distribute-all-lines anyway, so it doesn't matter.
See: http://jsfiddle.net/thirtydot/79mFr/2/
There's a minor downside to :after: to make the last row work perfectly in Safari, you have to be careful with the whitespace in the HTML.
Specifically, this doesn't work:
<div id="container">
<div></div>
<div></div>
</div>
And this does:
<div id="container">
<div></div>
<div></div></div>
You need to make .box inline-blocks, and justify text in .wrapper. .wraper:after is needed to justify the last line. Older IEs don't understand after, but in IE text-align-last:center will take care of the last line.
.wrapper{
text-align:justify;
max-width:1400px;
min-width:800px;
text-align-last:center;
}
.wrapper:after{
content:'';
display:inline-block;
width:100%;
height:0;
font-size:0;
line-height:0;
}
.box{
display:inline-block;
*display:inline;
vertical-align:top;
width:200px;
height:50px;
background:red;
}
Here's a jsfiddle.
You can float them and just apply a wrapper to the .box which will allow you to margin:auto; the .box relative to the floated wrapper.
CSS:
div.wrapper {
width:100%;
border:3px solid red;
}
div.clear {
clear:both;
}
div.box-wrapper {
float:left;
margin:10px 0;
height:100px;
width:20%;
}
div.box {
border:1px solid black;
width:80px;
height:100px;
margin:auto;
}
HTML:
<div class="wrapper">
<div class="box-wrapper"><div class="box"></div></div>
<div class="box-wrapper"><div class="box"></div></div>
<div class="box-wrapper"><div class="box"></div></div>
<div class="box-wrapper"><div class="box"></div></div>
<div class="box-wrapper"><div class="box"></div></div>
<div class="box-wrapper"><div class="box"></div></div>
<div class="box-wrapper"><div class="box"></div></div>
<div class="box-wrapper"><div class="box"></div></div>
<div class="box-wrapper"><div class="box"></div></div>
<div class="box-wrapper"><div class="box"></div></div>
<div class="clear"></div>
</div>
Demo: http://jsfiddle.net/2avwf/
I didn't make them 200px wide for the sake of the fiddle window. Just swap that width:80px out with the width you desire.
If you want to make this a dynamic solution, in which the number of boxes in a row will vary from user to user based off their screen size, etc., simply make 3 or 4 width-defining box-wrapper classes:
.box-wrapper-25 {
width:25%;
}
.box-wrapper-33 {
width:33%;
}
Then with JQuery you can easily detect the width of .wrapper and assign an override class to the box wrappers:
$('.box-wrapper').each(function(){
$(this).removeClass().addClass('box-wrapper box-wrapper-25'); // only need 4 per row
});
Something like this: http://jsfiddle.net/RcDky/
Try this jsFiddle: http://jsfiddle.net/MKuxm/
Just make the window larger and smaller to size the div, you'll see that the margin between the red boxes will size accordingly. I am aware that the red boxes are no longer 200px wide, but I'm afraid that isn't possible with pure css because you should not mix percentage widths and fixed pixel width.
HTML
<div>
<span>TEXT</span>
<span>TEXT</span>
<span>TEXT</span>
<span>TEXT</span>
</div>
CSS
div {
width: 95%;
}
span {
float: left;
background: red;
width: 20%;
margin-left: 2.5%;
margin-right: 2.5%;
}
I answered a similar question here
This is possible in pure css3 using media queries and the css calc() routine.
Of coarse this will only work on modern browsers. IE9+,Chrome,Firefox,
See this WORKING DEMO
The basic idea is to set up a media query for each #columns states, where I then use calc() to work out the margin-right on each of the elements (except the ones in the last column).
On my project I have faced with the same problem and I came to the next decision - the best way for me is to go with js, in my case you can have xxx count of block inside container, if there is enough space in 1st row the block from 2nd row goes up to the 1st row, and so on.
here is an example http://jsfiddle.net/gVAjN/11/
$(function() {
// Call function when DOM is ready
settingsAlignment();
$(window).resize(function() {
// Call function on window resize
settingsAlignment();
})
$('#new_div').click(function() {
box_number = $('.element').size();
box_add = box_number + 1;
$('.container').append($('<div class="element">Box'+ box_add + '</div>'))
settingsAlignment();
})
function settingsAlignment() {
// calculation of ul's padding-left and li's margin-right
var settingsUl = $('.container');
settingsLi = $('.element');
ul_width = settingsUl.outerWidth(true);
item_width = settingsLi.width();
min_gap = 7;
effective_item_width = item_width + min_gap;
items_in_row = Math.floor((ul_width - min_gap) / effective_item_width);
gaps_sum = ul_width - items_in_row * item_width;
new_gaps = gaps_sum / (items_in_row + 1);
item_margin = Math.floor(new_gaps);
row_width = (item_width + item_margin) * items_in_row - item_margin;
console.log(row_width + '= row_width');
console.log(ul_width + '= ul_width');
ul_left_padding = Math.ceil((ul_width - row_width) / 2);
console.log(ul_left_padding + '=ul_left_padding');
settingsUl.css('padding-left', ul_left_padding + 'px');
settingsLi.css('margin-right', item_margin + 'px');
console.log(settingsLi);
}
});
quite old but worth trying since multiple rows and text-align: justify; in the #container creates gaps when last row has less divs. I wanted everything to be floated left. So my idea was to use 2 wrappers.
<div class="wrapper">
<div class="wrapper2">
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="clear"></div>
</div>
</div>
as well as overflow: hidden; in css
.wrapper {
width:620px;
border:3px solid red;
margin:0 auto; overflow:hidden;
}
.wrapper2 {
width:630px;
}
div.clear {
clear:both;
}
.box {
width:200px; background:#000; height:100px; margin-bottom:10px; float:left; overflow:hidden; margin-right:10px;
}
drawback: margins are not auto set...
DEMO: http://jsfiddle.net/hexagon13/2avwf/52/
Try this:
div.wrapper {
display: flex;
align-items: stretch;
width: 100%;
height: 100%;
justify-content: space-between;
/* justify-content will give the auto margin you looking for
it will place the auto margin only between each div.box
make sure the div.wrapper has "display: flex;"
*/
}
div.box {
display: inline-flex; /* inline-flex will make the boxes all in the same line */
width: 200px; /* notice you don't need width to be a % for this to work */
height: 100%;
margin: auto; /* gives you the auto margin for the first and last box from the border of your wrapper */
}
I'm trying to build a page which will have a box-like layout..A top banner a bottom banner,two navigation panels(left and right) and some text that will appear in the middle.
Now I'm wondering if you can create something like that without using a table and without predefined/hardcoded values for margins.
Is that possible?
Thanks in advance
Mike
You can achieve centrally elastic three column layout with header and footer like this if that is what you mean?
With html:
<div id="top"></div>
<div id="left"></div>
<div id="right"></div>
<div id="middle"></div>
<div id="bottom"></div>
And css:
#top,#bottom{
width:100%;
height:70px;
background:silver;
clear:both;
}
#middle{
background:green;
}
#middle,#left,#right{
height: 200px;
}
#left,#right{
width: 200px;
background:skyblue;
}
#left{
float:left;
}
#right{
float:right;
}
Fiddle: http://jsfiddle.net/hkrVz/
You can build any table-like structure using divs and display:table,display:table-row,display:table-cell and you won't be abusing table semantics in markup. It really depends if you need to support IE7 as I think these CSS properties were only introduced to IE8 (years after everyone else had them).
If that's going to be a problem then just look around for options with flexibility to do what you need. I can't really think why hardcoded margins would even be an issue so perhaps you need to explain what you are attempting in more detail.