4

I want to make the UL (yellow) wrap the LI list elements (purple) horizontally without any fixed widths on the UL. The wrap has been added for the example.

HTML

  <ul>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
  </ul>

</div>

CSS

.wrap {
  background: green;
  width: 500px;
  padding: 10px 20px;
}

li {
  display: inline-block;
  width: 70px;
  height: 50px;
  background: purple;
  list-style: none;
}

ul {
  background: yellow;
  margin: 0; padding: 0;
}

Currently

Current CSS

Desired

Desired CSS

CodePen here: http://codepen.io/ptimson/pen/IrCHB

ptimson
  • 5,533
  • 8
  • 35
  • 53
  • Does li have to have a fix width of 70px ? – Ani May 27 '14 at 21:57
  • Yes. It can be anything but I used 70 as an example. – ptimson May 27 '14 at 22:00
  • Not sure if I am understanding this... The `ul` gets its width from its parent as its `max-width`. If you don't specify width in `ul` you get the width as its parent has. I mean, you have to specify some width in some element or you will finally get the body width – kosmos May 27 '14 at 22:02
  • And there's no way of wrapping the ul (or a div) around its content? – ptimson May 27 '14 at 22:05
  • If you want to fit the
      to the
    • items, how do you intend to define that line break occurs right after the sixth
    • ? if they all have display: inline-block; AND
        IS WHITE-SPACE:NORMAL;?
    – LGVentura May 27 '14 at 22:06
  • No, there is no way. As point... You can remove that ugly margins using `font-size: 0;` into `ul` rule – kosmos May 27 '14 at 22:06
  • Does it need to work in older browsers? If not, you could use `calc` to set the width like this: http://codepen.io/anon/pen/kiamq (also using @LGVentura's suggestion of setting font-size to 0 to remove the padding between LIs). – APAD1 May 27 '14 at 22:08
  • Note that calc doesn't work on most mobile browsers (I think currently only works on firefox mobile), opera browser and IE >= 9 – kosmos May 27 '14 at 22:12
  • I don't want to set the width of UL as it will resize in my real example. Ok so it may seem that only way of this could work would be a JS solution. – ptimson May 27 '14 at 22:13
  • 1
    @ptimson - Maye [this](http://stackoverflow.com/a/23805732/703717) is what you are looking for. – Danield May 27 '14 at 22:14
  • 1
    @Danield This looks like what I'm aiming for cheers – ptimson May 27 '14 at 22:18
  • @ptimson - you're welcome :) - you can easily change the markup to list items instead of divs, and you can also play around with the LESS variables to customise the layout as you need it. – Danield May 27 '14 at 22:24
  • @Danield Could you post as answer so I can accept please – ptimson May 27 '14 at 23:20

4 Answers4

7

Add this to the parent <ul> of the list

ul {
  display: flex;  
  flex-wrap: wrap;
}

That will cause the <li> to wrap as you want. Then add some margin/padding to the right of the <li> elements so they're reasonably spaced.

Lyall
  • 1,367
  • 3
  • 17
  • 42
4

To date, the only way you can do this with CSS alone is with media queries - one media query for each #columns layout necessary.

This can be quite tedious using css.

Fortunately, you can automate this using a preprocessor such as LESS.

So say that I have basic markup of <li>'s within an <ul>...

Here's how to take advantage of LESS to set up the media queries:

CODEPEN - Resize the window to see this in action

First set up some less variables according to the design which you need:

@item-width:100px;
@item-height:100px;
@marginV: 4px;
@marginH: 2px;
@min-cols:2;
@max-cols:9; //set an upper limit of how may columns you want to write the media queries for

Then:

Set up an iteration mixin like this: (You can paste this code into http://less2css.org)

.loopingClass (@index-width) when (@index-width <= @item-width * @max-cols) {
    @media (min-width:@index-width) {
        .container{
            width: @index-width;
        }
    }

    .loopingClass(@index-width + @item-width + 2*@marginH);
}

.loopingClass (@item-width * @min-cols + @min-cols*@marginH*2);
Danield
  • 121,619
  • 37
  • 226
  • 255
0
<div class="wrap">
  <ul>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li><br>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
  </ul>
</div>

css

.wrap {
  display:table;
  background: green;
  padding: 10px 20px;
}
ul {
    display:table;
  background: yellow;
  margin: 0;
  padding: 0;
    font-size: 0;
}
li {
  margin:0 4px 4px 0;
  display: inline-block;
  width: 70px;
  height: 50px;
  background: purple;
  list-style: none;
}
li:nth-child(7){
    margin-right: 0px;
}

******************************************************************

other

<div class="wrap">
<ul>
    <li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li>
</ul>
</div>

also

<div class="wrap">
<ul>
    <li>
    <li>
    <li>
    <li>
    <li>
    <li>
    <li>
    <li>
    <li>
    <li>
    <li>
  </ul>
</div>

css

.wrap {
  background: green;
  width: 520px;
  padding: 10px 20px;
}
ul {
  background: yellow;
  margin: 0;
  padding: 0;
  border:0;
}
li {
  position:relative;
  display: inline-block;
  width: 70px;
  height: 50px;
  background: purple;
  list-style: none;
  margin-right: 5px;
}
li:nth-child(7){
    margin-right: 0px;
}
li:nth-child(14){
    margin-right: 0px;
}

This isn't a "bug" (I don't think). It's just the way setting elements on a line works. You want spaces between words that you type to be spaces right? The spaces between these blocks are just like spaces between words. That's not to say the spec couldn't be updated to say that spaces between inline-block elements should be nothing, but I'm fairly certain that is a huge can of worms that is unlikely to ever happen.

Here's some ways to fight the gap and get inline-block elements sitting directly next to each other.

Remove the spaces The reason you get the spaces is because, well, you have spaces between the elements (a line break and a few tabs counts as a space, just to be clear). Minimized HTML will solve this problem, or one of these tricks:

<ul>
  <li>
   one</li><li>
   two</li><li>
   three</li>
</ul>

or

<ul>
  <li>one</li
  ><li>two</li
  ><li>three</li>
</ul

or with comments...

<ul>
  <li>one</li><!--
  --><li>two</li><!--
  --><li>three</li>
</ul>

They're all pretty funky, but it does the trick.

Negative margin You can scoot the elements back into place with negative 4px of margin (may need to be adjusted based on font size of parent). Apparently this is problematic in older IE (6 & 7), but if you don't care about those browsers at least you can keep the code formatting clean.

display: inline-block;
  margin-right: -4px;

Skip the closing tag HTML5 doesn't care anyway. Although you gotta admit, it feels weird.

<ul>
  <li>one
  <li>two
  <li>three
</ul>
alessandrio
  • 4,282
  • 2
  • 29
  • 40
-4

Change the width of wrap to 435px-ish, that should be it!

Geroy290
  • 468
  • 2
  • 9
  • 24