ditto ditto - 5 months ago 18
CSS Question

Positioning li.active to the center of it's parent element, and shifting the remaining items around it

I have a horizontal list that I'm trying to position so that the

li.active
is the centre of parent element.



div {
display:block;
width:100%;
text-align:center;

}
ul {
transform: translateX( calc(50% - (150px / 2) - (150px * 6)) );
overflow:hidden;
white-space:nowrap;
direction:rtl;
}
li {
display:inline-block;
background:blue;
height:300px;
width:150px;

}
li.active {
background:white;
background:green;
}

span {
display:block;
width:150px;
background: purple;
height:150px;

position:absolute;
top:0;
left: calc(50% - 75px);
}
* {
font-size:0;
padding:0;
margin:0;
}

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

<span></span>





Do note, I'll be adding items dynamically, so I've set the
ul
with
direction:rtl;
, so when a new item is added it will not affect the
transform: translateX
positioning.

In this example: http://jsbin.com/fafedowaza/edit?html,css,output - I'm to center the green block, so that it'll underlap the purple block.

How may I achieve this?

Answer

1. Transform: translateX

I changed display property for ul to inline-block so it can rely on it's content width instead of parent's. Also I noticed you count the green block twice when you wrote the calc statement, change (150px * 6) to (150px * 5). This solution works only when the window (or parent) is at least 900px width (6*150px).

div {
  display: inline-block;
  display: block;
  width: 100%;
  text-align: center;
}
ul {
  transform: translateX( calc(50% - (150px / 2) - (150px * 5)));
  overflow: hidden;
  white-space: nowrap;
  direction: rtl;
  display: inline-block;
  overflow: hidden;
}
li {
  display: inline-block;
  background: blue;
  height: 300px;
  width: 150px;
}
li.active {
  background: green;
}
span {
  display: block;
  width: 150px;
  background: purple;
  height: 150px;
  position: absolute;
  top: 0;
  left: calc(50% - 75px);
}
* {
  font-size: 0;
  padding: 0;
  margin: 0;
}
<div>
  <ul>
    <li class="active"></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
  </ul>
</div>

<span></span>

2. Position: absolute

This one will work regardless of parent's width. I'm not sure why transform: translateX behave itself this way, haven't use it much, but looks like position: absolute did the trick.

div {
  display: block;
  width: 100%;
  position: relative;
}
ul {
  position: absolute;
  left: calc(50% - (150px / 2) - (150px * 5));
  white-space: nowrap;
  direction: rtl;
  display: inline-block;
}
li {
  display: inline-block;
  background: blue;
  height: 300px;
  width: 150px;
}
li.active {
  background: green;
}
span {
  display: block;
  width: 150px;
  background: purple;
  height: 150px;
  position: absolute;
  top: 0;
  left: calc(50% - 75px);
}
* {
  font-size: 0;
  padding: 0;
  margin: 0;
}
<div>
  <ul>
    <li class="active"></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
    <li></li>
  </ul>
</div>

<span></span>

3. Adding items dynamically

I'm not sure what you meant when you said that you can add items dynamically and it won't affect the positioning, because you set calc statement based on quantity of li elements. This way, when you add a li you should change the calc statement or at least add another css class to ul which will override the old rule. If you're planning to add/remove li elements via JavaScript you will probably use it for fixing the positioning too. If your list of items is going to be dynamic on the server side, you can set a css class to your ul accordingly to the quantity of it's li elements.