Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nesting selectors via loops with SASS

Tags:

css

sass

I have this HTML

<ul> // first level
  <li>
    <ul></ul> // second level
  </li>
  <li>
    <ul> // second level
      <li>
        <ul></ul> // third level
      </li>
    </ul>
  </li>
</ul>

Is there any possible to loop nested lists one in another, to get something like this:

ul {
 padding: 10px;
 ul {
  padding: 20px;
  ul {
    padding: 30px;
    ... through 10 * ul
  }
 }
}  

With this i have only list multiplication.

@for $i from 1 through 10 {
    ul {
        padding-left: 100 - (10 * $i) + px;
    }
  }
like image 462
Lukas Avatar asked Mar 12 '14 11:03

Lukas


1 Answers

For Sass versions prior to 3.4, the function you need to do this is not part of native Sass (and recursive mixins don't work in certain versions). You need Compass function called nest().

$sel: '';
@for $i from 1 through 10 {
    // remove !global flag if you're using Sass < 3.3
    $sel: if($i == 1, "ul", nest($sel, "ul")) !global;

    #{$sel} {
        padding-left: 10px * $i;
    }
}

Sass 3.4 has a native version of this function called selector-nest():

$sel: '';
@for $i from 1 through 10 {
    $sel: if($i == 1, "ul", selector-nest($sel, "ul")) !global;

    #{$sel} {
        padding-left: 10px * $i;
    }
}

Output:

ul {
  padding-left: 10px;
}

ul ul {
  padding-left: 20px;
}

ul ul ul {
  padding-left: 30px;
}

ul ul ul ul {
  padding-left: 40px;
}

ul ul ul ul ul {
  padding-left: 50px;
}

ul ul ul ul ul ul {
  padding-left: 60px;
}

ul ul ul ul ul ul ul {
  padding-left: 70px;
}

ul ul ul ul ul ul ul ul {
  padding-left: 80px;
}

ul ul ul ul ul ul ul ul ul {
  padding-left: 90px;
}

ul ul ul ul ul ul ul ul ul ul {
  padding-left: 100px;
}

If you want to spell out the initial ul, then you would do it like this:

ul {
    // parent styles
    border: 1px solid;

    $sel: '';
    @for $i from 2 through 10 {
        $sel: if($i == 2, 'ul', nest($sel, 'ul')); // note no !global flag

        #{$sel} {
            padding-left: 10px * $i;
        }
    }
}

Note that you could use simple string concatenation instead of either of these functions, but it will only work in cases where you're only nesting a single selector. If you have 2 or more selectors, this is absolutely necessary:

$sel: '';
@for $i from 1 through 3 {
    $sel: if($i == 1, "article, section", selector-nest($sel, "article, section")) !global;

    #{$sel} {
      h1 {
        padding-left: 10px * $i;
      }
    }
}

Output:

article h1, section h1 {
  padding-left: 10px;
}

article article h1, article section h1, section article h1, section section h1 {
  padding-left: 20px;
}

article article article h1, article article section h1, article section article h1, article section section h1, section article article h1, section article section h1, section section article h1, section section section h1 {
  padding-left: 30px;
}
like image 83
cimmanon Avatar answered Nov 10 '22 00:11

cimmanon