Skip to content

Commit 0e5b1d7

Browse files
committed
Onboarding and Helper Loops articles.
1 parent e7906d2 commit 0e5b1d7

File tree

5 files changed

+418
-3
lines changed

5 files changed

+418
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,319 @@
11
<script>
2-
2+
import Prism from 'svelte-prism';
33
</script>
44

5-
<p>Yadda yadda made this pretty cool!</p>
5+
<p>
6+
I tend to find from project to project I need the same handful of helper classes. Whenever
7+
possible I use mixins to generate these helpers due to the ease of maintenance&mdash;it's nice to
8+
be able to add or remove additional classes to a range.
9+
</p>
10+
11+
<h4>The Helper Loop</h4>
12+
13+
<p>
14+
This is the classic mixin I use for generating helper classes, which I just call the helper loop:
15+
</p>
16+
17+
<Prism>
18+
{`// e.g. .a-1 {z-index:1} .a-2 {z-index:2} .a-3 {z-index:3}
19+
@mixin helper-loop($start, $stop, $step, $class-name, $property, $unit, $unit-start: false,
20+
$unit-step: false, $extend: "") {
21+
22+
$i: $start;
23+
24+
@if not $unit-start {
25+
$unit-start: $start;
26+
}
27+
28+
@if not $unit-step {
29+
$unit-step: $step;
30+
}
31+
32+
$value: $unit-start;
33+
34+
@while $i <= $stop {
35+
36+
.#{$class-name}-#{$i} {
37+
#{$property}: #{$value}#{$unit}!important;
38+
};
39+
40+
@if ($extend != "") {
41+
.#{$class-name}-#{$i} { @extend #{$extend} }
42+
}
43+
44+
$value: $value + $unit-step;
45+
46+
$i: $i + $step;
47+
48+
}
49+
}`}
50+
</Prism>
51+
52+
Let's take a look at an example for generating some margin classes. First is the more simple
53+
example, where <code>.margin-15</code> gives a value of <code>margin: 15px</code>:
54+
55+
<Prism>
56+
{`@include helper-loop(0, 15, 5, 'margin', 'margin', 'px');`}
57+
</Prism>
58+
59+
Or maybe we want to abstract the numerical value on the helper class from the unit itself, so
60+
<code>.margin-4</code>
61+
to get <code>margin: 1rem</code>:
62+
63+
<Prism>
64+
{`@include helper-loop(0, 4, 1, 'margin', 'margin', 'rem', 0, .25);`}
65+
</Prism>
66+
67+
With fonts maybe we want to skip the odd numbers:
68+
69+
<Prism>
70+
{`@include helper-loop(8, 36, 2, 'font-size', 'font-size', 'rem', 0.625, 0.125);`}
71+
</Prism>
72+
73+
<p>
74+
I like to have the number on the end of the helper class line up with the pixel size of a font, as
75+
it's easier to visualize what the result will be. So in this case <code>font-size-12</code> might
76+
be <code>1em</code>, but visually I want that to be the same as <code>12px</code>.
77+
</p>
78+
79+
<p>
80+
Sometimes I'll setup two loops next to each other. Maybe I want a few odd number font sizes in
81+
that bread in butter range of 11&ndash;17 pixels:
82+
</p>
83+
84+
<Prism>
85+
{`@include helper-loop(8, 36, 2, 'font-size', 'font-size', 'rem', 0.625, 0.125);
86+
@include helper-loop(11, 17, 2, 'font-size', 'font-size', 'rem', 0.6875, 0.125);`}
87+
</Prism>
88+
89+
<p>
90+
I like to have some classes to nudge elements using <code>position: relative;</code>, but I really
91+
just want to use a single helper class to do this like <code>.top-1</code>. This is where that
92+
<code>extend</code> parameter comes in:
93+
</p>
94+
95+
<Prism>
96+
{`.relative {
97+
position: relative;
98+
}
99+
100+
@include helper-loop(1, 5, 1, 'top', 'top', 'px', false, false, ".relative");`}
101+
</Prism>
102+
103+
<p>
104+
Then all I need is one class to nudge an element <span class="bottom-2">up</span> or
105+
<span class="bottom-2" />. I love this one for icons which rarely have the same visual baseline as
106+
text:
107+
</p>
108+
109+
<Prism language="html">
110+
{`Then all I need is one class to nudge an element <span class="bottom-2">up</span> or <span class="bottom-2"></span>`}
111+
</Prism>
112+
113+
<h4>Responsive Classes</h4>
114+
115+
<p>
116+
Building out responsive classes is more complex. I use a loop in a loop to do this. I also don't
117+
use a global mixin for this like the other helpers, preferring to copy, paste and modify an
118+
existing loop.
119+
</p>
120+
121+
<p>
122+
I'll use one of my spacing loops to demonstrate. Let's start with just one helper class to
123+
understand what we are creating:
124+
</p>
125+
126+
<Prism language="css">
127+
{`
128+
.col-margin-1 > * {
129+
margin-left: .25rem;
130+
margin-right: .25rem;
131+
}
132+
.col-margin-1 > *:first-child {
133+
margin-left: 0;
134+
}
135+
.col-margin-1 > *:last-child {
136+
margin-right: 0;
137+
}
138+
`}
139+
</Prism>
140+
141+
<p>
142+
Having child selectors and psuedo selectors complicates this enough that I can't use my helper
143+
loop mixin, and responsive classes further complicate matters. First thing I need is a map of my
144+
breakpoints. I like to match my breakpoints to what Bootstrap uses as they're easy to commit to
145+
memory:
146+
</p>
147+
148+
<Prism>
149+
{`$bootstrap-breakpoints: (
150+
'xs': 0,
151+
'sm': 576px,
152+
'md': 768px,
153+
'lg': 992px,
154+
'xl': 1200px,
155+
'xxl': 1400px,
156+
);`}
157+
</Prism>
158+
159+
<p>
160+
I want to be able to pass parameters into a function of some sort and have that spit out all the
161+
helper classes for me. That function call will look like this:
162+
</p>
163+
164+
<Prism>{`@include spacing-loop(.25, 4, 'margin');`}</Prism>
165+
166+
<p>
167+
I'm going to be calling this loop a couple of times to generate <code>.col-margin-8</code>,
168+
<code>.col-margin-12</code>
169+
and <code>.col-margin-16</code>. So there is a hidden parameter of
170+
<code>$spacing-breakpoints</code> which is map of all the breakpoints I want to generate classes for.
171+
</p>
172+
173+
<Prism>
174+
{`$spacing-breakpoints: 'xs', 'sm'; // 'md', 'lg', 'xl', 'xxl';`}
175+
</Prism>
176+
177+
<p>Next we need to generate each of the media breakpoints:</p>
178+
179+
<Prism>
180+
{`@mixin spacing-breakpoint-loop($property, $i, $value, $breakpoints) {
181+
182+
@each $breakpoint in $breakpoints {
183+
184+
@media (min-width: map-get($bootstrap-breakpoints, $breakpoint)) {
185+
@include spacing-styles($property, $i, $value, $breakpoint);
186+
}
187+
188+
}
189+
190+
}`}
191+
</Prism>
192+
193+
<p>This means our last mixin has the actual classes and instructions in it:</p>
194+
195+
<Prism>
196+
{`@mixin spacing-styles($property, $i, $value, $breakpoint) {
197+
198+
@if $breakpoint == 'xs' {
199+
$breakpoint: '';
200+
}
201+
@else {
202+
$breakpoint: '-#{$breakpoint}';
203+
}
204+
205+
.col-#{$property}#{$breakpoint}-#{$i} > * {
206+
#{$property}-left: calc(#{$value}rem / 2);
207+
#{$property}-right: calc(#{$value}rem / 2);
208+
}
209+
.col-#{$property}#{$breakpoint}-#{$i} > *:first-child {
210+
#{$property}-left: 0
211+
}
212+
.col-#{$property}#{$breakpoint}-#{$i} > *:last-child {
213+
#{$property}-right: 0
214+
}
215+
}`}
216+
</Prism>
217+
218+
<p>
219+
The only thing I want to call out here is the check for the smallest possible breakpoint of <code
220+
>'xs'</code
221+
>. The media query applies to any screen size which 0px and above, which means that class applies
222+
to all screen sizes and we don't need to designate those classes as <code>'-xs-'</code>.
223+
</p>
224+
225+
<p>To close this out I'm going to include the entire <code>_spacing.scss</code> file. Keep in mind that I have <code>$bootstrap-breakpoints</code> as global variable for all my <code>scss</code> files, but I'll include here for simplicity:</p>
226+
227+
<Prism>
228+
{`/* Child Spacing
229+
* Stuff to generate a helper classes for setting the spacing on all child elements.
230+
*/
231+
232+
/* EXAMPLE: .col-margin-1 or .row-margin-1 or .row-padding-1 or .col-margin-12 */
233+
// You get 1, 2, 3, 4, 8, 12, 16. Padding isn't enabled (so enable if needed). Jump to end of file.
234+
235+
// This should be a global variable available to all scss files.
236+
$bootstrap-breakpoints: (
237+
'xs': 0,
238+
'sm': 576px,
239+
'md': 768px,
240+
'lg': 992px,
241+
'xl': 1200px,
242+
'xxl': 1400px,
243+
);
244+
245+
// Add the breakpoints as they are needed: 'xs', 'sm', 'md', 'lg', 'xl', 'xxl'
246+
$spacing-breakpoints: 'xs'; //, 'sm', 'md', 'lg', 'xl', 'xxl';
247+
248+
@mixin spacing-styles($property, $i, $value, $breakpoint) {
249+
250+
@if $breakpoint == 'xs' {
251+
$breakpoint: '';
252+
}
253+
@else {
254+
$breakpoint: '-#{$breakpoint}';
255+
}
256+
257+
.col-#{$property}#{$breakpoint}-#{$i} > * {
258+
#{$property}-left: calc(#{$value}rem / 2);
259+
#{$property}-right: calc(#{$value}rem / 2);
260+
}
261+
.col-#{$property}#{$breakpoint}-#{$i} > *:first-child {
262+
#{$property}-left: 0
263+
}
264+
.col-#{$property}#{$breakpoint}-#{$i} > *:last-child {
265+
#{$property}-right: 0
266+
}
267+
268+
.row-#{$property}#{$breakpoint}-#{$i} > * {
269+
#{$property}-top: calc(#{$value}rem / 2);
270+
#{$property}-bottom: calc(#{$value}rem / 2);
271+
}
272+
.row-#{$property}#{$breakpoint}-#{$i} > *:first-child {
273+
#{$property}-top: 0
274+
}
275+
.row-#{$property}#{$breakpoint}-#{$i} > *:last-child {
276+
#{$property}-bottom: 0
277+
}
278+
}
279+
280+
@mixin spacing-breakpoint-loop($property, $i, $value, $breakpoints) {
281+
282+
@each $breakpoint in $breakpoints {
283+
284+
@media (min-width: map-get($bootstrap-breakpoints, $breakpoint)) {
285+
@include spacing-styles($property, $i, $value, $breakpoint);
286+
}
287+
288+
}
289+
290+
}
291+
292+
@mixin spacing-loop($amount, $steps, $property, $start: false) {
293+
294+
$i: 1;
295+
296+
@if $start {
297+
$i: $start;
298+
}
299+
300+
$value: $amount;
301+
302+
@while $i <= $steps {
303+
304+
@include spacing-breakpoint-loop($property, $i, $value, $spacing-breakpoints);
305+
306+
$value: $value + $amount;
307+
308+
$i: $i + 1;
309+
}
310+
}
311+
// Example: .col-margin-1
312+
@include spacing-loop(.25, 4, 'margin');
313+
@include spacing-loop(2, 8, 'margin', 8); // For 2rem
314+
@include spacing-loop(3, 12, 'margin', 12); // For 3rem
315+
@include spacing-loop(4, 16, 'margin', 16); // For 4rem
316+
317+
// Enable if needed.
318+
// @include spacing-loop(.25, 4, 'padding');`}
319+
</Prism>

0 commit comments

Comments
 (0)