Fixed width columns with fluid gutters - css

I know this can be done with columns, but I have to support IE.
I'm trying to get to a layout whose columns are all fixed width, with the gutters being fluid.
I couldn't get this to work with floats, so I settled on using justified inline-block items:
HTML
<div class="wrapper">
<div></div>
<div></div>
<div></div>
<!-- more divs... -->
</div>
CSS
.wrapper {
text-align: justify;
}
.wrapper div {
width: 100px;
display: inline-block;
}
This works wonderfully, but the last row of divs are all aligned to the left: http://jsfiddle.net/EsHh3/
The only solution I found is to add additional unnecessary divs: http://jsfiddle.net/EsHh3/1/
I feel uncomfortable about this, so I'd like to know if there are any other options.
Please don't tell me not to re-invent the wheel. I have not found any fluid grid system that supports fluid gutters.

For what you want to do, I'm afraid a CSS only solution is not available at the moment, much less if you want it to work in IE8.
Since you want to have (a) items that are in the HTML source as a list (b) a variable number of columns depending on available space (c) column spacing depending on width of container I think the solution you'll need would have to employ at least a bit of javascript.
Consider on of the frameworks proposed in the other answers. One I've worked with and could do what you want is Masonry (or the for-pay bigger brother Isotope). (There's also a non-jQuery version of Masonry). You'll have to come up with a function that when the page is resized, recalculates the desired gutter and reconfigures the framework. Something along the lines of calculating x = how many items would fit per line based on the container width and item width and then dividing the remaining space by x-1.
If you want to stick with the idea of adding extra DIV's to the markup, an alternative would be to listen to resize events, and add DIVs as needed based on the width and how many items would fit per line.
ORIGINAL ANSWER, which failed to fit all the criteria.
Since you're relying on text-align: justified the reason the last line doesn't expand to the full width is because there's no line break at the end of it. So to accomplish that we add an extra element with an wrapper:after {} rule, that is also an inline block with a width of 100% so it guaranties a line break.
See fiddle
The CSS ends up something like:
.wrapper {
text-align: justify;
width: 380px;
margin: 0 auto;
}
.wrapper div {
width: 100px;
display: inline-block;
}
.wrapper:after {content: ''; width: 100%; display: inline-block; background: pink; height: 2px; overflow: hidden}
Note that the pink background is there so that you can see where the element is. You might need to play with the border/margin/padding of that extra element or the wrapper so that content that comes after wrapper doesn't gain extra margin. In chrome unfortunately there's a slight missalignment of the last row items, possibly because of the extra space between the last DIV and the fake element.

Hey I don't know why you want a fluid gutter, but I have a simple grid sample which you might want to have a look and if you want to see the css then click the SCSS on the codepen site. Also, if you are learning then this sample is very good start point for how to make your own grid. Also, to avoid yourself reinventing the wheel you might want to try different grid frameworks out there. Just google css grid frameworks.

you can try this:
.wrapper {
text-align: justify;
width: 380px;
margin: 0 auto;
moz-column-count: 3;
-moz-column-gap: 20px;
-webkit-column-count: 3;
-webkit-column-gap: 20px;
column-count: 3;
column-gap: 20px;
}
Updated URL

This is how I would go about it: http://codepen.io/jeremychurch/pen/wmtJz
.container {
display: table;
width: 100%; }
.cell {
display: table-cell; }
.content {
width: 15em;
margin: 0 auto; }
<div class="container">
<div class="cell">
<div class="content">
</div>
</div>
<div class="cell">
<div class="content">
</div>
</div>
<div class="cell">
<div class="content">
</div>
</div>
</div>

Related

Css column layout - inline block elements, what is percent width relative to?

