Items grid with inner padding only - html

What techniques are there for creating a products grid that has padding between each item, but only within the grid? For example, what I am trying to achieve is the below:
Sample markup:
<div id="container">
<div class="item">
<!-- content -->
</div>
</div>
CSS:
#container { width: 100%; min-width: 960px; }
.item { float: left; width: 300px; height: 100px; }
(in the above, .item is going to be output 9 times).
The solution would need to be IE8+ compatible and preferably using a technique that isn't a hack. I have tried using display: table with border-spacing property - but this outputs the padding on the outer sides too.
I know I can also add specific classes to items to control whether the padding is shown for that item, but I was hoping for a more 'automated' solution.
Edit: The padding width should be calculated dynamically, so for example if the container is 960px, the padding is going to be 30px wide.
Secondly, if there are less than 3 items on the last row, these should not appear centered on the row, i.e. if there are only two items then the last 'cell' should just be empty.
EDIT: All the solutions so far insist on specfying the width of the gap/padding. I want to have the padding calculated dynamically. The only width I need to specify is that of .item, which is currently a fixed with of 300px.

Responsive grid with :
fluid width items
inner fluid gaps between them
IE8+ support (at least)
DEMO
add a general percent margins to the items with percent widths, make sure elements widths + left/right magins = 100%;
compensate the outer margins (between container and items) by setting a negative margin of the same value on the container
add a general wrapper with overflow:hidden;
This is simple and doesn't use any properties unsuported by IE8. I am pretty sure it can have a decent output in IE7 if you remove the borders and the box-sizing property.
Just to make sure, negative margins are not a "hack" :
Negative values for margin properties are allowed source : w3.org
HTML :
<div id="wrapper">
<div id="container">
<div class="item"></div>
<div class="item"></div>
...
</div>
</div>
CSS :
#wrapper {
overflow:hidden;
}
#container {
margin: -1.5%;
background:lightgrey;
}
#container:after {
content:'';
display:block;
clear:both; /* clear the floats */
}
.item {
margin:1.5%;
width:30.3333%;
padding-bottom:10%; /* to simulate height on the empty items */
background:grey;
border: 1px solid #000;
float:left;
/* following only if you want to add borders to the items */
box-sizing:border-box;
}
After, you just need to change the width of the .items with media query to rearange the number of elements in one row on the desired breakpoints.
Example :
#media screen and (max-width: 600px) {
.item {
width:47%;
}
}

Please don't consider this a formal answer. Josh's is clearly elegant.
I like these types of questions because it gives me an opportunity to think of a variety of ways to approach a problem. I've used tables and floated divs to give a total of 4 other ways to do this. If I can think of any more, I'll add them.
The FIDDLE.
The first table in HTML, just to fulfill the SO requirements.
HTML
<table class='table1'>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td></tr>
</table>
"Tables are inelegant" -(except for tabular data)

Here is one approach using :nth-child. (example)
Just give each element a top/left border, then remove the top border for the first three and then remove the left border for the first, fourth, and seventh elements.
.item {
float: left;
width:300px;
height: 100px;
background:lightgrey;
border-left: 30px solid #fff;
border-top: 30px solid #fff;
}
.item:nth-child(-n+3) {
border-top:none;
}
.item:nth-child(3n + 1) {
border-left:none;
}
The padding width should be calculated dynamically, so for example if the container is 960px, the padding is going to be 30px wide.
You could use calc() for that.
Something like width:calc(33.333% - 20px) would work. This would limit the support to IE9 though.
Full Screen Example
Secondly, if there are less than 3 items on the last row, these should not appear centered on the row, i.e. if there are only two items then the last 'cell' should just be empty.
This should work as expected - example with the ninth item removed.

I thought I'd throw in a quick responsive example for usage in Bootstrap.
Using Bootstrap's grid system, the following CSS will remove any margin on the outer touching columns of a 3-column (per row) grid:
.tight-grid div[class*='col-']{
margin-top:15px;
margin-bottom:15px;
}
.tight-grid .row:first-child div[class*='col-'] {
margin-top:0;
}
.tight-grid div[class*='col-']:nth-child(3n+3){
margin-right:0;
}
.tight-grid div[class*='col-']:nth-child(3n + 1) {
margin-left:0;
}
.tight-grid .row:last-child div[class*='col-'] {
margin-bottom:0;
}
Keep in mind that columns already have left and right padding applied by bootstrap (15px worth). So if this is not the desired amount, override it in the first style rule of the above css snippet.
DEMO | CODE
NOTE: I know OP didn't ask for bootstrap, specifically. I just wanted to provide a simple way to do is using bootstrap for fun :)

