Fluid width with equally spaced DIVs - html

I have a fluid width container DIV.
Within this I have 4 DIVs all 300px x 250px...
<div id="container">
<div class="box1"> </div>
<div class="box2"> </div>
<div class="box3"> </div>
<div class="box4"> </div>
</div>
What I want to happen is box 1 to be floated left, box 4 to be floated right and box 2 and 3 to be spaced evenly between them. I want the spacing to be fluid as well so as the browser is made smaller the space becomes smaller also.

See: http://jsfiddle.net/thirtydot/EDp8R/
This works in IE6+ and all modern browsers!
I've halved your requested dimensions just to make it easier to work with.
text-align: justify combined with .stretch is what's handling the positioning.
display:inline-block; *display:inline; zoom:1 fixes inline-block for IE6/7, see here.
font-size: 0; line-height: 0 fixes a minor issue in IE6.
#container {
border: 2px dashed #444;
height: 125px;
text-align: justify;
-ms-text-justify: distribute-all-lines;
text-justify: distribute-all-lines;
/* just for demo */
min-width: 612px;
}
.box1,
.box2,
.box3,
.box4 {
width: 150px;
height: 125px;
vertical-align: top;
display: inline-block;
*display: inline;
zoom: 1
}
.stretch {
width: 100%;
display: inline-block;
font-size: 0;
line-height: 0
}
.box1,
.box3 {
background: #ccc
}
.box2,
.box4 {
background: #0ff
}
<div id="container">
<div class="box1"></div>
<div class="box2"></div>
<div class="box3"></div>
<div class="box4"></div>
<span class="stretch"></span>
</div>
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/EDp8R/3/
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 class="box3"></div>
<div class="box4"></div>
</div>
And this does:
<div id="container">
..
<div class="box3"></div>
<div class="box4"></div></div>
You can use this for any arbitrary number of child divs without adding a boxN class to each one by changing
.box1, .box2, .box3, .box4 { ...
to
#container > div { ...
This selects any div that is the first child of the #container div, and no others below it. To generalize the background colors, you can use the CSS3 nth-order selector, although it's only supported in IE9+ and other modern browsers:
.box1, .box3 { ...
becomes:
#container > div:nth-child(odd) { ...
See here for a jsfiddle example.

The easiest way to do this now is with a flexbox:
http://css-tricks.com/snippets/css/a-guide-to-flexbox/
The CSS is then simply:
#container {
display: flex;
justify-content: space-between;
}
demo: http://jsfiddle.net/QPrk3/
However, this is currently only supported by relatively recent browsers (http://caniuse.com/flexbox).
Also, the spec for flexbox layout has changed a few times, so it's possible to cover more browsers by additionally including an older syntax:
http://css-tricks.com/old-flexbox-and-new-flexbox/
http://css-tricks.com/using-flexbox/

If css3 is an option, this can be done using the css calc() function.
Case 1: Justifying boxes on a single line ( FIDDLE )
Markup is simple - a bunch of divs with some container element.
CSS looks like this:
div
{
height: 100px;
float: left;
background:pink;
width: 50px;
margin-right: calc((100% - 300px) / 5 - 1px);
}
div:last-child
{
margin-right:0;
}
where -1px to fix an IE9+ calc/rounding bug - see here
Case 2: Justifying boxes on multiple lines ( FIDDLE )
Here, in addition to the calc() function, media queries are necessary.
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).
This sounds like a lot of work, but if you're using LESS or SASS this can be done quite easily
(It can still be done with regular css, but then you'll have to do all the calculations manually, and then if you change your box width - you have to work out everything again)
Below is an example using LESS: (You can copy/paste this code here to play with it, [it's also the code I used to generate the above mentioned fiddle])
#min-margin: 15px;
#div-width: 150px;
#3divs: (#div-width * 3);
#4divs: (#div-width * 4);
#5divs: (#div-width * 5);
#6divs: (#div-width * 6);
#7divs: (#div-width * 7);
#3divs-width: (#3divs + #min-margin * 2);
#4divs-width: (#4divs + #min-margin * 3);
#5divs-width: (#5divs + #min-margin * 4);
#6divs-width: (#6divs + #min-margin * 5);
#7divs-width: (#7divs + #min-margin * 6);
*{margin:0;padding:0;}
.container
{
overflow: auto;
display: block;
min-width: #3divs-width;
}
.container > div
{
margin-bottom: 20px;
width: #div-width;
height: 100px;
background: blue;
float:left;
color: #fff;
text-align: center;
}
#media (max-width: #3divs-width) {
.container > div {
margin-right: #min-margin;
}
.container > div:nth-child(3n) {
margin-right: 0;
}
}
#media (min-width: #3divs-width) and (max-width: #4divs-width) {
.container > div {
margin-right: ~"calc((100% - #{3divs})/2 - 1px)";
}
.container > div:nth-child(3n) {
margin-right: 0;
}
}
#media (min-width: #4divs-width) and (max-width: #5divs-width) {
.container > div {
margin-right: ~"calc((100% - #{4divs})/3 - 1px)";
}
.container > div:nth-child(4n) {
margin-right: 0;
}
}
#media (min-width: #5divs-width) and (max-width: #6divs-width) {
.container > div {
margin-right: ~"calc((100% - #{5divs})/4 - 1px)";
}
.container > div:nth-child(5n) {
margin-right: 0;
}
}
#media (min-width: #6divs-width){
.container > div {
margin-right: ~"calc((100% - #{6divs})/5 - 1px)";
}
.container > div:nth-child(6n) {
margin-right: 0;
}
}
So basically you first need to decide a box-width and a minimum margin that you want between the boxes.
With that, you can work out how much space you need for each state.
Then, use calc() to calcuate the right margin, and nth-child to remove the right margin from the boxes in the final column.
The advantage of this answer over the accepted answer which uses text-align:justify is that when you have more than one row of boxes - the boxes on the final row don't get 'justified' eg: If there are 2 boxes remaining on the final row - I don't want the first box to be on the left and the next one to be on the right - but rather that the boxes follow each other in order.
Regarding browser support: This will work on IE9+,Firefox,Chrome,Safari6.0+ - (see here for more details) However i noticed that on IE9+ there's a bit of a glitch between media query states. [if someone knows how to fix this i'd really like to know :) ] <-- FIXED HERE

