4

Looking for a set of CSS rules that can layout an unknown number of siblings blocks into a staircase formation.

Let's say I have a number of sibling DIV elements within an enclosing one:

<div class="parent">
    <div>SIBLING 1</div>
    <div>SIBLING 2</div>
    ...
    <div>SIBLING n</div>
</div>

For an arbitrary n and I wish to have them laid out so that SIBLING 1 has a margin of m and that SIBLING 2 has margin m+o for some o and SIBLING 3 has a margin of m+2o, until SIBLING n has a margin of m+o(n-1). So the results should look something like this:

    SIBLING 1
      SIBLING 2
        SIBLING 3
          ...
                     SIBLING n

In other words the margin (margin-left in this example) increases with each sibling. It is easy to do a rule for each sibling with nth-child but is there a more generic solution?

Itai
  • 225
  • 2
  • 12
  • Similar to mine? https://stackoverflow.com/questions/31055107 – Praveen Kumar Purushothaman Jun 24 '17 at 18:13
  • 1
    can you use a css preprocessor like sass or less? – Michael Coker Jun 24 '17 at 18:16
  • Would not like to use external tools to generate the CSS just for this. It is not needed otherwise. – Itai Jun 24 '17 at 18:18
  • 1
    Similar, but I don't want floating divs, but neat question too! – Itai Jun 24 '17 at 18:18
  • @Itai can I offer an approach when I wrap each sibling within a `.wrapper` div? יעבוד? – Itay Ganor Jun 24 '17 at 18:37
  • What does _unknown number_ really means? ... 10 - 20 - 50 - 100 – Ason Jun 24 '17 at 18:45
  • @LGSon In the order of a dozen or so. I only said *unknown* because I don't want to hard-code it in the CSS but it will be generated by PHP, so the HTML can now it (although less ideal). – Itai Jun 24 '17 at 19:26
  • @ItayGanor - Sure, each div can have a wrapper div, that is fine. – Itai Jun 24 '17 at 19:27
  • Posted a suggestion using `nth-child` but just noticed you mentioned that already in your question. Let me know if this still is an option or else I delete my answer – Ason Jun 24 '17 at 19:55
  • Just a suggestion, not an answer: Can't you apply an inline style with the PHP, increasing the margin on each step? – Cave Johnson Jun 24 '17 at 20:01
  • @KodosJohnson - Not really, as I intend to do this within a media query, so that on some devices they siblings would line up. – Itai Jun 24 '17 at 20:10
  • In that case, how comfortable are you with generating the margins with PHP, and then using `!important` to override the margins in the media queries to reset them back to 0? – Cave Johnson Jun 24 '17 at 20:12
  • In addition, you can generate the CSS code directly with PHP, generating a class name for each corresponding div. For example: `.step-1`, `.step-2`, etc. And then reset the margins for those classes in the media queries. – Cave Johnson Jun 24 '17 at 20:15
  • @KodosJohnson Then it is 10 times simpler using `nth-child` – Ason Jun 24 '17 at 20:17
  • @LGSon I guess it depends on your point of view. With your solution, if you want to change the step, you have to update every `nth-child`. With PHP, you can define the step in a variable and then you just have to change that variable. I don't think there is anything wrong with doing inline styles and then overriding them with `important`. – Cave Johnson Jun 24 '17 at 20:23
  • @LGSon But I think your solution is still the only way to do what the OP wants with CSS only and it would work a lot better if they were using css preprocessors. Then you can just define the step in a variable and loop through some number of `nth-child`s – Cave Johnson Jun 24 '17 at 20:24
  • @Itai I updated with a second sample, based on your comment not want a framework – Ason Jun 24 '17 at 20:28
  • @KodosJohnson I don't think there is anything wrong with doing inline styles either ... posted a second sample that uses that + a step variable – Ason Jun 24 '17 at 20:41

2 Answers2

1

I wrapped every sibling with a .wrapper div.

.wrapper > .wrapper {
    margin-left: 1em;
}
<div class="parent">

    <div class="wrapper">
        <div>SIBLING 1</div>

        <div class="wrapper">
            <div>SIBLING 2</div>

            <div class="wrapper">
                <div>SIBLING 3</div>

                <div class="wrapper">
                    <div>SIBLING N</div>
                </div>

            </div>

        </div>

    </div>

</div>

JSFiddle

Itay Ganor
  • 3,025
  • 1
  • 15
  • 34
1

For them to be siblings, this is most likely the only option using CSS only (and no float), and since you said in an order of a dozen or so, the CSS will be quite modest.

div {
  width: 30px;
  height: 20px;
  background: lightgray;
  text-align: center;
}
div:nth-child(1) { margin-left: 0px;   }        /* 1st */
div:nth-child(2) { margin-left: 30px;  }        /* 2nd */
div:nth-child(3) { margin-left: 60px;  }        /* 3rd */
div:nth-child(4) { margin-left: 90px;  }        /* 4th */
div:nth-child(5) { margin-left: 120px; }        /* 5th */
div:nth-child(6) { margin-left: 150px; }        /* 6th */
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>

Updated based on a comment.

With a media query and a tiny script this is simple, no framework, just vanilla javascript.

(function(w,d) {

  var steps = 30;
  
  w.addEventListener("load", function() {
    var divs = d.querySelectorAll('div');
    for (var i = 0; i < divs.length; i++) {
      divs[i].style.cssText = 'margin-left: ' + (steps * i) + 'px';
    }
  }, false);
  
}(window,document));
div {
  width: 30px;
  height: 20px;
  background: lightgray;
  text-align: center;
}
@media (max-width: 500px) {
  div {
    margin-left: 0 !important;     /* since the margin is set with inline style,
                                      we need important to override them         */
  }
}
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
Ason
  • 79,264
  • 11
  • 79
  • 127
  • 1
    That's fair. I was hoping there was a clever CSS-only way to do this but it's not that bad to use the nth-child since the numbers are limited. – Itai Jun 27 '17 at 16:19