2

I've written the following loop to loop through a list of team to generate the background position for a sprite image. How can I make this into a function so that I can pass in the $teams, $X and $Y value instead?

$teams: A, B, C, D;

$x: 0;
$y: 0;

@each $team in $teams {
    $i: index($teams, $team);
    $y: $y + 20px;
    .team#{$team}:before,
    .team#{$team}:after {
        background-position: $x $y;
    }
}

Output:

.teamA:before,
.teamA:after {
  background-position: 0 20px;
}

.teamB:before,
.teamB:after {
  background-position: 0 40px;
}

.teamC:before,
.teamC:after {
  background-position: 0 60px;
}

.teamD:before,
.teamD:after {
  background-position: 0 80px;
}

Another problem I face is where some teams would share the same background position, therefore the desired output would be something like such:

.teamA:before,
.teamA:after,
.teamAB:before,
.teamAB:after {
  background-position: 0 20px;
}

.teamB:before,
.teamB:after {
  background-position: 0 40px;
}

.teamC:before,
.teamC:after
.teamCB:before,
.teamCB:after {
  background-position: 0 60px;
}

.teamD:before,
.teamD:after {
  background-position: 0 80px;
}

Is it possible to group team names by some delimiter for it to compile into the same shared property?

$teams: 'A AB', B, 'CB, C', D;
calebo
  • 3,312
  • 10
  • 44
  • 66

1 Answers1

0

You could check if the current index is a list or value. If it's a value, do what you're already doing. If it's a tuple, iterate through each one, setting the position to the same value for each (only change the numerical value if it's a new index on the outermost list).

$teams: A AB, B, CB C, D;

$x: 0;
$y: 0;

@each $team in $teams {
  $y: $y + 20px;

  @if type-of($team) == list {
    @each $team-sub in $team {
      .team#{$team-sub}:before,
      .team#{$team-sub}:after {
        background-position: $x $y;
      }
    }
  }
  @else {
    .team#{$team}:before,
    .team#{$team}:after {
      background-position: $x $y;
    }
  }
}

I've tested this, and it works as expected.

Edit: Here's an updated version with compound selectors. This will be removed from SASS in the future, so use at your own risk.

$teams: A AB, B, CB C, D;

$x: 0;
$y: 0;

@each $team in $teams {
  $y: $y + 20px;

  @if type-of($team) == list {
    @each $team-sub in $team {
      $i: index($team, $team-sub);

      @if $i == 1 {
        .team#{$team-sub}::before,
        .team#{$team-sub}::after {
          background-position: $x $y;
        }
      }
      @else {
        .team#{$team-sub}::before {
          @extend .team#{nth($team, 1)}::before;
        }

        .team#{$team-sub}::after {
          @extend .team#{nth($team, 1)}::after;
        }
      }
    }
  }
  @else {
    .team#{$team}::before,
    .team#{$team}::after {
      background-position: $x $y;
    }
  }
}
jhpratt
  • 6,841
  • 16
  • 40
  • 50
  • Is it possible to group A and AB into the same group like: `A:before, A:after, AB:before, AB:after { ... }` – calebo Jul 27 '17 at 04:49
  • I don't believe that's possible with straight SCSS. It _might_ be possible using a function, but I'd have to dig into the documentation for that. Ultimately the browser doesn't care, unsurprisingly, if they're combined or not. – jhpratt Jul 27 '17 at 05:25
  • 1
    I've found [this](https://stackoverflow.com/a/19088399/2718801). I'll try and mix the two together tomorrow when I get a chance! – jhpratt Jul 27 '17 at 05:42
  • @calebo I've got working code, which I just added, but please note that it extends `::before`, which is deprecated and will be removed in an upcoming version. [Per the maintainer's note](https://github.com/sass/sass/pull/2300#issuecomment-314647053), this is an intentional decision to avoid complexity on the backend (as compound selectors will not be able to be extended). – jhpratt Jul 27 '17 at 19:39