Following your specification, this is:
Grid of items based on Divs;
Dynamically calculated spacing between items;
Cross Browser;
Specific item and container widths;
No hardcoded item classes to specific to the grid layout.
You can achieve that with this set of styles:
/* ensures the height correctness for the parent of .item, the #products. */
.clearfix{ clear:both }
#products{ border:1px solid gray; width:960px;}
.item{
float:left;
background-color:silver;
border:1px solid blue;
width:300px;
height:100px;
margin-left:2.5%;
margin-top:2.5%;
}
/* fixes top margin. */
.item:first-child, .item:first-child + *, .item:first-child + * + *{
margin-top:0px;
}
/* fixes margin of first divs on the left. */
.item:first-child,
.item:first-child + * + * + *,
.item:first-child + * + * + * + * + * + *,
.item:first-child + * + * + * + * + * + * + * + * + * {
margin-left:0px;
}
HTML
<div id="products">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="clearfix"></div>
</div>
You can watch this on JSFiddle.
Assumptions
I've added a div to the end of the container to ensure that it's height as in consideration the floated div's height. You can adjust this based on your specific overall disposition of html elements.
The margin-left fix implemented through this kind of rules .item:first-child + * + * + * is due to the cross browser requisite. I used the first-child selector with the '*' selectors, because it is supported by all main browsers (IE6+, FF, Chrome, SF, Opera). It's in fact hardcoded, but my idea about it, is that, if you want something less hardcoded then you can replace those rules by a rule targeting .item-head (the class that should be on all items next to the left border).
Anyway, I think that based on my simple solution, you can very easily evolve it to your desired solution. Have Fun!

I have somewhat of a solution, but it's not exactly what you're looking for, because I don't think what you want can be done without a solution that makes use of :nth-child (either natively or with a JS polyfill).
Take a look at my sample: http://jsfiddle.net/ncA64/1/
I've built product grids just like this many times. It gives you a fixed margin of 30px around each tile, and the width of each tile flexes to accommodate the width of the parent.
Code, for reference. HTML:
<div id="container">
<div class="item">
<div class="inner">
<!-- -->
</div>
</div>
<div class="item"><div class="inner"></div></div>
<div class="item"><div class="inner"></div></div>
<div class="item"><div class="inner"></div></div>
<div class="item"><div class="inner"></div></div>
<div class="item"><div class="inner"></div></div>
<div class="item"><div class="inner"></div></div>
<div class="item"><div class="inner"></div></div>
<div class="item"><div class="inner"></div></div>
<div class="item"><div class="inner"></div></div>
<div class="item"><div class="inner"></div></div>
</div>
and CSS:
/* basic box model reset */
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 0;
margin: 0;
border: none;
}
#container {
min-width: 960px;
margin: -30px -15px 0;
overflow: hidden;
}
.item {
width: 33.333333%;
float: left;
background: #fff;
}
.item .inner {
min-height: 100px;
margin: 30px 15px 0;
border: 1px solid #000;
background: #ffc;
}

text-align: justify for the container and display:inline-block for the items with no float (it float anyway... it's inline now).
Simple, responsive and works on lot of older browsers
EDIT: Forgot to say "and a additional div, to clear at the end, also display-inline, but 100% width"
http://jsfiddle.net/qFEB7/1/

Test this code:
body {
margin:0;
padding:0;
}
#wrapper {
overflow:hidden;
width:1200px;
margin:100px auto;
padding:10px;
display:table;
}
#container {
display:table-row;
}
.item {
width: 33.3333%;
min-height: 20px;
height: auto !important;
max-height: 200px;
word-wrap: break-word;
border-right:1px solid #ddd;
display:table-cell;
padding:10px;
border-bottom:1px solid #ddd;
border-top:1px solid #fff;
}
#container .item:first-child{
border-left:1px solid #ddd;
}
#container:first-child .item{
border-top:1px solid #ddd;
}
// use the html
<div id="wrapper">
<div id="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
</div>
<div id="container">
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
</div>
<div id="container">
<div class="item">7</div>
<div class="item">8</div>
<div class="item">9</div>
</div>
<div id="container">
<div class="item">10</div>
<div class="item">11</div>
<div class="item">12</div>
</div>
</div>

Related

CSS Float : 2 Divs, 1 div = Nav, 1 div = product. Full height NAV how to do this?

