5

Consider the following

<div class="container">
     <div class="grid">
         <div class="unit"></div>
         <div class="unit"></div>
         <div class="unit"></div>
         <div class="unit"></div>
         <div class="unit"></div>
         <div class="unit"></div>
          ....
      </div>
</div>

Using images, basically what I have is something like this

enter image description here

As you can see the green blocks and the container are aligned to the left

What I want to acheive is something like this.

enter image description here

The .unit elements have constant width

The .grid element should expand with width (so that more unit elements would fit into 1 line) while being always centered within .container.

Any clue how to achieve that using only CSS (and maybe some html wrappers if necessary) ?

man
  • 197
  • 9
  • Without seeing the css it's hard to say. This is being caused by your floats. When you are using floats, there is no easy way to center the children in the parent container. If the container is a fixed width, you may be able to add `margin: 0 auto;` to it so the container itself is centered. – EternalHour Jul 14 '14 at 02:38
  • I'm not doing any floats .. margin wont work because If I set `grid` to `block` there is no way to center the `units` as in the image – man Jul 14 '14 at 18:16

5 Answers5

1

Let me begin by saying that this is an interesting question and my first thought was that flexbox is the way to solve this. I have tried all manner of flexbox arrangements, but this type of solution eluded me. So, below is the solution that uses floating, clearing, and media queries.

For this example, I have assumed that each row would have at least 3 and no more than 9 boxes. However, you can extend this solution to handle anywhere between 1 and more than 9 boxes.

Here's HTML:

<div class="grid">
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
</div>

Here's a CSS that (1) performs a mini-reset to eliminate browser-applied paddings and margins that may interfere with sizing and (2) formats the .grid and its div children:

* {
    margin: 0;
    padding: 0;
}

.grid {
    display: table;
    outline: 1px solid blue;
    min-width: 330px;
    margin: 0 auto;
}

.grid > div {
    width: 100px;
    height: 61px;
    margin: 5px;
    background-color: teal;
    float: left;
}

The .container block was eliminated because .grid is displayed as a table. The latter is a block that shrinkwraps around its children and margin: 0 auto can be applied to center it on the page. The .grid's min-width of 330px assures that a minimum of three blocks can fit per line. Whenever floating happens within a table element, its margins do not collapse, therefore no explicit clearing of floats (e.g., via clearfix) is necessary.

Each .grid div child takes 110px of horizontal space (100px width + 10px in left and right margins). This number is important for the media queries code that follows below:

@media screen and (min-width: 330px) and (max-width: 439px) {
    .grid > div:nth-of-type(3n + 1) {
        clear: left;
    }
}

@media screen and (min-width: 440px) and (max-width: 549px) {
    .grid > div:nth-of-type(4n + 1) {
        clear: left;
    }
}

@media screen and (min-width: 550px) and (max-width: 659px) {
    .grid > div:nth-of-type(5n + 1) {
        clear: left;
    }
}

@media screen and (min-width: 660px) and (max-width: 769px) {
    .grid > div:nth-of-type(6n + 1) {
        clear: left;
    }
}

@media screen and (min-width: 770px) and (max-width: 879px) {
    .grid > div:nth-of-type(7n + 1) {
        clear: left;
    }
}

@media screen and (min-width: 880px) and (max-width: 989px) {
    .grid > div:nth-of-type(8n + 1) {
        clear: left;
    }
}

@media screen and (min-width: 990px) {
    .grid > div:nth-of-type(9n + 1) {
        clear: left;
    }    
}

The rationale behind the code is this: if there is enough space to include only n blocks per line, then every (n + 1)th block's left edge is cleared, which moves the block to a new line.

And, here's a fiddle: http://jsfiddle.net/5hWXw/. Resize the preview window to see the adjustments.

DRD
  • 5,557
  • 14
  • 14
  • This actually solve the issue, but the problem is its not generic. Imagine I have like 20 blocks in 1 row, or more, being conditional on the screen width is something I don't want to rely on – man Jul 14 '14 at 18:24
  • We all have to work within certain limitations. Given the specifics of your request - CSS-only solution that centers a `.grid` that stretches just enough, within its container, to perfectly shrinkwrap fixed-sized blocks that flow to the left - that's the best I could come up with. Cheers. – DRD Jul 14 '14 at 19:24
  • And, here's a product of my conversation with @Tyblitz - a generalizable solution that uses jQuery: http://jsfiddle.net/GWQSe/. – DRD Jul 14 '14 at 20:33
  • Seems that it is doable without the need of jquery, just by adding trailing empty elements – man Jul 14 '14 at 23:16
  • The size of the `.unit` and the width of the user's browser will affect how many trailing empty elements you will need. That will definitely require some good 'ole code. And, this is hardly an optimal solution because if, say, for one screen size you'll need 5 trailing blocks, then for a resized browser some of those trailing elements would need to be removed. More code. Overall, using spacer elements reminds of the days of spacer gifs. That's not the most elegant way to do things. Using pure CSS with media queries sounds a lot better. – DRD Jul 15 '14 at 00:16