Other posts have mentioned flexbox, but if more than one row of items is necessary, flexbox's space-between property fails (see the end of the post)
To date, the only clean solution for this is with the
CSS Grid Layout Module (Codepen demo)
Basically the relevant code necessary boils down to this:
ul {
display: grid; /* (1) */
grid-template-columns: repeat(auto-fit, 120px); /* (2) */
grid-gap: 1rem; /* (3) */
justify-content: space-between; /* (4) */
align-content: flex-start; /* (5) */
}
1) Make the container element a grid container
2) Set the grid with an 'auto' amount of columns - as necessary. This is done for responsive layouts. The width of each column will be 120px. (Note the use of auto-fit (as apposed to auto-fill) which (for a 1-row layout) collapses empty tracks to 0 - allowing the items to expand to take up the remaining space. (check out this demo to see what I'm talking about) ).
3) Set gaps/gutters for the grid rows and columns - here, since want a 'space-between' layout - the gap will actually be a minimum gap because it will grow as necessary.
4) and 5) - Similar to flexbox.
body {
margin: 0;
}
ul {
display: grid;
grid-template-columns: repeat(auto-fit, 120px);
grid-gap: 1rem;
justify-content: space-between;
align-content: flex-start;
/* boring properties: */
list-style: none;
width: 90vw;
height: 90vh;
margin: 2vh auto;
border: 5px solid green;
padding: 0;
overflow: auto;
}
li {
background: tomato;
height: 120px;
}
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
Codepen demo (Resize to see the effect)
Browser Support - Caniuse
Currently supported by Chrome (Blink), Firefox, Safari and Edge! ... with partial support from IE (See this post by Rachel Andrew)
NB:
Flexbox's space-between property works great for one row of items, but when applied to a flex container which wraps it's items - (with flex-wrap: wrap) - fails, because you have no control over the alignment of the last row of items;
the last row will always be justified (usually not what you want)
To demonstrate:
body {
margin: 0;
}
ul {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
align-content: flex-start;
list-style: none;
width: 90vw;
height: 90vh;
margin: 2vh auto;
border: 5px solid green;
padding: 0;
overflow: auto;
}
li {
background: tomato;
width: 110px;
height: 80px;
margin-bottom: 1rem;
}
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
Codepen (Resize to see what i'm talking about)
Further reading on CSS grids:
MDN
Jen Simmons - Learn CSS grid
A Complete Guide to CSS Grid | Codrops CSS Reference
A Complete Guide to Grid - CSS Tricks

This worked for me with 5 images in diferent sizes.
Create a container div
An Unordered list for the images
On css the unordened must be displayed vertically and without bullets
Justify content of container div
This works because of justify-content:space-between, and it's on a list, displayed horizontally.
On CSS
#container {
display: flex;
justify-content: space-between;
}
#container ul li{ display:inline; list-style-type:none;
}
On html
<div id="container">
<ul>
<li><img src="box1.png"><li>
<li><img src="box2.png"><li>
<li><img src="box3.png"><li>
<li><img src="box4.png"><li>
<li><img src="box5.png"><li>
</ul>
</div>

