1// SASSY MODULAR-SCALE
2// https://github.com/scottkellum/modular-scale
3
4// Defaults
5$ratio: golden_ratio() !default;
6$base-size: 16px !default;
7$round-pixels: true !default;
8
9// Modular Scale function
10@function modular-scale($multiple, $base-size: $base-size, $ratio: $ratio, $round-pixels: $round-pixels) {
11
12  // return the $base-size if $multiple is zero
13  @if $multiple == 0 {
14    @if type-of($base-size) == "list" {
15      $base-size: sort_list($base-size);
16      @return nth($base-size, 1);
17    }
18
19    // return just the simple $base-size value if it's not a list
20    @return $base-size;
21  }
22
23  // if multiple base-sizes are passed in as a list
24  // and multiple ratios are passed in as a list
25  // calculate values in using each base-size / ratio combination
26  @if type-of($base-size) == "list" and type-of($ratio) == "list" {
27    @if unit(ms-multibase-multiratio($multiple, $base-size, $ratio)) == "px" and $round-pixels == true {
28      @return round(ms-multibase-multiratio($multiple, $base-size, $ratio));
29    }
30    @return ms-multibase-multiratio($multiple, $base-size, $ratio);
31  }
32
33  // if multiple base-sizes are passed in as a list
34  // calculate values in using each base-size
35  @if type-of($base-size) == "list" and type-of($ratio) == "number" {
36    @if unit(ms-multibase($multiple, $base-size, $ratio)) == "px" and $round-pixels == true {
37      @return round(ms-multibase($multiple, $base-size, $ratio));
38    }
39    @return ms-multibase($multiple, $base-size, $ratio);
40  }
41
42  // if multiple ratios are passed in as a list
43  // calculate values in using each ratio
44  @if type-of($base-size) == "number" and type-of($ratio) == "list" {
45    @if unit(ms-multiratio($multiple, $base-size, $ratio)) == "px" and $round-pixels == true {
46      @return round(ms-multiratio($multiple, $base-size, $ratio));
47    }
48    @return ms-multiratio($multiple, $base-size, $ratio);
49  }
50
51  // If there are no lists just run the simple function
52  @if unit(power($ratio, $multiple) * $base-size) == "px" and $round-pixels == true {
53    @return round(power($ratio, $multiple) * $base-size);
54  }
55  @return power($ratio, $multiple) * $base-size;
56}
57
58// calculate values in using each base-size / ratio combination
59@function ms-multibase-multiratio($multiple, $base-size: $base-size, $ratio: $ratio) {
60
61  // start with an empty list to place all values in
62  $scale-values: ();
63
64  // make sure base sizes are in ascending order
65  $base-size: sort_list($base-size);
66
67  // take each base-size in turn
68  $k: 1;
69  @while $k <= length($base-size) {
70
71    // add each $base-size to the list except the first
72    @if $k > 1 {
73      $scale-values: append($scale-values, nth($base-size, $k));
74    }
75
76    // take each ratio in turn
77    $j: 1;
78    @while $j <= length($ratio) {
79
80      // reset $modular-scale for each set
81      $modular-scale: nth($base-size, $k);
82
83      // do the scale for each base-size using this ratio
84      @if $multiple > 0 {
85
86        // up $multiple times
87        // and add the result to $scale-values
88        @for $i from 1 through $multiple {
89          $modular-scale: power(nth($ratio, $j), $i) * nth($base-size, $k);
90          $scale-values: append($scale-values, $modular-scale);
91        }
92
93        // and down until the value is lower than the lowest $base-size
94        // and add the result to $scale-values
95        $i: -1;
96        $modular-scale: nth($base-size, $k);
97        @while $modular-scale >= nth($base-size, 1) {
98          $modular-scale: power(nth($ratio, $j), $i) * nth($base-size, $k);
99          $scale-values: append($scale-values, $modular-scale);
100          $i: $i - 1;
101        }
102      }
103      @if $multiple < 0 {
104
105        // do the scale down for each set to below 1px
106        $i: 0;
107        $modular-scale: nth($base-size, $k);
108        @while $i >= $multiple {
109          $modular-scale: power(nth($ratio, $j), $i) * nth($base-size, $k);
110          $scale-values: append($scale-values, $modular-scale);
111          $i: $i - 1;
112        }
113      }
114      $j: $j + 1;
115    }
116    $k: $k + 1;
117  }
118
119  // return trimmed and sorted final list
120  @return trim-sort($multiple, $scale-values, $base-size);
121}
122
123// calculate values in using each base-size
124@function ms-multibase($multiple, $base-size: $base-size, $ratio: $ratio) {
125
126  // start with an empty list to place all values in
127  $scale-values: ();
128
129  // make sure base sizes are in ascending order
130  $base-size: sort_list($base-size);
131
132  // take each base-size in turn
133  $k: 1;
134  @while $k <= length($base-size) {
135
136    // add each $base-size to the list except the first
137    @if $k > 1 {
138      $scale-values: append($scale-values, nth($base-size, $k));
139    }
140
141    // reset $modular-scale for each set
142    $modular-scale: nth($base-size, $k);
143
144    // do the scale for each base-size using this ratio
145    @if $multiple > 0 {
146
147      // up $multiple times
148      // and add the result to $scale-values
149      @for $i from 1 through $multiple {
150        $modular-scale: power($ratio, $i) * nth($base-size, $k);
151        $scale-values: append($scale-values, $modular-scale);
152      }
153
154      // and down until the value is lower than the lowest $base-size
155      // and add the result to $scale-values
156      $i: -1;
157      $modular-scale: nth($base-size, $k);
158      @while $modular-scale >= nth($base-size, 1) {
159        $modular-scale: power($ratio, $i) * nth($base-size, $k);
160        $scale-values: append($scale-values, $modular-scale);
161        $i: $i - 1;
162      }
163    }
164    @if $multiple < 0 {
165
166      // do the scale down for each set to below 1px
167      $i: 0;
168      $modular-scale: nth($base-size, $k);
169      @while $i >= $multiple {
170        $modular-scale: power($ratio, $i) * nth($base-size, $k);
171        $scale-values: append($scale-values, $modular-scale);
172        $i: $i - 1;
173      }
174    }
175    $k: $k + 1;
176  }
177
178  // return trimmed and sorted final list
179  @return trim-sort($multiple, $scale-values, $base-size);
180}
181
182// calculate values in using each ratio
183@function ms-multiratio($multiple, $base-size: $base-size, $ratio: $ratio) {
184
185  // start with an empty list to place all values in
186  $scale-values: ();
187
188  // If $multiple is a positive integer (up the scale)
189  @if $multiple > 0 {
190
191    // take each ratio in turn
192    $j: 1;
193    @while $j <= length($ratio) {
194
195      // reset $modular-scale for each set
196      $modular-scale: $base-size;
197
198      // do the scale using this ratio thru the multiple, and add the result to $scale-values
199      @for $i from 1 through $multiple {
200        $modular-scale: power(nth($ratio, $j), $i) * $base-size;
201        $scale-values: append($scale-values, $modular-scale);
202      }
203      $j: $j + 1;
204    }
205
206    // sort acsending
207    $scale-values: sort_list($scale-values);
208
209    // return the final value using the laced list
210    @return nth($scale-values, $multiple);
211  }
212
213  // If $multiple is a negative integer (down the scale)
214  @if $multiple < 0 {
215
216    // take each ratio in turn
217    $j: 1;
218    @while $j <= length($ratio) {
219
220      // reset $modular-scale for each set
221      $modular-scale: $base-size;
222
223      // do the scale using this ratio thru the multiple, and add the result to $scale-values
224      @for $i from 1 through $multiple * -1 {
225        $modular-scale: power(nth($ratio, $j), -$i) * $base-size;
226        $scale-values: append($scale-values, $modular-scale);
227      }
228      $j: $j + 1;
229    }
230
231    // sort decending
232    $scale-values: reverse_list(sort_list($scale-values));
233
234    // return the final value using the laced list
235    @return nth($scale-values, $multiple * -1);
236  }
237}
238
239// trim and sort the final list
240@function trim-sort($multiple, $scale-values: $scale-values, $base-size: $base-size) {
241  @if $multiple > 0 {
242
243    // trim list so we can count from the lowest $base-size
244    $scale-values: trim_list($scale-values, nth($base-size, 1), true);
245
246    // sort acsending
247    $scale-values: sort_list($scale-values);
248
249    // return the final value using the laced list
250    @return nth($scale-values, $multiple);
251  }
252  @else {
253
254    // trim list so we can count from the lowest $base-size
255    $scale-values: trim_list($scale-values, nth($base-size, 1), false);
256
257    // sort acsending
258    $scale-values: reverse_list(sort_list($scale-values));
259
260    // return the final value using the laced list
261    @return nth($scale-values, -$multiple);
262  }
263}
264
265/////////////////////////////////////////////////////////////////////////
266
267// alias for golden_ratio()
268@function golden() {
269  @return golden_ratio();
270}
271
272// Shortcut
273@function ms($multiple, $base-size: $base-size, $ratio: $ratio, $round-pixels: $round-pixels) {
274  // Return the value from the Modular Scale function
275  @return modular-scale($multiple, $base-size, $ratio, $round-pixels);
276}
277
278// Write Modular Scale List
279@function modular-scale-list($start: 0, $finish: 20, $base-size: $base-size, $ratio: $ratio, $round-pixels: $round-pixels) {
280  $ms-list: unquote("MS-LIST:");
281  @for $i from $start through $finish {
282    $ms-list: append($ms-list, ms($i, $base-size, $ratio, $round-pixels));
283  }
284  @return $ms-list;
285}
286
287@function ms-list($start: 0, $finish: 20, $base-size: $base-size, $ratio: $ratio, $round-pixels: $round-pixels) {
288  @return modular-scale-list($start, $finish, $base-size, $ratio, $round-pixels);
289}
290
291@mixin modular-scale-list($start: 0, $finish: 20, $base-size: $base-size, $ratio: $ratio, $round-pixels: $round-pixels) {
292  @debug modular-scale-list($start, $finish, $base-size, $ratio, $round-pixels);
293}
294
295@mixin ms-list($start: 0, $finish: 20, $base-size: $base-size, $ratio: $ratio, $round-pixels: $round-pixels) {
296  @debug modular-scale-list($start, $finish, $base-size, $ratio, $round-pixels);
297}
298
299@mixin modular-scale-list-output($start: 0, $finish: 20, $base-size: $base-size, $ratio: $ratio, $round-pixels: $round-pixels) {
300    MODULAR-SCALE-LIST {
301      ms-list: modular-scale-list($start, $finish, $base-size, $ratio, $round-pixels);
302    }
303  }
304
305@mixin ms-list-output($start: 0, $finish: 20, $base-size: $base-size, $ratio: $ratio, $round-pixels: $round-pixels) {
306  @include modular-scale-list-output($start, $finish, $base-size, $ratio, $round-pixels);
307}
308
309// Other libraries can easily query if this function is avalible
310$modular-scale-loaded: true;