I'm not sure I understand how css column layout is supposed to work.
I have a straightforward html
<div class="container">
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
<div class="block"></div>
</div>
and css
.block {
background-color: blue;
width: 50em;
height: 10px;
margin: 2px;
display: inline-block;
}
.container {
border: 1px solid black;
display: inline-block;
column-count: 2;
-moz-column-count: 2;
-webkit-column-count: 2;
}
This works as expected with the elements flowing downwards and then over into a second column.
Now what if I change the width value of .block to a percentage width? All my widths are tiny. They still are clearly relative to something since shrinking and growing the percentages changes the width proportionately but I have no idea what 100% corresponds to.
What is the percentage width relative to?
The width is relative to the column pseudo-element inserted by the browser:
http://www.w3.org/TR/css3-multicol/
In the traditional CSS box model, the content of an element is flowed into the content box of the corresponding element. Multi-column layout introduces a new type of container between the content box and the content, namely the column box (or column for short). The content of a multicol element is flowed into its column boxes.
(Emphasis mine.)
So, the percentage width you're asking for is relative to the implicit column boxes.
Browser Support
As I noted in my comment support for column-count etc is poor today. Except where you really need a specific feature of CSS multicolumn, I find it easier to just use the old inline-block approach. Works in every browser in use today, easy to figure out.
http://jsfiddle.net/b9chris/nt83M/
.block {
background-color: blue;
width: 45%;
height: 10px;
margin: 2px;
display: inline-block;
vertical-align: top;
}
.container {
border: 1px solid black;
width: 200px;
display: inline-block;
}
<span class=container>
<span class=block></span>
<span class=block></span>
<span class=block></span>
<span class=block></span>
<span class=block></span>
</span>
Two important caveats:
For old IE support to work properly you need to use tags that are inline by default, like span. Using a tag that's block by default, like div, will look great in Chrome etc but fail in IE8.
You need to set vertical-align: top in the inner tags to get things to work the way you'd expect them (otherwise everything acts like vertical-align: bottom).
Essentially how column layouts work is you have a container that a width and you split that container into columns. When you decide how many columns you want for your design you assign each of those columns a percentage. Then you float those columns next to each other.
So if you have a 12 column layout the column classes would be as follows:
.col-1 { width: 4.8076923077% }
.col-2 { width: 13.4615384615% }
.col-3 { width: 22.1153846154% }
.col-4 { width: 30.7692307692% }
.col-5 { width: 39.4230769231% }
.col-6 { width: 48.0769230769% }
.col-7 { width: 56.7307692308% }
.col-8 { width: 65.3846153846% }
.col-9 { width: 74.0384615385% }
.col-10 { width: 82.6923076923% }
.col-11 { width: 91.3461538462% }
.col-12 { width: 100%; margin: 0 }
The above columns take into account margins and padding, but here's a fiddle that lays it out.
Parent element width within a content column refers to the column width, a property that defaults to auto. A columnar element is either defined by column-width or column-count (but not both, column-count overrides any column-width value if they are both non-auto). So in your example, providing column-count is causing an automatically generated width to be presented as container width.
source - right above example IX here: http://www.w3.org/TR/2011/CR-css3-multicol-20110412/
Column boxes act as the containing block for their content. That is,
column boxes behave like block-level, table cell, and inline-block
boxes as per CSS 2.1, section 10.1, item 2 [CSS21]. However, column
boxes do not establish containing blocks for elements with ‘position:
fixed’ or ‘position: absolute’.

CSS Layout filling the rest of the horizontal space

I'm trying to achieve a specific css layout. I tried a lot of possibilities including floats, and css tables but i just can't figure it out. CSS tables helped me a lot in the past when there are some fixed columns and some columns that should take the rest of the space but this one seems to be different.
I need to have two columns. Toghether they need to be 100% width of their parent. The right column should be as wide as its content (i.e. it's got 3 buttons in it it should be as wide as these three buttons). The left column should take the rest of the remaining space. Thats it. Sounds easy. In TeX world it is called "\hfill" i would love to have such a command in css.
Here's what i tried so far:
<section>
<div id="a"></div>
<div id="b">
<button>Bla</button>
<button>Test</button>
<button>Hello</button>
<button>World</button>
</div>
</section>
CSS:
section { display: table; width: 100%;}
div { display: table-cell; height: 100px; border: 1px solid #000;}
#a { width: 100% }
#b{ }
And a fiddle:
http://jsfiddle.net/fa9FJ/270/
actually this is quite close to what i want, but the buttons need to be next to each other horizontally.
What you need is
#b {
white-space: nowrap;
}
Demo
This will prevent the buttons to wrap inside the div element
Try this..it works
button
{
width: 96%;
}
#b { display: table; }
button { display: table-cell; }
this should do the trick :)

Collapsing whitespace automatically

