Disclaimer - This most probably isn't the best way possible of achieving this - it is just an experiment combining SASS features.

Just a little experiment using an SVG sprite of all the flags of the teams in the World Cup for a recent project where needed to be able to include the flags at various sizes throughout the site.

Because I was using dynamically added classes in some places and specific flags in others I wanted to be able to easily choose between these two options whilst also not adding a lot of unnecessary code into my compiled stylesheet.

What I wanted to achieve.

  • Use a simple way of including the flags throughout project - @mixin
  • Specify a height of the desired flag and update maths - @mixin variables
  • Be able to loop through the math for all flags when needed - @each
  • Compile only what is required when a specific flag is needed - @if

First things first

Lets get the generic styling out of the way by creating a class that will contain all the generic styling.

.flag-icon {
  background: url('http://matthewshields.co.uk/wordpress/wp-content/themes/me/img/flag-sprite.svg');
  background-repeat: no-repeat;
  background-size: 100% auto;
  display: inline-block;
}

Multicultural-List.

Pretty simple - just a list of all the countries.

// List of all individual countries in the World Cup
$countries: algeria argentina australia belgium bosnia brazil cameroon chile columbia costa_rica croatia ecuador england france germany ghana greece holland honduras iran italy ivory_coast japan mexico nigeria portugal russia south_korea spain switzerland united_states uruguay;

Give me your input.

Using a mixin allows me to pass through variables for use within it, in this case a desired country from the list and the height of the desired flag.

@mixin flag($chosen-country, $height) {
    // 
}

It's Mathematics.

Ok so this part is pretty specific to my example but you get the idea, it takes the desired height and works out the appropriate width of the flag. I can do this in this fashion because all of the flags in my sprite are of the same size - this wouldn't work if the sprite images were of a variety of sizes.

For neatness sake I also rounded down the width and recalculated the height again. Because there is also a 2px gap between the flags in my sprite I also calculated the height of each sprite segment using the same logic. I calculated these values as variables for ease of use later on, keeping everything as tidy as possible.

@mixin flag($chosen-country, $height) {
  $width: floor($height / 0.66);
  $newHeight: $width * 0.66;
  $spriteHeight: $width * 0.7;

  width: $width;
  height: $newHeight;
}

To Each Their Own.

To output a class for each flag for use with dynamically added classes I loop through the countries list with an @each function resulting in a class being added for each country with the background position for that flag in the sprite.

To do this I created a counter using the index functionality as $i, using this along with the $spriteHeight variable from earlier I incremented the background by a regularly increasing amount. This requires that the images in the sprite follow the same order as in the variable list.

@mixin flag($chosen-country, $height) {
  $width: floor($height / 0.66);
  $newHeight: $width * 0.66;
  $spriteHeight: $width * 0.7;

  width: $width;
  height: $newHeight;

  @each $country in $countries {
    $i: index($countries, $country);
    $background-position: -($spriteHeight * ($i - 1));
    
    &.#{$country} {
      background-position: 0 $background-position;
    }
  }
}

This would then give the following result:

.flag-icon {
  width: 50px;
  height: 33px;
}

.flag-icon.algeria {
  background-position: 0 0px;
}

.flag-icon.argentina {
  background-position: 0 -35px;
}

.flag-icon.australia {
  background-position: 0 -70px;
}

// And so on for all 32 countries in the list...

It's Better Filtered.

What I have so far is all well and good for when classes are being added dynamically and every scenario must be covered, but if I was just after a single flag the outputted CSS is a bit excessive to say the least. This is where I wanted to be able to filter this down to the single flag that I wanted.

To do this I used an @if conditional statement to compare against the $chosen-country variable through by the mixin, by placing this within the @each loop despite the fact it loops through all 32 countries it will only actually output when the statement is deemed true streamlining the resulting CSS. To still allow the previous output when needed I have kept that wrapped in another @if statement looking specifically for the value 'all' having been passed through.

@mixin flag($chosen-country, $height) {
  $width: floor($height / 0.66);
  $newHeight: $width * 0.66;
  $spriteHeight: $width * 0.7;

  width: $width;
  height: $newHeight;

  @each $country in $countries {
    $i: index($countries, $country);
    $background-position: -($spriteHeight * ($i - 1));

    @if $chosen-country == $country {
      background-position: 0 $background-position;
    } 
    @else if $chosen-country == "all" {
      &.#{$country} {
        background-position: 0 $background-position;
      }
    }
  }
}

I now have the capability to easily implement both types of output using the same mixin achieving everything I wanted in this experiment.

// Specific Flag
.flag-icon {
  @include flag(argentina, 33px);
}
// Outputs...
.flag-icon {
  width: 50px;
  height: 33px;
  background-position: 0 -35px;
}


// All flags
.flag-icon {
  @include flag(all, 33px);
}
// Outputs...
.flag-icon {
  width: 50px;
  height: 33px;
}

.flag-icon.algeria {
  background-position: 0 0px;
}

.flag-icon.argentina {
  background-position: 0 -35px;
}

.flag-icon.australia {
  background-position: 0 -70px;
}

// And so on for all 32 countries in the list...

See It In Action

See the Pen Filter a SASS @each function by Matthew Shields (@MatthewShields) on CodePen.