3

I have a ul element and 5 child <li>.

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

The <ul> has a display: flex property. I tried using the calc property on the <li> to evenly size my list items:

calc:(100% / 5);

This gives the desired result and evenly sizes the 5 <li> blocks

Now I added borders to the right side of all, but the last child <li> element. So I reduced the total width of all the borders combined from the total width of the <ul>.

calc:((100% - 8px) / 5);

This also worked properly and evenly sized the <li> blocks with the borders.

ul {
  width: 600px;
  height: 300px;
  margin: 0;
  padding: 0;
  display: flex;
  background: red;
}

li {
  list-style: none;
  display: block;
  width: calc((100% - 0.8px) / 5);
  height: 100%;
  border-right: 0.2px solid black;
  background: blue;
}

li:last-child {
  border-right: none;
}
<ul>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
</ul>

Now I tried to set the border width in viewport unit vw instead of px but it gives a different result.

ul {
  width: 600px;
  height: 300px;
  margin: 0;
  padding: 0;
  display: flex;
  background: red;
}

li {
  list-style: none;
  display: block;
  width: calc((100% - 0.8vw) / 5);
  height: 100%;
  border-right: 0.2vw solid black;
  background: blue;
}

li:last-child {
  border-right: none;
}
<ul>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
</ul>

As you can see from the snippet above, there is a little bit of space to the right. This becomes bigger with a wider viewport (try viewing the snippet full page). So I think the problem lies with the vw units and flexbox here.

So what is the cause of this error?

EDIT:

From the provided answers and comments, I have seen there are other and more proper approches to achieve what I was trying to do. I appreciate those answers but those are not the answers to my question. Since calc is showing an error in this case, most likely it will cause more problems when I try to use calc and viewport units in other cases (not just borders). So I need to know the reason and "calc" fix.

  • 1
    I'm not sure why that's happening, but fyi in case you didn't know, you can use `box-sizing: border-box;` and the border width won't impact the element's outer width. – Michael Coker Mar 04 '17 at 06:19
  • It's a little weird to use `%` and `vw` in `calc`, because both `%` and `vw` are percentage on different bases. You didn't say anything about parent of `ul`. Let say width of `ul` parent is 300px and the viewport width i.e `vw` is 400px, so `0.8vw` is more than you expect and there is white space. – ata Mar 04 '17 at 06:21
  • @MichaelCoker Yeah I saw the calc alternative post "http://stackoverflow.com/questions/16034397/css-calc-alternative?rq=1" and was thinking of trying out box-sizing. –  Mar 04 '17 at 06:28
  • @ata Why is the parent ul necessary? It does not affect the li in any way. I guess you misunderstood the question. –  Mar 04 '17 at 06:30
  • @AnuragDaolagajao Yes you're right I made a mistake but the concept is true. Width of `ul` is 600px but width of viweport might be more than 600px, then `0.8vw` is more than `0.8%` and there will be a white space. – ata Mar 04 '17 at 06:35
  • @AnuragDaolagajao: What exactly is the question? What are you trying to achieve? If all you want is to keep the `li` same width across the `ul`, then you are doing it wrong. What's with the border width units? What is `0.2px`?? And why do you want it in `vw`? I mean what do you really want to do is unclear from the question. – Abhitalks Mar 04 '17 at 06:37
  • @ata You are mistaken. It was nowhere mentioned that the combined border width has to be 0.8%. Also there is no relation between vw and the % width of my li. –  Mar 04 '17 at 06:41
  • @AnuragDaolagajao: That's it? Adding an answer soon. – Abhitalks Mar 04 '17 at 06:46
  • I have updated the question. I don't want a fix, but want to find the reason of the error –  Mar 04 '17 at 06:48
  • If the number of li are constant, use 20% instead because using calc to get a known value just slows your page down for useless calculations. – zer00ne Mar 04 '17 at 06:54

3 Answers3

2

You don't need to do calc to add inner content for your li. If you give the box-sizing: border-box; prop, border and padding will not make the container grows.

ul {
  width: 600px;
  height: 300px;
  margin: 0;
  padding: 0;
  display: flex;
  background: red;
}

li {
  list-style: none;
  display: block;
  width: calc(100% / 5);
  height: 100%;
  border-right: 2px solid black;
  background: blue;
  box-sizing: border-box;
}

li:last-child {
  border-right: none;
}
<ul>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
</ul>
Maxwell s.c
  • 1,583
  • 15
  • 29
0

It seems you are using flex to distribute your lis inside of your ul. In this case, you do not need to calculate the widths to make those equal. That is what flex is supposed to do.

See this example:

* { box-sizing: border-box; margin: 0; padding: 0; }
ul, li { list-style: none; }
ul { width: 600px; height: 300px; background: red; display: flex; }
li {
  flex: 1 0 auto;
  border-right: 0.8vw solid black;
  background: blue;
}
li:last-child { border-right: none; }
<ul>
  <li></li><li></li><li></li><li></li><li></li>
</ul>

When specifying flex dsiplay on containers, you just need to apply the flex property on the children to make them behave as flexible items. In your specific use-case, you need the following:

  1. flex-grow: set to 1. This will allow your li to grow to fill the entire ul width.
  2. flex-shrink: set to 0. You do not want your li to shrink.
  3. flex-basis: set to auto. You want your li to grow to an equalized width automatically.

So, you see, you do not need calc at all.

You also, need not to specifically apply display: block to your lis. As per the specs here: https://www.w3.org/TR/css-flexbox-1/#flex-items

The display value of a flex item is blockified: if the specified display of an in-flow child of an element generating a flex container is an inline-level value, it computes to its block-level equivalent

As pointed out by @BoltClock in the comments, the list-item is already blockified.

Borders

Now, coming to borders. In your first example you have specified the width in 0.2px unit. This makes no sense. Although the specs allow fractional pixels, it will round it off to the nearest pixel available on display which is usually 1.

In you second example, you want the borders to scale with the viewport. That's good. No problem with the 0.8vw.

Just see the example I posted, in this fiddle. Resize the result window and you will see the borders changing relative to the viewport size.

Lastly, you may or may not want to set the box-sizing. It depends on your layout. Whatever you use, you use it consistently.

Abhitalks
  • 27,721
  • 5
  • 58
  • 81
  • "You also, need not to specifically apply display: block to your lis." He only doesn't need to do so because he already sets list-style: none. The text that you quote doesn't apply to display: list-item because display: list-item is a block-level display type, not an inline-level display type (that would be display: inline-list-item). – BoltClock Mar 04 '17 at 07:04
  • Thanks @BoltClock. I missed that. Adding to the answer. "*He only doesn't need to do so because he already sets list-style: none.*" - list-style of none shouldn't be a factor here, as it is still a list-item. See this: https://jsfiddle.net/abhitalks/mu4ds20p/1/ – Abhitalks Mar 04 '17 at 07:09
  • @Anurag, any specific reason to un-accept the answer? – Abhitalks May 04 '17 at 06:29
0

Pixels (px): Absolute pixels. So for example, 20px will be literally 20 pixels on any screen. If a monitor is of 1980x1200, and you set an element's height to 200px, the element will take 200 pixels out of that.

Viewport height/width (vw/vh): Size relative to the viewport (browser windoe, basically).

1px = (100 / document.documentElement.clientWidth)vw 1px = (100 / 500) = 0.2vw

Piyali
  • 506
  • 2
  • 11