0

In your CSS, make sure: 1. In the .grid rule, text-align is set to center 2. In the .unit rule, display is set to inline-block. The div element is a block-level element and so each new element is displayed on a new line. Giving the display property a value of inline-block forces all the divs with class unit to be displayed on the same line (until there's no more space). Also text-align : center doesn't work with elements with display property set to block, and block-level elements have a display value of block by default.

0

You have to just give value to your classes like this,

.grid { text-align:center; }

.unit { display:inline-block; }

I hope this will solve your issue.

If not, than please show your full code via Jsfiddle.

Husen
  • 955
  • 1
  • 6
  • 16
0

@DRD's answer is nice but requires lots of media queries. If the following floats your boat however: don't look too far when it can be simple: set a padding-left/-right on your container...

.grid {
  padding: 0 5%;
}

You'll notice the whitespace is not even when the width isn't a multiplication of the .unit 's entire box (padding, margin, border, width). Setting a %-based width can help here.

See this fiddle for a test case. I've added a tiny bit of Javascript to adjust the padding dynamically, remove it to see the CSS-only result. EDIT: @DRD created a jQuery function which works better than my JS, see it here (don't forget to include jQuery if you want to use it).

webketje
  • 10,376
  • 3
  • 25
  • 54
  • I'd love to see a fiddle of this solution. – DRD Jul 14 '14 at 18:39
  • @DRD, I forked your fiddle and added it to my answer, good point. – webketje Jul 14 '14 at 19:31
  • 1
    Using JS to adjust the padding is one way to do, but it also creates a lot of flickering. Here's a solution that let's the browser do all the positioning and the script decides to which elements the `clear: left` is applied. The experience is much smoother and the solution is generalizable without any need to use media queries: http://jsfiddle.net/GWQSe/. Also, it uses less processing power even though I am using jQuery instead of talking to DOM directly. – DRD Jul 14 '14 at 20:31
  • @DRD Great fix, I'll add it to my answer! The flickering only occurs when downsizing the window (?), I didn't take the time to correct that in regular JS. Makin' this work in native JS would be the cherry on the cake. Although if the function is only triggered on page load (users don't go around resizing windows all the time, though they occasionally might), both work fine. Thanks a lot for your addition. – webketje Jul 14 '14 at 21:58
0

It seems that a solution to this is similar to that in here Flex-box: Align last row to grid

First of all setting .grid to inline, then adding more div's with height: 0 would do the trick, number of extra div's should be atleast equal to max-number of units in 1 line (minus 1).

This is a bit incontinent, but still easier than defining multiple @media as @DRD suggested, and doesn't require javascript/window.resize() handling

<div class="container">
    <div class="grid">
        <div class="unit"></div>
        <div class="unit"></div>
        <div class="unit"></div>
        <div class="unit"></div>
        <div class="unit"></div>
        <div class="unit"></div>
        <div class="unit empty"></div>
        <div class="unit empty"></div>
        <div class="unit empty"></div>
        <div class="unit empty"></div>
        <div class="unit empty"></div>
        <div class="unit empty"></div>
        <div class="unit empty"></div>
    </div>
</div>


.container {
   display: block;
   text-align: center;
}

.empty {
   height: 0 !important;
}

.grid {
   display: inline;
}

I still hope for a better solution using only css

Community
  • 1
  • 1
man
  • 197
  • 9
  • The codepen referred to in the post that you have linked to uses flexbox arrangement where boxes' dimensions change depending on the browser width: http://jsfiddle.net/4z8b4/. The minute you fix their width, the solution falls apart: http://jsfiddle.net/nkX6p/. – DRD Jul 15 '14 at 00:53
  • One more thing and I am done with this thread. CSS is still a presentational language, so pick your battles, dude. I predict that in the future many more things that we do in JS we'll do easily in CSS. – DRD Jul 15 '14 at 01:06