in jQuery you might target the Parent directly.
THIS IS USEFUL IF YOU DO NOT KNOW EXACTLY HOW MANY CHILDREN WILL BE
ADDED DYNAMICALLY or IF YOU JUST CAN'T FIGURE OUT THEIR NUMBER.
var tWidth=0;
$('.children').each(function(i,e){
tWidth += $(e).width();
///Example: If the Children have a padding-left of 10px;..
//You could do instead:
tWidth += ($(e).width()+10);
})
$('#parent').css('width',tWidth);
This will let the parent grow horizontally as the children are beng added.
NOTE: This assumes that the '.children' have a width and Height Set
Hope that Helps.

If you know the number of elements per "row" and the width of the container you can use a selector to add a margin to the elements you need to cause a justified look.
I had rows of three divs I wanted justified so used the:
.tile:nth-child(3n+2) { margin: 0 10px }
this allows the center div in each row to have a margin that forces the 1st and 3rd div to the outside edges of the container
Also great for other things like borders background colors etc

Related

How do I get nested divs to be same height and expand to the largest of the heights?

This is best explained with a JSFiddle https://jsfiddle.net/4beugz4w/1/ and code examples.
I am trying to design a very standard header with a name/logo thing on the left and navigation on the right. I can't get the heights of the divs to be right and also to vertically center the navigation links according to the middle of how the name/logo thing is. I hope that made sense.
HTML
<div id="inside1">
Name or Logo
</div>
<div id="inside2">
<ul>
<li>About Me</li>
<li>Work</li>
<li>Resume</li>
</ul>
</div>
</div>
CSS
#outside
{
background-color: red;
}
#outside > *
{
display: inline;
}
#inside1
{
background-color: blue;
font-size: 30px;
}
#inside2
{
background-color: green;
float: right;
}
#inside2 ul li
{
font-size: 16px;
display: inline;
margin-left: 30px;
}
UPDATE 31-03-2017
Since this answer was posted in Dec, 2015 things have changed for the (even) better css Grid layout module. This module has recently been implemented in all browsers with the exception of partial support in the latest version of Edge (http://caniuse.com/#search=grid).
A quote by Chris Coyier from CSS tricks explaining the difference between flexbox and grid:
CSS Grid Layout is the most powerful layout system available in CSS. It is a 2-dimensional system, meaning it can handle both columns and rows, unlike flexbox which is largely a 1-dimensional system. You work with Grid Layout by applying CSS rules both to a parent element (which becomes the Grid Container) and to that elements children (which become Grid Items).
If you would like to check it out, there is a CSS Grid guide on CSS-Tricks which is just as clear as the flexbox guide link that already exists in this answer. Go check it out here!
If you require support for somewhat older browsers, e.g. IE 10+, flexbox can be made to work with that but grid isn't supported there. (http://caniuse.com/#search=flexbox)
ORIGINAL ANSWER
In this fiddle I have the desired result you want.
I'm using display: flex here together with more of it's properties to make things work.
The flexbox model is a very modern one which pretty much solves (almost if not) all positioning problems by giving you the things that you need as a dev, common tasks are made easier with flexbox and browser vendors implemented it fast so that we can basically use it today as the older browsers like Internet Explorer < 11 are no longer a bother like Internet Explorer <= 8 used to be.
If you're not familiar with using flexbox I would definitely recommend you read up on it since it will make your life a breeze where with conventional methods (inline-block, float) it would be horror.
The following things I removed within your code:
removed the entire #outside > * {} selector as it was useless
to elaborate: display: inline prevents elements from receiving any height or margin-top / margin-bottom in any way due to it literally becoming a text element.
removed float: right from #inside2 since it wasn't required anymore
when using display: flex all children are flex-children that gain special properties to align themselves using the flexbox model
The following things I added within your code:
display: flex to #outside
this property allows it's children to be sized according to the flexbox model
flex-flow: row wrap to #outside
this allows multiple children to be aligned on the same line
justify-content: space-between to #outside
makes sure that your items are taking the full width of the screen but with whitespace in between to fill the gap
flex: 0 0 auto to both #inside1 and #inside2
prevents elements from growing bigger than they need to be.
For useful reads on how flexbox works / how well it's supported,
CSS-tricks guide
MDN on flexbox
Browser support for flexbox
Here you go !!
NOTE
Apply display: table for the parent and display: table-cell for the child. Use vertical-align: middle to the child div to make it align vertical center.
body {} #outside {
background-color: red;
overflow: hidden;
display: table;
width: 100%;
}
#outside > * {
display: inline;
}
#inside1 {
background-color: blue;
font-size: 30px;
display: table-cell;
vertical-align: middle;
}
#inside2 {
background-color: green;
float: right;
}
#inside2 ul li {
font-size: 16px;
display: inline;
margin-left: 30px;
}
ul {
padding: 0;
line-height: 16px;
}
<div id="outside">
<div id="inside1">
Name or Logo
</div>
<div id="inside2">
<ul>
<li>About Me</li>
<li>Work</li>
<li>Resume</li>
</ul>
</div>
</div>
CSS:
#outside
{
background-color: red;
display: table;
width: 100%;
}
#outside > *
{
display: table-cell;
}
#inside1
{
background-color: blue;
font-size: 30px;
vertical-align: middle;
}
#inside2
{
background-color: green;
float: right;
}
#inside2 ul li
{
font-size: 16px;
display: inline;
margin-left: 30px;
}
JsFiddle
Use below css and change as per your requirement
I am using display table/table-cell for cross-browser, though you can get the same result through css flex-box.
#outside
{
background-color: red;
display:table;
width:100%;
}
#outside > *
{
display: table-cell;
}
#inside1
{
background-color: blue;
font-size: 30px;
width:30%;
}
#inside2
{
background-color: green;
text-align: right;
width:70%;
}
#inside2 ul li
{
font-size: 16px;
display: inline;
margin-left: 30px;
}
You should use on a wrapper
display: table
and
display: table-cell;
vertical-alignment: top
on its inner elements.
Working example.