I want to setup the following using float.
Everything worked out fine except the nav div is not full height.
Screenshot : http://postimg.org/image/gywuh9lv1/
HTML :
<div class='container'>
<div class='left'>NAV PANEL FULL HEIGHT, ADJUST TO AMOUNTS OF PRODUCTS</div>
<div class='right'>
<div class='product'>PRODUCTS</div>
<div class='product'>PRODUCTS</div>
<div class='product'>PRODUCTS</div>
<div class='product'>PRODUCTS</div>
<div class='product'>PRODUCTS</div>
<div class='product'>PRODUCTS</div>
<div class='product'>PRODUCTS</div>
<div class='product'>PRODUCTS</div>
<div class='product'>PRODUCTS</div>
</div>
</div>
CSS :
float: left;
Just for info :
min-height:100%; NOT working.
For example : height:500px; is working but this is not dynamic, if my page has more content then it already fails.
Do something like this:
CSS
.container {
position: relative;
}
.right {
padding-left: 220px; /* Your left-nav width + padding here */
}
.left {
position: absolute;
top: 0; /* Or a px value if there's supposed to be a margin between this and the container. */
bottom: 0; /* Same as above */
width: 200px; /* Or however big you want to make it. */
}
This solution will actually force your left nav to grow with the container, instead of just making it look that way. It's also backwards compatible to most browsers and doesn't have any of the caveats that come with display: table;.
height:100% will only work if your html & body are height:100% too ;
Here is Codepen an example

Responsive design toggle using Bootstrap

I have this responsive design using Bootstrap's grid system:
HTML
<div class="container">
<div class="col-xs-12 col-md-7 view">
<div id="panelviewer">
<div class="row">
<div class="col-xs-12 col-md-6 panel1">ONE</div>
<div class="col-xs-12 col-md-6 panel2"><br><br>TWO</div>
</div>
</div>
</div>
</div>
CSS
.container {
max-width:600px;
overflow:visible;
}
.view {
border:dashed #333 1px;
}
.row {
overflow:visible;
}
#panelviewer {
position:relative;
}
#panelviewer .row {
white-space:nowrap;
}
.panel1 {
display:inline-block;
float:none;
background:#ccc;
vertical-align:top
}
.panel2 {
display:inline-block;
float:none;
background:#eee;
vertical-align:top
}
#media (min-width: 990px) {
#panelviewer {
width:671px;
}
}
.open {
right:100%;
margin-left:-34px;
}
I'm trying the create a toggle effect bringing a div into, and out of, view. I can't seem to the get the measurements right. Specifically, I have these questions:
Why is a 100% right offset combined with a margin-left value not bringing the entire div into view?
Why is the div's width not fitting to the parent (desktop only)?
Why is there a 4px gap between the two divs?
Take a look at (and resize) the JsFiddle demo to see what I mean.
Some answers to your question:
This is because there are negative margins influencing the position of each panels from Bootstrap CSS
Padding is declared in the parent, and when specifying 100% width on the panels, they will stretch to the content-box width of the parent, which excludes paddings.
This is because you have declared the two elements as inline-block elements: this means that the browser will treat them as inline elements when laying them out, and interpreting any whitespace between them as space: so the two elements are treated like two separate words.
What I would suggest is that you reset the margins and paddings for the .row element, and then instead of playing with both left and right positions, stick to one. Declare the individual panels as block-level elements, and use absolute positioning. However, since absolute positioning takes them out of the document flow, you will need to declare an explicit height for the parent.
.row {
overflow:visible;
position: relative;
width: 100%;
height: 50px; /* Or any desired value */
margin: 0;
}
#panelviewer {
position: relative;
}
.row > div {
position: absolute;
width: 100%;
}
.panel1 {
display: block;
background: #ccc;
}
.panel2 {
display: block;
background: #eee;
left: 100%;
}
.open {
left: -100%;
}
http://jsfiddle.net/teddyrised/7HcQ8/6/
Following Terry's answer, I ended up doing away with the padding on the parent div view. This brought the divs into line with the exception of the 4px space.
I then used the <!-- --> hack to remove it:
<div class="row">
<div class="col-xs-12 col-md-6 panel1">
ONE
</div><!--
--><div class="col-xs-12 col-md-6 panel2">
<br><br>TWO
</div>
</div>
See jsfiddle

css - How do I make the height of two right divs equal the height of the left divs

