@function up-to($list, $index) { $l: (); @each $e in $list { @if length($l) < $index { $l: append($l, $e, list-separator($list)); } } @return $l; } @function parent($selector: null) { $selector: & !default; $selector: selector-parse($selector); $first-parent-selector: nth($selector, 1); @return nth($first-parent-selector, length($first-parent-selector)); } @function without-parent($selector: null) { $selector: & !default; $selector: selector-parse($selector); $ancestors: (); @each $subselectors in $selector { $ancestors: append($ancestors, up-to($subselectors, length($subselectors) - 1), comma); } @debug $ancestors; @return $ancestors; } @function null-selector($selector) { @if not $selector { @return true; } @else if length($selector) > 0 and length(nth($selector, 1)) > 0 { @return false; } @else { @return true; } } @mixin grandparent($grandparents, $context: null) { $context: & !default; $grandparents: selector-parse($grandparents); $ancestors: without-parent($context); $selector: if(null-selector($ancestors), $grandparents, selector-nest($ancestors, $grandparents)); $selector: selector-nest($selector, parent($context)); @at-root #{$selector} { @content; } } // EXAMPLES #context { .jumbotron { @include grandparent(".container, .container-fluid") { color: red; } } } .jumbotron { @include grandparent(".container, .container-fluid") { color: red; } } // Outputs: // #context .container .jumbotron, #context .container-fluid .jumbotron { // color: red; } // // .container .jumbotron, .container-fluid .jumbotron { // color: red; }