How can I create three responsive divs using display: table and no JS?

How can I create a responsive arrangement of three divs, such that:
when the viewport is narrow, the three divs appear one atop the other
when the viewport is average, the first div appears full width atop the other two, which are side-by-side and have equal height
when the viewport is wide, the three divs appear side-by-side with equal height
I would like the solution to be broadly supported by browsers.
I've tried a number of media query based strategies, as follows:
To achieve #1, I style each div as display:block
To achieve #2, I style the green and blue divs as display:table-cell and created a container div styled with display:table.
However, if I create another container div for all three elements and style it with display:table, neither of the following approaches work:
Setting all divs to display:table-cell - because the red table cell and the other two are intervened by the smaller container div
Setting the red div and the smaller container divs to display:table-cell - because the smaller container div still needs to be set to display:table for the sake of the green and blue divs inside it.
It's all a bit hard to explain, but I guess you have the idea. Any help would be greatly appreciated.
Thanks!
Edit: I don't want to set the height of any div manually. It should be dictated by its content
What you are trying to achieve is fairly difficult using display: table because of just the issue you ran into: containers are required and the configuration is not that flexible due to the way tables' strict requirements.
I suggest you use flexbox which has fairly good browser coverage now: http://caniuse.com/#feat=flexbox
Here is a good example of how to get equal height rows using flexbox: http://osvaldas.info/flexbox-based-responsive-equal-height-blocks-with-javascript-fallback
I know #fauxserious already posted a very similar answer, but I'll post mine anyways because it's a bit different.
This doesn't use a table, nor the ::before or ::after CSS pseudo-elements.
div#div1 {
background-color: red;
}
div#div2 {
background-color: green;
}
div#div3 {
background-color: blue;
}
div {
box-sizing: border-box;
padding: 20px;
float: left;
margin: 1%;
width: 31%;
}
#media screen and (max-width: 750px) {
div#div1 {
width: 98%;
}
div#div2, div#div3 {
width: 48%;
}
}
#media screen and (max-width: 500px) {
div {
width: 98% !important;
}
}
<div id="div1"></div>
<div id="div2"></div>
<div id="div3"></div>
(It's best to see the above snippet if you open it in a new tab / window and resize it.)
See working example on JSFiddle.net.
EDIT See updated snippet. If you remove the height property of the divs (and replace it with padding so that you can see it even when it's empty), then the height will be determined by its content.
Edit: sorry I missed the equal height part.
You are trying to make squares so let me code and then explain. I'm going to make this a list to help identify things. Assume the ul has been reset (no margin, padding or style-type).
<ul>
<li>
<div>
</div>
</li>
<li>
<div>
</div>
</li>
<li>
<div>
</div>
</li>
</ul>
Here's the CSS to make everything squares.
li{
position:relative;
width:33%;
padding-top:33%;
}
li > div{
position:absolute;
top:0;
left:0;
right:0;
bottom:0;
height:100%;
width:100%;
}
You'll notice the padding to be equal to the width. Padding percentage no matter where it's used is based on the parent element's width (margin also works this way). Even if you use it on the top or bottom.
Now with that we can get to positioning with CSS
ul:before, ul:after{
content:"";
display:table;
}
ul:after{
clear:both;
}
li{
position:relative;
width:33%;
padding-top:33%;
float:left;
}
#media screen and (max-width:800px){
li{
width:50%;
padding-top:50%;
}
li:first-child{
width:100%;
padding-top:0; /* Not sure what height you'd want here*/
}
}
#media screen and (max-width:400px){
li{
width:100%;
padding-top:100%;
}
}
I was unsure of why you wanted to use display: table;, however I did something a little different but will look like the images you posted above.
HTML:
<div class="container">
<div class="box box1"></div>
<div class="box box2"></div>
<div class="box box3"></div>
</div>
CSS:
.container {
width: 90%;
margin: 0 auto;
}
.box {
width: 32.3333%;
float: left;
height: 200px;
margin: .5%;
}
.box1 {
background-color: #ff4034;
}
.box2 {
background-color: #22ff62;
}
.box3 {
background-color: #24a6ff;
}
#media screen and (max-width: 900px){
.box:first-child {
width: 99%;
}
.box:nth-child(n + 2){
width: 49%;
}
}
#media screen and (max-width: 436px){
.container .box {
width: 99%;
clear: both;
margin-bottom: 10px;
}
}
Result: Your images above
How about using flex?
.parent {
border: 1px solid #555;
display: flex;
flex-flow: row wrap;
}
.dual {
display: flex;
flex-flow: row wrap;
flex: 2 2 550px;
}
.item {
padding: 20px;
margin: 10px;
flex: 1 1 200px;
min-width: 200px;
}
<div class="parent">
<div class="item" style="background-color: red">red</div>
<div class="dual">
<div class="item" style="background-color: green; flex: 1 1 100px">green</div>
<div class="item" style="background-color: blue; flex: 1 1 100px">blue</div>
</div>
</div>
I had to tweak the sizes a little due to padding and margins, like ".dual" being 550px instead of 400px. Also if the combined items are the same size they will show as two rows in the second column sometimes when shrinking so I made them smaller. Make it full page when you run the snippet or check out the fiddle link which is easier to resize has some extra text showing the blue and green boxes keep the same height in layout 2.