I have a site that is divided into two classes: right and left. The left had 3 boxes in it and the right had one. The box on the right's height would stretch or shrink to be the same as the sum of the height's of the left boxes. I have added another box underneath the box on the right and I want the same effect now with the two boxes (the sum of the height of the two boxes on the right should always equal the sum of the height of the three boxes on the left. Here is the old code that worked with the one box on the right:
<div class="right">
<div class="boxx details-history">
<div class="boxx-content">
Box content goes here
</div>
</div>
</div>
And here is the css:
.right{ float: right; display: inline; width:404px; position:relative; }
.boxx { margin-top:11px; }
.boxx:first-child { margin-top:0; }
.boxx .boxx-content { background: #fff; padding:4px 18px; color:#a7a7a7;
font-family: 'Roboto', sans-serif; font-weight:300; border-radius: 0 0 3px 3px; }
.details-history .boxx-content { padding: 0 0 0 0!important; position:absolute;
left:0; right:0; bottom:0; top:22px; }
Here is the new code:
<div class="right">
<div class="boxx details-history">
<div class="boxx-content">
Box content goes here
</div>
</div>
<div class="boxx details-coursework">
<div class="boxx-content custom-scroll">
Box content goes here
</div>
</div>
</div>
I've been trying for several hours now to write some css to make this work, but i can't seem to get it right. I think the trick has something to do with taking the 'position: absolute;' out of .details-history and putting it into a new class called details-coursework, but i can't figure out exactly what to do.
I used some sort of the task. In my example, there are two boxes: left and right. The right box should automatically adjust its height according to left box's height (which may be arbitrary). There is a lot of scrollable text in the right box.
#container {
width: 200px;
}
#left-positioner-parent {
position: relative;
/* Width of the left box relative to #container.
Could be in pixels too. */
width: 50%;
}
/* Contained style to exclude use of calc()
with border width and height in #right-box */
#left-box {
border: 15px solid red;
}
#right-box {
position: absolute;
/* To exclude use of calc() */
box-sizing: border-box;
left: 100%;
width: 100%;
top: 0;
height: 100%;
overflow-y: auto;
overflow-x: hidden;
border: 5px solid black;
}
#right-content {
/* No need of styling for this example */
}
<!-- A container for useful example width -->
<div id="container">
<!-- A different div for the left content is to allow
the left div to have borders without using CSS calc()
and border width and height in right div's style. -->
<div id="left-positioner-parent">
<div id="left-box">Left<br>block of text.</div>
<div id="right-box">
<!-- Some long scrollable content -->
<div id="right-content">Right<br>block<br>of<br>text<br>with<br>multiple<br>lines.</div>
</div>
</div>
</div>
Only way I can see this working without JS is to set heights for all the elements
HTML
<div class="wrapper">
<div class="left">
<div class="one"></div>
<div class="two"></div>
<div class="three"></div>
</div>
<div class="right">
<div class="one"></div>
</div>
</div>
CSS
.left {
width : 50%;
height : 1000px;
background : rgba(0,0,200,0.1);
float : left;
}
.right {
width : 50%;
height : 1000px;
background : rgba(200,0,0,0.1);
float : right;
}
.left div {
margin : auto;
margin-top : 20px;
width : 90%;
height : 100px;
background : rgba(200,0,0,0.1);
border : #FFFFFF 1px solid;
}
.right .one {
margin : 20px auto;
width : 90%;
height : 344px;
background : rgba(200,0,0,0.1);
border : #FFFFFF 1px solid;
}
Check out this Fiddle
You have to fake it. You simply can't do this with CSS. Percentage based heights with known number of boxes could help, but you would need JS to at least calculate and set the height of the parent. Without knowing your design, the easiest way to do this is something like this:
<div class="container">
<div class="right">
Whatever Content You Want
</div>
<div class="left">
Whatever Content You Want
</div>
<div class="clear"></div>
</div>
.right {
float:right;
width:404px;
}
.left { margin-right:404px; }
.clear { clear:both; } /* Or another clearing method */
This will create what you have for columns inside of a container that is as tall as the tallest element. What you would then do is put a backgound-image on the .container element that has a 404px graphic of some sort just on the right side of it. That would make it look like the right side appear as if it is as tall as the left side, but without it actually being that tall.

DIV width to content of other DIVs, floating and centering all

