7

I have a css question for a change. One that is best described with an image. enter image description here

The exact definition. I have a div with multiple inline div's inside of it. I want to set a class to one of them (yellow one) to center it and move the rest of them accordingly in one line (outside div has overflow hidden) If i make second one from the right yellow, it would get centered and there will be three of them on the left side, then it(centered) and one on the right. I hope I made it clear. I know it can be done with javascript but everything is fluid so that would introduce couple of problems later on while re-sizing the whole page.

Help appreciated.

Thanks, Peter

Peter Kottas
  • 893
  • 13
  • 27
  • Not possible with CSS. – Paulie_D Jul 13 '15 at 12:04
  • @Paulie_D This is probably possible using CSS (see: http://stackoverflow.com/questions/8720931/can-css-detect-the-number-of-children-an-element-has and the linked resources on the accepted question) but it will push CSS to its limit and blow up the file size of the resulting CSS. – feeela Jul 13 '15 at 12:27
  • 1
    @feeela I'm doubtful, very doubtful. You have no way of knowing the size of the elements (I'm assuming these are dynamic and thus variable) and there is no selector that can decide on the position of the **previous** sibling. – Paulie_D Jul 13 '15 at 12:40
  • @Paulie_D But you can know **how many** siblings there are and use percentages to move them to the left. But I would also use JS. – feeela Jul 13 '15 at 14:15
  • @feeela You'd have to prove it to me...I'm still not sure how you would even use percentages when you don't know the width of any of the items or what percentage of the total width is taken up by the sum of the internal divs. Plus doing this with **one class** ...nah! – Paulie_D Jul 13 '15 at 14:18
  • @Paulie_D Don't you tell me this won't work. You know, such statements push my motivation to 600%! [See below for a prove.](http://stackoverflow.com/questions/31382636/center-one-of-many-spans-in-div-horizontaly/31388066#31388066) – feeela Jul 13 '15 at 16:00
  • But doesn't your answer require all the items to be the same size? What if they aren't..the provided image indicates that they won't be. – Paulie_D Jul 13 '15 at 16:07
  • @Paulie_D In a slider or similar display, the items in a row a typically equally sized. And the image could be a mistake. Nonetheless this is also possible using different widths – but as fixed percentage values, which should sum up to 100%. – feeela Jul 13 '15 at 16:09
  • If you see the comment on the other answer he states that fixed sizes are an issue. Anyway, nice effort. – Paulie_D Jul 13 '15 at 16:19

3 Answers3

3

(tl;dr: http://jsfiddle.net/feeela/3eq8dcLc/)

Health advice: Use JavaScript for such tasks, or you maybe get crazy.

Having said that, I present to you a fluid CSS-only version.

The variables you need to know are:

  • How many items are in the list
  • Which item should get highlighted

Both can be solved in CSS.


Limitations:

  • Each list-count must be written down in CSS; so if you have a slider, which may contain three to hundred items, you have to write the CSS 98 times.
  • Doesn't work with floated items inside an inner wrapper (the usual way a slider is set up) – you can't translate the inner wrapper, because there is no way of knowing how many children an element has – thus you don't know how far to translate to the left or right. You can only work directly on the individual items (as counting siblings is possible).

Knowing this, you cannot move a row of items by setting a class name to the targeted item (the one which should get highlighted) but you can do so by using a class name on the parent container.


Example markup:

<div class="slider item-4">
    <ul>
        <li>Lorem ipsum dolor sit amet</li>
        <li>Consectetur adipisicing elit</li>
        <li>Alias aspernatur</li>
        <li>Assumenda atque aut consectetur</li>
        <li>Consequatur culpa dolore</li>
    </ul>
</div>

Step 1:

Set the item widths as percentages, based on the count of its siblings.

For an explanation on how this works, see https://stackoverflow.com/a/12198561/341201 and the linked resources.

/* two items */
.slider > ul li:first-child:nth-last-child(2),
.slider > ul li:first-child:nth-last-child(2) ~ li {
    width: 50%;
}

/* three items */
.slider > ul li:first-child:nth-last-child(3),
.slider > ul li:first-child:nth-last-child(3) ~ li {
    width: 33.3333%;
}

Step 2:

Move the first item using a positive (move to right) or negative (move to left) margin based on the position of the highlighted item and the sibling count. This is the tricky part.

/* Second item
  Notes:
  - The second item of three is already in the middle
*/
.slider.item-2 > ul li:first-child:nth-last-child(2) {
    margin-left: -25%;
}
.slider.item-2 > ul li:first-child:nth-last-child(4) {
    margin-left: 12.5%;
}
.slider.item-2 > ul li:first-child:nth-last-child(5) {
    margin-left: 20%;
}
.slider.item-2 > ul li:first-child:nth-last-child(6) {
    margin-left: 25%;
}

/* Third item
  Notes:
  - No third item in a list of two
  - The third item of five is already in the middle
*/
.slider.item-3 > ul li:first-child:nth-last-child(3) {
    margin-left: -33.3333%;
}
.slider.item-3 > ul li:first-child:nth-last-child(4) {
    margin-left: -12.5%;
}
.slider.item-3 > ul li:first-child:nth-last-child(6) {
    margin-left: 8.3333%;
}

/* …expand as required up to N items */

I prepared an example which works with two to six items in a row. If your sliders may contain more items, you have to expand the CSS accordingly.

Full example:

(Also available as JS fiddle)

hr {
    /* visual sugar */
    margin-top: 5em;
    margin-bottom: 5em;
}

.slider {
    overflow: hidden;
}

.slider > ul {
    margin: 0;
    padding-left: 0;
    list-style: none;
    white-space: nowrap;
}

.slider > ul li {
    box-sizing: border-box;
    display: inline-block;
    overflow: hidden;
    margin-left: -4px;
    min-height: 5rem;
    white-space: normal;
    border: 1px solid black;
}
.slider > ul li:first-child {
    margin-left: 0;
}

/* The following sections sets the slider item widths */

/* two items */
.slider > ul li:first-child:nth-last-child(2),
.slider > ul li:first-child:nth-last-child(2) ~ li {
    width: 50%;
}

/* three items */
.slider > ul li:first-child:nth-last-child(3),
.slider > ul li:first-child:nth-last-child(3) ~ li {
    width: 33.3333%;
}

/* four items */
.slider > ul li:first-child:nth-last-child(4),
.slider > ul li:first-child:nth-last-child(4) ~ li {
    width: 25%;
}

/* five items */
.slider > ul li:first-child:nth-last-child(5),
.slider > ul li:first-child:nth-last-child(5) ~ li {
    width: 20%;
}

/* six items */
.slider > ul li:first-child:nth-last-child(6),
.slider > ul li:first-child:nth-last-child(6) ~ li {
    width: 16.6666%;
}

/* N items – expand as required… */



/* Highlight a specific item */
.slider.item-2 > ul li:nth-child(2),
.slider.item-3 > ul li:nth-child(3),
.slider.item-4 > ul li:nth-child(4),
.slider.item-5 > ul li:nth-child(5),
.slider.item-6 > ul li:nth-child(6) {
    background: yellow;
}


/* This sections centers a specific item */

/* Second item
  Notes:
  - The second item of three is already in the middle
*/
.slider.item-2 > ul li:first-child:nth-last-child(2) {
    margin-left: -25%;
}
.slider.item-2 > ul li:first-child:nth-last-child(4) {
    margin-left: 12.5%;
}
.slider.item-2 > ul li:first-child:nth-last-child(5) {
    margin-left: 20%;
}
.slider.item-2 > ul li:first-child:nth-last-child(6) {
    margin-left: 25%;
}

/* Third item
  Notes:
  - No third item in a list of two
  - The third item of five is already in the middle
*/
.slider.item-3 > ul li:first-child:nth-last-child(3) {
    margin-left: -33.3333%;
}
.slider.item-3 > ul li:first-child:nth-last-child(4) {
    margin-left: -12.5%;
}
.slider.item-3 > ul li:first-child:nth-last-child(6) {
    margin-left: 8.3333%;
}

/* Fourth item
  Notes:
  - No fourth item in a list of two and three
*/
.slider.item-4 > ul li:first-child:nth-last-child(4) {
    margin-left: -37.5%;
}
.slider.item-4 > ul li:first-child:nth-last-child(5) {
    margin-left: -20%;
}
.slider.item-4 > ul li:first-child:nth-last-child(6) {
    margin-left: -8.3333%;
}

/* Fifth item
  Notes:
  - No fifth item in a list of two, three and four
*/
.slider.item-5 > ul li:first-child:nth-last-child(5) {
    margin-left: -40%;
}
.slider.item-5 > ul li:first-child:nth-last-child(6) {
    margin-left: -25%;
}

/* Sixth item
  Notes:
  - No sixth item in a list of two, three, four and five
*/
.slider.item-6 > ul li:first-child:nth-last-child(6) {
    margin-left: -41.6666%;
}
<h3>Highlight second item</h3>

<div class="slider item-2">
    <ul>
        <li>Lorem ipsum dolor sit amet</li>
        <li>Consectetur adipisicing elit</li>
    </ul>
</div>

<div class="slider item-2">
    <ul>
        <li>Lorem ipsum dolor sit amet</li>
        <li>Consectetur adipisicing elit</li>
        <li>Alias aspernatur</li>
    </ul>
</div>

<div class="slider item-2">
    <ul>
        <li>Lorem ipsum dolor sit amet</li>
        <li>Consectetur adipisicing elit</li>
        <li>Alias aspernatur</li>
        <li>Assumenda atque aut consectetur</li>
    </ul>
</div>

<div class="slider item-2">
    <ul>
        <li>Lorem ipsum dolor sit amet</li>
        <li>Consectetur adipisicing elit</li>
        <li>Alias aspernatur</li>
        <li>Assumenda atque aut consectetur</li>
        <li>Consequatur culpa dolore</li>
    </ul>
</div>

<div class="slider item-2">
    <ul>
        <li>Lorem ipsum dolor sit amet</li>
        <li>Consectetur adipisicing elit</li>
        <li>Alias aspernatur</li>
        <li>Assumenda atque aut consectetur</li>
        <li>Consequatur culpa dolore</li>
        <li>Ducimus facilis ipsam itaque</li>
    </ul>
</div>

<hr/>

<h3>Highlight third item</h3>

<div class="slider item-3">
    <ul>
        <li>Lorem ipsum dolor sit amet</li>
        <li>Consectetur adipisicing elit</li>
    </ul>
</div>

<div class="slider item-3">
    <ul>
        <li>Lorem ipsum dolor sit amet</li>
        <li>Consectetur adipisicing elit</li>
        <li>Alias aspernatur</li>
    </ul>
</div>

<div class="slider item-3">
    <ul>
        <li>Lorem ipsum dolor sit amet</li>
        <li>Consectetur adipisicing elit</li>
        <li>Alias aspernatur</li>
        <li>Assumenda atque aut consectetur</li>
    </ul>
</div>

<div class="slider item-3">
    <ul>
        <li>Lorem ipsum dolor sit amet</li>
        <li>Consectetur adipisicing elit</li>
        <li>Alias aspernatur</li>
        <li>Assumenda atque aut consectetur</li>
        <li>Consequatur culpa dolore</li>
    </ul>
</div>

<div class="slider item-3">
    <ul>
        <li>Lorem ipsum dolor sit amet</li>
        <li>Consectetur adipisicing elit</li>
        <li>Alias aspernatur</li>
        <li>Assumenda atque aut consectetur</li>
        <li>Consequatur culpa dolore</li>
        <li>Ducimus facilis ipsam itaque</li>
    </ul>
</div>

<hr/>

<h3>Highlight fourth item</h3>

<div class="slider item-4">
    <ul>
        <li>Lorem ipsum dolor sit amet</li>
        <li>Consectetur adipisicing elit</li>
    </ul>
</div>

<div class="slider item-4">
    <ul>
        <li>Lorem ipsum dolor sit amet</li>
        <li>Consectetur adipisicing elit</li>
        <li>Alias aspernatur</li>
    </ul>
</div>

<div class="slider item-4">
    <ul>
        <li>Lorem ipsum dolor sit amet</li>
        <li>Consectetur adipisicing elit</li>
        <li>Alias aspernatur</li>
        <li>Assumenda atque aut consectetur</li>
    </ul>
</div>

<div class="slider item-4">
    <ul>
        <li>Lorem ipsum dolor sit amet</li>
        <li>Consectetur adipisicing elit</li>
        <li>Alias aspernatur</li>
        <li>Assumenda atque aut consectetur</li>
        <li>Consequatur culpa dolore</li>
    </ul>
</div>

<div class="slider item-4">
    <ul>
        <li>Lorem ipsum dolor sit amet</li>
        <li>Consectetur adipisicing elit</li>
        <li>Alias aspernatur</li>
        <li>Assumenda atque aut consectetur</li>
        <li>Consequatur culpa dolore</li>
        <li>Ducimus facilis ipsam itaque</li>
    </ul>
</div>

<hr/>

<h3>Highlight fifth item</h3>

<div class="slider item-5">
    <ul>
        <li>Lorem ipsum dolor sit amet</li>
        <li>Consectetur adipisicing elit</li>
    </ul>
</div>

<div class="slider item-5">
    <ul>
        <li>Lorem ipsum dolor sit amet</li>
        <li>Consectetur adipisicing elit</li>
        <li>Alias aspernatur</li>
    </ul>
</div>

<div class="slider item-5">
    <ul>
        <li>Lorem ipsum dolor sit amet</li>
        <li>Consectetur adipisicing elit</li>
        <li>Alias aspernatur</li>
        <li>Assumenda atque aut consectetur</li>
    </ul>
</div>

<div class="slider item-5">
    <ul>
        <li>Lorem ipsum dolor sit amet</li>
        <li>Consectetur adipisicing elit</li>
        <li>Alias aspernatur</li>
        <li>Assumenda atque aut consectetur</li>
        <li>Consequatur culpa dolore</li>
    </ul>
</div>

<div class="slider item-5">
    <ul>
        <li>Lorem ipsum dolor sit amet</li>
        <li>Consectetur adipisicing elit</li>
        <li>Alias aspernatur</li>
        <li>Assumenda atque aut consectetur</li>
        <li>Consequatur culpa dolore</li>
        <li>Ducimus facilis ipsam itaque</li>
    </ul>
</div>

<hr/>

<h3>Highlight sixth item</h3>

<div class="slider item-6">
    <ul>
        <li>Lorem ipsum dolor sit amet</li>
        <li>Consectetur adipisicing elit</li>
    </ul>
</div>

<div class="slider item-6">
    <ul>
        <li>Lorem ipsum dolor sit amet</li>
        <li>Consectetur adipisicing elit</li>
        <li>Alias aspernatur</li>
    </ul>
</div>

<div class="slider item-6">
    <ul>
        <li>Lorem ipsum dolor sit amet</li>
        <li>Consectetur adipisicing elit</li>
        <li>Alias aspernatur</li>
        <li>Assumenda atque aut consectetur</li>
    </ul>
</div>

<div class="slider item-6">
    <ul>
        <li>Lorem ipsum dolor sit amet</li>
        <li>Consectetur adipisicing elit</li>
        <li>Alias aspernatur</li>
        <li>Assumenda atque aut consectetur</li>
        <li>Consequatur culpa dolore</li>
    </ul>
</div>

<div class="slider item-6">
    <ul>
        <li>Lorem ipsum dolor sit amet</li>
        <li>Consectetur adipisicing elit</li>
        <li>Alias aspernatur</li>
        <li>Assumenda atque aut consectetur</li>
        <li>Consequatur culpa dolore</li>
        <li>Ducimus facilis ipsam itaque</li>
    </ul>
</div>
Community
  • 1
  • 1
feeela
  • 29,399
  • 7
  • 59
  • 71
  • Wow ... Truly amazing approach. And thanks for all your effort you put into this (and thanks to Paulie_D for motivating you as well). This is really one of the best answers I've seen. This being said, I haven't implemented it yet so we ll see if it actually works in my case (max items count is maybe 10 so it should be okay). I ll post the final version here when i get it to work just so that you see how much you helped me :) Thanks! – Peter Kottas Jul 14 '15 at 11:23
  • Hmm now that I've read it more properly, I see that the with is in fact fixed or same for every item. So that means it would probably be best if I use javascript for this, shouldn't be too difficult I guess I just thought there might be a css only trick to achieve it. I ll accpet this answer since it was css question and this is as good as it gets probably – Peter Kottas Jul 14 '15 at 11:32
1

A partial solution with fixed-width children using transforms:

.container {
    width: 500px;
    padding: 5px;
    border: solid 2px black;
    overflow: hidden;
}
.slider {
    position: relative;
    width: 100%;
    text-align: right;
    transform: translate(-50%);
}
.slider div {
    display: inline-block;
    margin: 0 5px;
    transform: translate(50%);
    border: solid 1px black;
    width: 47px;
    height: 30px;
}

.slider div:last-child {
    background-color: yellow;
}

Full source: https://jsfiddle.net/wh98dxav/2

dmandrioli
  • 116
  • 4
1

As @Paulie_D mentions in the comments, what you are after would be very difficult (maybe even impossible) if you add the class to the child element due to the lack of previous sibling selectors.

This can be achieved, however, by changing the logic a bit by placing the identifying class on the parent. The result is somewhat verbose (and will only get worse with more elements) but does allow for ordering based on the addition of a single class.

The logic behind it:

  • The child elements are positioned absolutely (relative to the parent) which takes them out of the flow. This allows for the selected element to be aligned to the center, but also means that the elements aren't aware of the position of the elements around them. Due to this we need to write rules for each sibling element
  • The selected element is centered using left: 50%; and margin-left: -50px; (half the element's width)
  • The other child elements are also positioned using left: 50%;, this puts the left edge of the element in the middle of the parent. We then use margin-left of varying degrees to offset them from the selected element

For example:

As the selected element is 100px wide we use margin-left: -50px; to center it. To place an element to the left of it we deduct 100px (the width of the element) from the margin making margin-left: -150px;. To place an element to the right of it we add 100px to the margin making margin-left: -150px;.

The following example uses jQuery just to allow you to toggle the class, the positioning is all done using CSS:

$("#parent").on("click", function() {
  //Credit to Denys Séguret for the class toggle http://stackoverflow.com/questions/14200833/jquery-toggling-between-3-classes-initially
  $(this).each(function() {
    var classes = ['one', 'two', 'three', 'four', 'five', 'six'];
    this.className = classes[($.inArray(this.className, classes) + 1) % classes.length];
  });
});
#parent {
  border: 1px solid #000000;
  height: 50px;
  margin: 5px 0;
  overflow: hidden;
  position: relative;
}
.child {
  background-color: #CCCCCC;
  left: 50%;
  height: 50px;
  position: absolute;
  top: 0;
  transition: all 1s;
  width: 100px;
}
.child:nth-child(odd) {
  background-color: #999999;
}
/*First .child selected*/
.one .child:nth-child(1) {
  background-color: yellow;
  margin-left: -50px;
}
.one .child:nth-child(2) {
  margin-left: 50px;
}
.one .child:nth-child(3) {
  margin-left: 150px;
}
.one .child:nth-child(4) {
  margin-left: 250px;
}
.one .child:nth-child(5) {
  margin-left: 350px;
}
.one .child:nth-child(6) {
  margin-left: 450px;
}
/*Second .child selected*/
.two .child:nth-child(1) {
  margin-left: -150px;
}
.two .child:nth-child(2) {
  background-color: yellow;
  margin-left: -50px;
}
.two .child:nth-child(3) {
  margin-left: 50px;
}
.two .child:nth-child(4) {
  margin-left: 150px;
}
.two .child:nth-child(5) {
  margin-left: 250px;
}
.two .child:nth-child(6) {
  margin-left: 350px;
}
/*Third .child selected*/
.three .child:nth-child(1) {
  margin-left: -250px;
}
.three .child:nth-child(2) {
  margin-left: -150px;
}
.three .child:nth-child(3) {
  background-color: yellow;
  margin-left: -50px;
}
.three .child:nth-child(4) {
  margin-left: 50px;
}
.three .child:nth-child(5) {
  margin-left: 150px;
}
.three .child:nth-child(6) {
  margin-left: 250px;
}
/*Fourth .child selected*/
.four .child:nth-child(1) {
  margin-left: -350px;
}
.four .child:nth-child(2) {
  margin-left: -250px;
}
.four .child:nth-child(3) {
  margin-left: -150px;
}
.four .child:nth-child(4) {
  background-color: yellow;
  margin-left: -50px;
}
.four .child:nth-child(5) {
  margin-left: 50px;
}
.four .child:nth-child(6) {
  margin-left: 150px;
}
/*Fifth .child selected*/
.five .child:nth-child(1) {
  margin-left: -450px;
}
.five .child:nth-child(2) {
  margin-left: -350px;
}
.five .child:nth-child(3) {
  margin-left: -250px;
}
.five .child:nth-child(4) {
  margin-left: -150px;
}
.five .child:nth-child(5) {
  background-color: yellow;
  margin-left: -50px;
}
.five .child:nth-child(6) {
  margin-left: 50px;
}
/*Sixth .child selected*/
.six .child:nth-child(1) {
  margin-left: -550px;
}
.six .child:nth-child(2) {
  margin-left: -450px;
}
.six .child:nth-child(3) {
  margin-left: -350px;
}
.six .child:nth-child(4) {
  margin-left: -250px;
}
.six .child:nth-child(5) {
  margin-left: -150px;
}
.six .child:nth-child(6) {
  background-color: yellow;
  margin-left: -50px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="one" id="parent">
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
</div>

https://jsfiddle.net/4tp9u7o0/2/

Hidden Hobbes
  • 13,893
  • 3
  • 38
  • 64