How to align multiple divs left and right in the same line in a responsive container (% width)?

I wanted the behaviour of inline-block and float together of several divs in a responsive container (% width), where:
float effect:
1a. it would have divs left and right aligned
1b. when the window width shrinks - the space between the left and right divs would also shrink
inline-block effect:
2a. all the divs would be in the same line
2b. when the window width shrinks - it will hide the divs (usually starting on the right)
Examples:
when the window is larger that the divs:
when the window is smaller that the divs:
2a. the wanted effect
2b. the wrong effect
Here is a code example of what I got so far (which only simulates the float effect (1) and effect in same line (2b) but missing effect when shrinking the window width (3b) ), with a demo:
.item1 {background-color: red;}
.item2 {background-color: yellow;}
.item3 {background-color: blue;}
#container {
width: 95%;
height: 50px; /* not sure if is needed */
}
#container div {
display: inline-block; /* does nothing with floats */
width:100px;
height: 50px;
}
.left {float: left;}
.right {float: right;}
<div id="container">
<div class="item1 left">item1</div>
<div class="item2 right">item2</div>
<div class="item3 right">item3</div>
</div>
Notes:
The container has a % value (to be a bit responsive).
the width of the divs (items) is supposed to have a fixed width (to have a logo image, a menu, and some icons (more images), ...)
in the example, I've also added the inline-block just to show that it does not works with it
the example only uses 3 divs (1 left and 2 right), but if possible I preferred a solution where I could have more without changing too much of code.
(I want to avoid fixed position (like right:20px or 20%) to be easier to add new items.)
was supposed to find a solution using only html and css (or html5 and css3) (avoiding JavaScript).
You should take a look at bootstraps grid system. It would save you a lot of time. http://getbootstrap.com/2.3.2/scaffolding.html#gridSystem
May be it is not fully what you want, but it gets close:
use flex for the container, and hide the second row.
and play with flex-shrink, flex-basis, max-width and margin
.container {
width: 80%;
display: flex;
flex-wrap: wrap;
height: 100px;
margin-bottom: -100px;
border: solid 1px red;
overflow: hidden;
}
.container div {
height: 100px;
border: solid 1px;
}
.left {
flex: 200px 0 0;
background-color: lightgreen;
margin-right: auto;
}
.right {
flex: 100px 1 1;
background-color: yellow;
max-width: 200px;
}
.disappears {
flex: 200px 0 1;
background-color: papayawhip;
}
<div class="container">
<div class="left">left</div>
<div class="right">right</div>
<div class="disappears">dis</div>
<div class="disappears">dis</div>
</div>
You need to add overflow:hidden; to your #container
#container {
width: 95%;
height: 50px; /* not sure if is needed */
overflow: hidden;
}
After more research and tests, I finally come up with a solution, with a demo:
.item1 {background-color: red;}
.item2 {background-color: yellow;}
.item3 {background-color: blue;}
#container {
width: 95%;
display: flex;
justify-content: space-between;
}
/* affects container_left and container_right divs */
#container > div {
display: flex;
}
/* affects items */
#container > div > div {
width: 100px;
min-width: 100px; /* to avoid shrinking in IE 11*/
height: 50px;
}
#container, #container > div {
/* reading from right to left (RTL)*/
/* flex-direction: row-reverse; */
}
<div id="container">
<div class="container_left">
<div class="item1">item1</div>
</div>
<div class="container_right">
<div class="item2">item2</div>
<div class="item3">item3</div>
</div>
</div>
Notes:
It does the effects asked, at least in Firefox (v 37.0.2) and Internet Explorer (IE 11).
In chrome (v 42.0.2311.135 m) it doesn't respect the min-width. Maybe there's some way around it that I didn't realize.
Changed the html to put 2 containers for left and right items, (and if needed you could also add a middle container). And in css using the flex property with the "justify-content: space-between" to align the containers.
New items can be easily added to the right positions (just in html) without the need to use a grid system.
Also added some css code to uncomment if you want to reverse the item order (in right to left languages).