I would like to achieve something that initialy looked simple to me but turned out to be not.
My code is:
<html>
<head>
<style>
div {
border-top: 1px solid black;
margin: 10px;
}
div#all {
border: 0;
}
</style>
<body>
<div id=all>
<div class=first>First</div>
<div class=rowstarter>Row Starter</div>
<div class=content>Content</div>
<div class=content>Content</div>
<div class=content>Content</div>
<div class=content>Content</div>
<div class=content>Content</div>
<div class=rowstarter>Row Starter</div>
<div class=content>Content</div>
<div class=content>Content</div>
<div class=rowstarter>Row Starter</div>
<div class=content>Content</div>
<div class=content>Content</div>
<div class=content>Content</div>
<div class=content>Content</div>
</div>
</body>
</html>
What I'd like to get is all DIVs in "content" class are inline-blocks (or floats) set one after another from left to right.
The "rowstarter" class is the same but has to clear the before floats (start a new row).
The "first" DIV has to have a width equal to the content below (so if the window width allows the browser to display 5 "content" DIVs in a row, each having 100px width then "first" has 5 * 100px + 5 * (2 * 10px [margins]) = 600px if 6 "content" DIVs then "first" has 720px width...).
Is this possible without using Javascript, only with CSS?
As the number of content divs is going to be dynamic, you will need to use javascript in order to achieve what you want. There is no css that will allow you to do calculations to work out a percentage width based on number of child elements.
The alternative to javascript would be if you knew how many divs are in each row while you are generating your html, you can add inline styles for the widths
Here are some examples
Pure css (needs html layout change)
jQuery
I have posted a fiddle which I believe answers your question.
First, you have to give #all and each child div, except for .first, a left float:
#all,
#all div {
float: left;
}
#all .first {
float: none;
}
Then, clear .rowstarter on the left.
#all .rowstarter {
clear:left;
}
You actually don't need the "content" class at all (and I would recommend removing it, as it clutters the code and adds to the page weight).
Edit: If you add a .rowstarter div in front of the .first div, .rowstarter has to have a fixed width and the left margin of .first needs to increase by the sum of the width and margins of .rowstarter.
#all .rowstarter {
width: 100px; // arbitrary fixed width
margin: 10px; // you've given all divs inside #all this margin, just restating for emphasis
}
#all .rowstarter + .first {
margin-left: 130px; // width of .rowstarter, plus its left and right margins and .first's original 10px left margin
}
To achieve the centering of div#all you have to add a wrapper around it, then apply the following css trick:
.wrapper {
position: absolute;
left: 50%;
}
#all {
position: relative;
left: -50%;
}
I have set up a jsFiddle that probably answers your question. It now also contains the width but the added code is without any width so you are free to use what you want now
http://jsfiddle.net/agtFw/3
The HTML:
<div id="all">
<div class="first">First</div>
<div class="content rowstarter">Row Starter</div>
<div class="content">Content</div>
<div class="content">Content</div>
<div class="content">Content</div>
<div class="content">Content</div>
<div class="content">Content</div>
<div class="content rowstarter">Row Starter</div>
<div class="content">Content</div>
<div class="content">Content</div>
<div class="content rowstarter">Row Starter</div>
<div class="content">Content</div>
<div class="content">Content</div>
<div class="content">Content</div>
<div class="content">Content</div>
</div>
it is no problem to give 2 or more classes to a div and it helps you a lot sometimes!
and the css:
div {
border-top: 1px solid black;
margin: 10px;
}
div.content
{
float:left;
}
div.rowstarter
{
clear:left;
}
div#all {
border: 0;
}

CSS layout problem with borders

I'm currently working in the following site for a client http://minta.jvsoftware.com/ but I'm trying to make the top and bottom borders of the main container div to look like this http://awesomescreenshot.com/0f8jdwn71 basically make the borders span to the left up to the end of the screen (don't mind the red color this is supposed to be the same color as the border I have now).
I've been trying to come up with a solution but so far I have failed, I'm willing to try a JS/jQuery solution if implementing it with just css becomes too hard.
Can anyone help me? Thanks in advance!
You can achieve this by pure CSS with negative margins.
First you have to update the CSS for .container as follows:
.container {
clear: both;
font-family: "Times New Roman",Times,serif;
margin: 124px auto 36px;
padding: 0;
width: 940px;
}
Now wrap the content of the main div into another div and apply some css like this:
<div id="main" class="container clearfix" role="main">
<div style="border: 1px solid red; margin-left: -2000px; padding: 8px 8px 8px 2000px;">
<div class="content"> ... </div>
<div class="featured-image"> ... </div>
<div style="clear:both;"></div>
</div>
</div>
Here a screenshot to help you figure it out:
To achieve the layout you want, i think you have to put a at the left beside the container div and make them float left and give this div the border at the top and the bottom with the red color
Why you don't use "position:absolute"? In this case it's perfect solution I guess.
<style>
.topborder,
.bottomborder {
position:absolute;
left:-100px;
width:150px;
height:3px;
background:#ff0000;
z-index:999;
}
.topborder {
top:-3px;
}
.bottomborder {
bottom:-3px;
}
#main {
position:relative;
}
</style>
<div id="main" class="container clearfix" role="main">
<div class="topborder"></div><div class="bottomborder"></div>
your content
</div>