I have a really simple example which I've written on JSBin. It looks like this:
All I'd like to do is simply take two divs of a given width and height and display them side-by-side without a gap between them. I've used display: inline-block to accomplish the above, but it seems like it refuses to chomp the whitespace between divs, which seems to completely violate the idea of the separation of content and styling.
Here's my HTML:
<div class="container">
<div class="a">
<!-- completely empty -->
</div>
<div class="b">
<!-- nothing at all -->
</div>
</div>
and here's my CSS:
.container {
display: inline-block;
}
.a {
width: 320px;
height: 240px;
display: inline-block;
background-color: #83C5D1;
}
.b {
width: 180px;
height: 240px;
display: inline-block;
background-color: #B2D9D6;
}
How can I work around this to get them snug together without touching my HTML?
Add float:left to both of the divs classes .a and .b
I upated your JSBin http://jsbin.com/iwihox/4/edit
You're using a tabular design. Go for broke!
.container {
display: table-row;
}
.container > * {
display: table-cell;
}
Edit: Firefox did not like the inline-block children.
QUICK FIX
All given answers are good solutions, however the main reason for the gap is that there is white-space characters in your actual HTML that gets rendered. If you remove the space between both divs:
..</div><div>..
That will fix your current problem.
Heres the JSBIN: http://jsbin.com/iwihox/10/edit
THE PROPER SOLUTION:
The proper way to do this, is add float:left to both classes .a and .b. Making them float does change the box-model, so depending on your surrounding markup, you will need to add clear:both to the next tag in your HTML to have the document properly flowing.
CHECK THIS FIDDLE: http://jsbin.com/iwihox/19/edit
Let me know, Thanks!

CSS - aligning wrapped floating divs to the center

I am trying to create something like a gallery that shows different number of images per row based on the width of the browser. This has already been achieved using overflow: hidden in the outer div and float: left in the inner div.
However, what happens with this is that my images are always aligned to the left, leaving alot of whitespace on the right. How do I make it such that the gallery is always centered in the screen no matter how many images there are per row.
My code is on http://codepen.io/anon/pen/KzqAs
Thank you very much. :)
How about this: http://codepen.io/anon/full/mtBbF
HTML
<div class="container">
<div class="red box">red</div>
<div class="blue box">blue</div>
<div class="black box">black</div>
</div>
CSS
body{
text-align:center; /*You would need to define this in a parent of .container*/
}
.container{
display: inline-block;
margin: 0 auto;
text-align: left;
}
.box {
width: 300px;
height: 300px;
float: left;
}
Demonstration
You need to use an id(or class) on the main div. Set width: 300+px and margin: auto
Also your boxes should be with display: inline-block to allow them to begave "inline"
I have changed colors of the boxes a bit for better visibility.

How do you set a floating div's width to take up remaining space without pushing other divs down?

For part of a layout I want to make, I want to use three divs, all floating next to each other. The Left and Right have a max-width set, which works fine, but I want the middle div to expand its width to fill the remaining space. To clarify, the left and right divs may have a width of anywhere from 0px to the max-width, depending on what is in each, and I want the middle div to expand its width so that it takes up the rest of the space not used by the divs on either side.
The problem it's having now is that if there is a lot of content in the middle div, it's expanding and pushing the right div off to the next line instead of keeping it up with the other two.
Here's the css I have so far:
#left-column {
width: auto;
max-width: 200px;
height: auto;
float: left;
}
#middle-column {
float: left;
width: auto;
}
#right-column {
width: auto;
max-width: 200px;
height: auto;
float: right;
}
...and the HTML:
<div id="left-column">...</div>
<div id="middle-column">...</div>
<div id="right-column">...</div>
I think that this can be accomplished using a three-column, single-row table, but I absolutely do NOT want to use tables - I want to accomplish as much as possible by using pure css.
Thanks!
Classic Floats
If you order it:
<div id="left-column"></div>
<div id="right-column"></div>
<div id="middle-column"></div>
and you float the left column left, and the right column right, the middle column should fill in the remaining space. You will have some issues with margins, borders and paddings though.
Flexbox
If you don't need to support older browsers, you can use flexbox. With flexbox, this sort of structure becomes much simpler, and the markup doesn't need to change.
You will need to be able to select the parent element, so for the purposes of this demo, the code will be wrapped by <div class="wrapper">.
.wrapper {
display: flex;
flex-direction: row;
height: 200px;
}
.left {
background-color: red;
width: 100px;
}
.middle {
background-color: green;
flex: 1;
}
.right {
background-color: blue;
width: 100px;
}
<div class="wrapper">
<div class="left"></div>
<div class="middle"></div>
<div class="right"></div>
</div>
The height and widths are added explicitly so that the <div>s are visible. With actual content, the columns would automatically adjust.
I don't want to dredge up an old thread here but I was looking for a solution to my own problem and came across this and I thought I'd better share with Francisco...
Tables are a terrible idea for positioning layout, the main problem is that before a table will show/render in the browser it has to render it's </table> tag.
Could you imagine if Facebook's column content used a table for it's layout, it would take ages for it to render anything to the screen when checking your timeline for instance!
Another issue is that tables behave extremely differently in each browser.
Basically: <table> for layout = NO!, <table> for listing out rows of data or information = YES!

Resources