How to get tiles centered and left-justified at the same time

I have a container of tiles (or divs) and I want the container to be centered, while the tiles are left justified in the container.
so if the window is small:
..[s][s][s]..
..[s][s].....
If the window is widened a little:
...[s][s][s]...
...[s][s]......
further:
.[s][s][s][s].
.[s]..........
I've tried:
#container's-parent: { display: block; text-align: center; }
#parent: { display: inline-block; text-align: left; }
.tiles: { display: inline-block }
but that doesn't appear to work.
I want this to work in Chrome at least, but I also need to eventually support latest FF, Safari, and IE 10+
FWIW: It's now 2017 and the grid layout module does this out of the box (codepen demo). If the browser support suits you - then use grid. If not, then read on....
As mentioned in #Skadi2k3's answer, the best you can do with CSS is with a series of media queries.
That being said, if you are using a preprocessor such as LESS - this isn't such a difficult or error-prone task. (although, yes, the CSS will still be long and ugly)
FIDDLE or CODEPEN (Supports LESS)
Here's how to take advantage of LESS to set up the media queries:
Set up an iteration mixin like this: (You can paste this code into http://less2css.org)
#item-width:100px;
#item-height:100px;
#margin: 5px;
#min-cols:2;
#max-cols:12; //set an upper limit of how may columns you want to write the media queries for
.loopingClass (#index-width) when (#index-width <= #item-width * #max-cols) {
#media (min-width:#index-width) {
#content{
width: #index-width;
}
}
.loopingClass(#index-width + #item-width);
}
.loopingClass (#item-width * #min-cols);
The above mixin will spit out a series of media queries in the form:
#media (min-width: 200px) {
#content {
width: 200px;
}
}
#media (min-width: 300px) {
#content {
width: 300px;
}
}
#media (min-width: 400px) {
#content {
width: 400px;
}
}
...
#media (min-width: 1200px) {
#content {
width: 1200px;
}
}
So with a simple markup like:
<ul id="content">
<li class="box"></li>
<li class="box"></li>
...
<li class="box"></li>
</ul>
With remaining CSS (LESS):
#content {
margin:0 auto;
overflow: auto;
min-width: #min-cols * #item-width;
max-width: #max-cols * #item-width;
display: block;
list-style:none;
background: aqua;
}
.box {
float: left;
height: #item-height - 2 *#margin;
width: #item-width - 2*#margin;
margin:#margin;
background-color:blue;
}
... you get the desired result.
...and it's super easy to customize the layout:
All I need to do is change the variables that I used in the LESS mixin according to my needs - I get the exact layout that I'm after.
So let's say I have items 300px X 100px with a minimum of 2 columns and max 6 columns and a margin of 15px - I just modify the variables like so:
#item-width:300px;
#item-height:100px;
#margin: 15px;
#min-cols:2;
#max-cols:6;
...and voila, I get this CODEPEN
What about this?
http://jsfiddle.net/cHTVd/1/
You have to set display: inline-block for the container too:
body { text-align: center; }
#container {
width: 250px;
border: solid green 3px;
display: inline-block;
text-align: left;
}
.tile { width: 100px;
border: solid red 3px;
display: inline-block;
margin: 8px;
}
EDIT: Giving container relative width is easy - http://jsfiddle.net/cHTVd/3/
I am afraid that "reverse justify" would have to be done with JS. CSS text-align has only four values: left | right | center | justify. It's trivial to change it to justify - http://jsfiddle.net/cHTVd/4/. For the "reverse justify" you would probably need some javascript work similar to this: http://jsfiddle.net/yjcr7/2/.
Unless you want to use Javascript you could use the media query (lots of them):
#parent{ width: 100px; margin: 0 auto;padding:0;}
.tile{width: 80px; float:left;padding:10px;outline:2px dashed red;}
#media screen and (max-width:200px)
#media screen and (min-width:201px) and (max-width:300px){
#parent{ width: 200px;}
}
#media screen and (min-width:301px) and (max-width:400px){
#parent{ width: 300px;}
}
#media screen and (min-width:401px){
#parent{ width: 400px;}
}
The problem is that you need to know how many of the tiles fit into the container to set a tight fitting width to the container, but that is a bottom up information and not how cascading works. If you want a more elegant solution you need to use JS on resize events, calculate how many boxes fit into one line and set the width of the container.
I solved this on my own projects in a quick and dirty manner by simply adding several empty "tiles" to the end that are the same width as the regular content tiles, but with a negligible height. These empty tiles serve to "push" the content tiles on the last line to the left where they belong. (The "real" last line often consists of nothing but empty tiles that are invisible to the user.) So, for example, if there some number of tiles on a page, and I expect the width of the browser to be able to accommodate from 1 to 4 (for example) tiles in width, I will add 3 extra empty tiles (designated "e") to the end:
..[s][s][s]..
..[s][s][e]..
...[e][e].... // this row isn't visible because [e] has no content
If the window is widened a little:
...[s][s][s]...
...[s][s][e]...
....[e][e].....
further:
.[s][s][s][s].
.[s][e][e][e].
or more narrow:
.[s][s].
.[s][s].
.[s][e].
.[e][e].
or really narrow
..[s]..
..[s]..
..[s]..
..[s]..
..[s]..
..[e]..
..[e]..
..[e]..
The empty tiles may pile up at the bottom, but since they are some small height, they don't create a whole lot of extra whitespace.
A hackish solution for sure, but it does work, is reliable on different browsers, and doesn't require a mound of code.
Answer the same like Danield's, but in SCSS:
*
{
margin:0;padding:0;
}
$item-width:200px;
$item-height:100px;
$margin: 15px;
$min-cols:2;
$max-cols:6; //set an upper limit of how may columns you want
//to write the media queries forss to css
#for $i from $min-cols to $max-cols + 1 {
$index-width: $i*$item-width;
#media (min-width:$index-width) {
#content {
width: $index-width;
}
}
}
#content {
margin:0 auto;
overflow: auto;
min-width: $min-cols * $item-width;
max-width: $max-cols * $item-width;
display: block;
list-style:none;
background: aqua;
}
.box {
float: left;
height: $item-height - 2 *$margin;
width: $item-width - 2*$margin;
margin:$margin;
background-color:blue;
}
It generates the same CSS like his solution.
Working codepen example here.
Try this:
.tiles: {
display: inline-block;
margin: 0 auto;
max-width: 90%;
}
No verticall margin, auto margin for horizontal sides!
This is pretty easy with flexbox.
.container {
display: flex;
flex-wrap: wrap;
}
You can customize how the tiles fit as well, such as giving them a starting point (flex-basis) or how much the tile can grow or shrink
.tile {
flex-grow: 0;
flex-shrink: 0;
flex-basis: 3em;
Check out the codepen: http://codepen.io/anon/pen/uexbf
Looks like there is solution (though it is described in Russian and I haven't found a translation).
Demo can be seen here.
No idea how to do it with CSS, if it's even possible. But with jQuery it's rather simple:
$('button').click(function(){
$('nav ul').each(function(){
$parent = $(this).parent();
$parent.width( $(this).width() );
});
});
nav {
display: inline-block;
text-align: left; /* doesn't do anything, unlike some might guess */
}
ul {
display: inline;
}
/* needed style */
ul {
padding: 0;
}
body {
width: 420px;
}
/* just style */
body {
background: #ddd;
margin: 1em auto;
}
button {
display: block;
}
nav {
background: #bbb;
margin: 1rem auto;
padding: 0.5rem;
}
li {
display: inline-block;
width: 40px;
height: 20px;
border: solid thin #777;
margin: 4px;
background: #999;
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>fix</button>
<nav>
<ul>
<li>3</li>
<li>.</li>
<li>1</li>
<li>4</li>
</ul>
</nav>
<nav>
<ul>
<li>3</li>
<li>.</li>
<li>1</li>
<li>4</li>
<li>1</li>
<li>5</li>
<li>9</li>
<li>2</li>
<li>6</li>
<li>5</li>
<li>3</li>
<li>5</li>
</ul>
</nav>

Div width 100% minus fixed amount of pixels

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.