├── .gitignore
├── .stylelintrc.json
├── LICENSE
├── PRINCIPLES.md
├── README.md
├── base
├── __import.scss
├── _document.scss
└── _reset.scss
├── components
├── __import.scss
└── _button.scss
├── objects
├── __import.scss
├── _aspect-ratio.scss
├── _container.scss
├── _position.scss
└── _sr-only.scss
├── scopes
├── __import.scss
└── _wysiwyg.scss
├── settings
├── __import.scss
├── _breakpoints.scss
├── _colors.scss
└── _global.scss
├── style.scss
├── tools
├── __import.scss
├── _breakpoints.scss
├── _error.scss
├── _lists.scss
├── _make-class.scss
├── _make-utility.scss
├── _map-use.scss
├── _math.scss
├── _strings.scss
└── _type.scss
├── type
├── __import.scss
├── _headings.scss
└── _p.scss
└── utilities
├── __import.scss
├── _background.scss
├── _border-radius.scss
├── _box-sizing.scss
├── _color.scss
├── _content.scss
├── _display.scss
├── _flex.scss
├── _gc-start.scss
├── _gc.scss
├── _height.scss
├── _margin.scss
├── _overflow.scss
├── _padding.scss
├── _pointer-events.scss
├── _position.scss
├── _transform.scss
├── _type.scss
├── _visibility.scss
├── _width.scss
└── _z-index.scss
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
--------------------------------------------------------------------------------
/.stylelintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "stylelint-config-standard",
4 | "stylelint-config-rational-order",
5 | "stylelint-config-recommended-scss"
6 | ],
7 | "rules": {
8 | "at-rule-empty-line-before": null,
9 | "at-rule-name-space-after": "always-single-line",
10 | "block-opening-brace-space-before": "always",
11 | "block-closing-brace-newline-after": [
12 | "always", {
13 | "ignoreAtRules": [ "if", "else" ]
14 | }
15 | ],
16 | "color-hex-length": "long",
17 | "comment-empty-line-before": null,
18 | "declaration-empty-line-before": null,
19 | "function-parentheses-newline-inside": null,
20 | "number-leading-zero": "never",
21 | "rule-empty-line-before": [
22 | "always", {
23 | "ignore": ["after-comment", "first-nested", "inside-block"]
24 | }
25 | ],
26 | "scss/at-else-closing-brace-newline-after": "always-last-in-chain",
27 | "scss/at-else-closing-brace-space-after": "always-intermediate",
28 | "scss/at-else-empty-line-before": "never",
29 | "scss/at-if-closing-brace-newline-after": "always-last-in-chain",
30 | "scss/at-if-closing-brace-space-after": "always-intermediate"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Lighthouse London
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/PRINCIPLES.md:
--------------------------------------------------------------------------------
1 | # Principles
2 | 1. **Don't repeat, or unset styles**
3 | 2. **Code 'mess' has to live somewhere**
4 |
5 | ## 1. Don't repeat, or unset styles
6 | stemCSS achieves this by:
7 | ### Build classes that are specific and explicit
8 | - If a `color: black` is only applied on `:hover` at breakpoint `large`, your class is `.u-color-black@hover@large`
9 | - Which in your compiled css would be:
10 | ```
11 | @media (min-width: 1240px) {
12 | .u-color-black\@hover\@large {
13 | color: black;
14 | }
15 | }
16 | ```
17 | ### Too edge-case? Keep it tied to a component until you re-use it
18 | ```
19 | .c-form {
20 | &__label {
21 | @include breakpoint(large) {
22 | &:hover {
23 | color: $colour-black;
24 | }
25 | }
26 | }
27 | }
28 | ```
29 |
30 |
31 |
32 | ### `@extend` to apply each `property: value` to an Object or Component
33 | - The codebase creates `.u-color-black` as a Utility
34 | - Five components want to use `color: black;`
35 | - `.c-button { @extend .u-color-black; } `
36 | - Compiled CSS: `.u-color-black, .c-button { color: black; }`
37 |
38 |
39 |
40 | ## 2. Code 'mess' has to live somewhere
41 | You can build up and style your components in your **HTML**, or in your **SCSS**. This is where your mess will live.
42 |
43 |
44 |
45 | ### Option A - Mess in the HTML
46 |
47 | ```
48 | Submit
49 | ```
50 |
51 |
52 |
53 | ### Option B - Mess in the SCSS
54 | ```
55 | .c-submit {
56 | @extend .u-flex;
57 | @extend .u-ai-center;
58 | @extend .u-jc-center;
59 | @extend .u-bgcolor-green;
60 | @extend .u-shadow;
61 | @extend .u-h4;
62 | @extend .u-weight-bold;
63 | @extend .u-family-roboto;
64 | }
65 | ```
66 |
67 |
68 |
69 | ### Option C - A bit of both
70 | ```
71 | Submit
72 |
73 | .c-submit {
74 | @extend .u-flex;
75 | @extend .u-ai-center;
76 | @extend .u-jc-center;
77 | @extend .u-h4;
78 | @extend .u-weight-bold;
79 | @extend .u-family-roboto;
80 | }
81 | ```
82 |
83 | ### The decision is just 'where do I prefer to manage these 'sets' of classes?
84 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # stemCSS
2 | An [OOCSS](https://www.keycdn.com/blog/oocss) Sass framework for rapidly creating organised, responsive, and consistent user interfaces. Originally based off an early fork of [iotaCSS](https://www.iotacss.com/), stemCSS has grown into it's own thing, with a focus on code reuse and flexible programatically created utilities.
3 |
4 | ## Getting Started
5 | 1. Download the [latest release]() _- this link is TODO when v1 is done!_
6 |
7 | ```
8 | $ curl -o stemCSS.zip https://codeload.github.com/wearelighthouse/stemCSS/zip/master
9 | ```
10 |
11 | 2. Get the contents of it into an assets folder in your project. E.g.
12 |
13 | ```
14 | $ unzip -q stemCSS.zip
15 | $ rm -r stemCSS.zip
16 | $ mkdir -p assets/scss
17 | $ cp -r stemCSS-master/* assets/scss/
18 | $ rm -r stemCSS-master/
19 | ```
20 |
21 | 3. [Use something like gulp + gulp-sass to transpile the scss](https://css-tricks.com/gulp-for-beginners/).
22 |
23 |
24 | # Utilities
25 | Class or placeholder selectors that produces a single `value: property`.
26 | ```
27 | .u-color-black { color: black; }
28 | .u-flex { display: flex; }
29 | .u-pos-absolute { position: absolute; }
30 | ```
31 |
32 | _In some circumstances_ - like `mx` (`margin-left`, `margin-right`), a utility produces two or more properties.
33 | ```
34 | .u-mx-auto {
35 | margin-left: auto;
36 | margin-right: auto;
37 | }
38 | ```
39 |
40 | Utilities are "created" by passing a sass map (hence the double brackets) into the make-utility mixin:
41 | ```
42 | @include make-utility((...));
43 | ```
44 | The items in the map can include an __alias__ to determine the name of the utility, a __class__ flag which creates the utility as a class which is always included in the transpiled CSS and can be used in the HTML (rather than just a placeholder which _cannot_ be used in the HTML, and is only in the transpiled CSS if it gets extended), and a __set of CSS properties__.
45 | ```
46 | @include make-utility((
47 | alias: 'mx-auto',
48 | class: true,
49 | margin-left: auto,
50 | margin-right: auto
51 | ));
52 | ```
53 | If an __alias__ is not included in the sass map, the first CSS property and value is used as the name of the utility, e.g.
54 | ```
55 | @include make-utility((
56 | height: 1px
57 | ));
58 | ```
59 | ... can be used with:
60 | ```
61 | @extend %u-height-1px;
62 | ```
63 |
64 | See examples in the pre-existing utilties: [`/utilties/*.scss`](https://github.com/wearelighthouse/stemCSS/tree/master/utilities).
65 |
66 |
67 | # Objects
68 | Layouts objects - grids, containers, and helpful sets of classes like aspect-ratio etc.
69 | Never *visual* - you can't picture an object because it has no colours. If it has _colours_ - it's _probably_ a component.
70 | Objects typically @extend utilities.
71 | ```
72 | .o-container {
73 | @extend .u-mx-auto;
74 | width: 90vw;
75 | }
76 | ```
77 |
78 | # Components
79 | *Visual components* in your design system. `Header, Button, Footer, Hero` etc.
80 | Follow the *BEM* methodology for their children _where appropriate_.
81 | ```
82 | .c-button {
83 | @extend .u-flex;
84 | @extend .u-bg-color-black;
85 | @extend .u-color-white;
86 |
87 | &__icon {
88 | @extend .u-pos-absolute;
89 | @extend .u-left-50pc;
90 | transform: translateX(-50%);
91 | }
92 | }
93 | ```
94 |
95 | # Breakpoints
96 |
97 | ### Defining Breakpoints
98 | These are defined in `settings/_breakpoints`, which includes:
99 |
100 | General breakpoints as sass variables - can simply be used anywhere you need them!
101 | ```
102 | $breakpoint-minimum: 320px;
103 | $breakpoint-large: 1400px;
104 | ```
105 |
106 | Breakpoints sass map (get merged with the following map, sans any special generation)
107 | ```
108 | $global-breakpoints: (
109 | landscape: 'screen and (orientation: landscape)',
110 | portrait: 'screen and (orientation: portrait)'
111 | );
112 | ```
113 |
114 | Breakpoints sass map with automatic --from and --upto generation
115 | ```
116 | $global-breakpoints: map-merge($global-breakpoints, make-width-breakpoints((
117 | small: 400px,
118 | medium: 800px,
119 | large: 1200px,
120 | )));
121 | ```
122 |
123 | ### Using Breakpoints
124 |
125 | ##### iotaCSS style
126 | ```
127 | @include breakpoint(from-medium) {
128 | color: red;
129 | }
130 | ```
131 |
132 | ##### stemCSS style
133 | ```
134 | @extend %u-color-red--from-medium;
135 | ```
136 | The main advantage of using "stemCSS style" breakpoints are that they are extending placeholders, rather than requiring additional individual CSS rules (i.e. you cannot `@extend` a utility from within a standard iotaCSS breakpoint).
137 |
138 | If, for example for consistency, you wanted to restrict the available widths to only 0%, 50%, or 100%, and had created those options in the `_width.scss` utility, then using `@extend %u-width-60pc--from-medium` would fail, whereas `@include breakpoint(from-medium) { width: 60% }` would obviously not.
139 |
140 | # Colors
141 |
142 | Text and background color utilities and are very similar to [iotaCSS's](https://www.iotacss.com/docs/utilities/color/). Colors are defined in [`settings/_colors.scss`](https://github.com/wearelighthouse/stemCSS/blob/master/settings/_colors.scss). E.g:
143 | ```
144 | $color-very-dark: #111111;
145 | $auto-colors: (
146 | 'black': $color-very-dark
147 | }
148 | ```
149 | Allows you to use both: `@extend %u-color-black;` and `@extend %u-bg-color-black;`
150 |
--------------------------------------------------------------------------------
/base/__import.scss:
--------------------------------------------------------------------------------
1 | @import
2 | 'reset',
3 | 'document';
4 |
--------------------------------------------------------------------------------
/base/_document.scss:
--------------------------------------------------------------------------------
1 | body {
2 | @include font-scale(14, 22);
3 | }
4 |
--------------------------------------------------------------------------------
/base/_reset.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * Resets and/or normalizes styles for commonly used HTML elements.
3 | * Intended for modern versions of Chrome, Firefox, Edge, Safari, and IE11.
4 | *
5 | * Inspired by normalize.css v8.0.1 and Eric Meyer’s Reset CSS 2.0
6 | * - But easy to swap out for either of those in full if required!
7 | */
8 |
9 | // Remove margins on body
10 | body {
11 | margin: 0;
12 | }
13 |
14 | // Normalize global line-height
15 | html {
16 | line-height: 1.15;
17 | }
18 |
19 | // Render `` correctly in IE
20 | main {
21 | display: block;
22 | }
23 |
24 | // Reset heading font-weight
25 | h1,
26 | h2,
27 | h3,
28 | h4,
29 | h5,
30 | h6 {
31 | font-weight: normal;
32 | }
33 |
34 | // Remove list markers
35 | li {
36 | list-style: none;
37 | }
38 |
39 | // Remove link styling
40 | a {
41 | color: inherit;
42 | text-decoration: none;
43 | }
44 |
45 | // Reset some button styling
46 | button {
47 | margin: 0;
48 | padding: 0;
49 | font: inherit;
50 | background: none;
51 | border: none;
52 | }
53 |
--------------------------------------------------------------------------------
/components/__import.scss:
--------------------------------------------------------------------------------
1 | @import
2 | 'button';
3 |
--------------------------------------------------------------------------------
/components/_button.scss:
--------------------------------------------------------------------------------
1 | .c-button {
2 | @extend %u-mx-auto;
3 | }
4 |
--------------------------------------------------------------------------------
/objects/__import.scss:
--------------------------------------------------------------------------------
1 | @import
2 | 'aspect-ratio',
3 | 'container',
4 | 'sr-only',
5 | 'position';
6 |
--------------------------------------------------------------------------------
/objects/_aspect-ratio.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * Specify an aspect ratio for an element, and it will
3 | * figure out it's own height based off it's width. E.g.
4 | * ``
5 | *
6 | * To use a specific aspect ratio it must be included in the ratio list
7 | * `((horizontal:vertical), (...), (...), ...)`
8 | */
9 | @each $ratio in ((16:9), (2:1), (1:1)) {
10 | $h: first(map-keys($ratio));
11 | $v: first(map-values($ratio));
12 |
13 | #{'.o-aspect-ratio--' + $h + '-' + $v} {
14 | @extend %u-pos-relative;
15 |
16 | &::before {
17 | @extend %u-block;
18 | @extend %u-content-none;
19 | @extend #{'%u-width-100' + $global-unit-percent};
20 | padding-top: #{get-percent-from-list(($h, $v)) * 1%};
21 | }
22 |
23 | > * {
24 | @extend %u-pos-absolute;
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/objects/_container.scss:
--------------------------------------------------------------------------------
1 | .o-container {
2 | @extend .u-mx-auto;
3 | width: 90vw;
4 | }
5 |
--------------------------------------------------------------------------------
/objects/_position.scss:
--------------------------------------------------------------------------------
1 | .o-absfill {
2 | @extend %u-pos-absolute;
3 | @extend %u-top;
4 | @extend %u-left;
5 | @extend %u-width-100pc;
6 | @extend %u-height-100pc;
7 | }
8 |
9 | .o-abscentre {
10 | @extend %u-pos-absolute;
11 | @extend %u-top-50pc;
12 | @extend %u-left-50pc;
13 | @extend %u-translate--50pc;
14 | }
15 |
16 | .o-abscentre-x {
17 | @extend %u-pos-absolute;
18 | @extend %u-left-50pc;
19 | @extend %u-translateX--50pc;
20 | }
21 |
22 | .o-abscentre-y {
23 | @extend %u-pos-absolute;
24 | @extend %u-top-50pc;
25 | @extend %u-translateY--50pc;
26 | }
27 |
--------------------------------------------------------------------------------
/objects/_sr-only.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * Visually hidden, but provided for screen readers (dictated).
3 | * Similar to WordPress .screen-reader-text:
4 | * https://make.wordpress.org/accessibility/handbook/markup/the-css-class-screen-reader-text/
5 | */
6 | .o-sr-only {
7 | @extend %u-pos-absolute;
8 | @extend %u-width-1px;
9 | @extend %u-height-1px;
10 | @extend %u-ov-hidden;
11 | top: -1px;
12 | left: -1px;
13 | margin: -1px;
14 | padding: 0;
15 | border: 0;
16 | clip-path: inset(50%);
17 | }
18 |
--------------------------------------------------------------------------------
/scopes/__import.scss:
--------------------------------------------------------------------------------
1 | @import
2 | 'wysiwyg';
3 |
--------------------------------------------------------------------------------
/scopes/_wysiwyg.scss:
--------------------------------------------------------------------------------
1 | .s-wysiwyg {
2 | p {
3 | @extend .type-p;
4 | margin-bottom: 1rem;
5 | }
6 |
7 | a {
8 | text-decoration: underline;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/settings/__import.scss:
--------------------------------------------------------------------------------
1 | @import
2 | 'global',
3 | 'breakpoints',
4 | 'colors';
5 |
--------------------------------------------------------------------------------
/settings/_breakpoints.scss:
--------------------------------------------------------------------------------
1 | $breakpoint-minimum: 320px;
2 | $breakpoint-large: 1400px;
3 |
4 | $breakpoint-smallest-font: $breakpoint-minimum;
5 | $breakpoint-largest-font: $breakpoint-large;
6 |
7 | $global-breakpoints: (
8 | landscape: 'screen and (orientation: landscape)',
9 | portrait: 'screen and (orientation: portrait)'
10 | );
11 |
12 | /**
13 | * User specified breakpoint "boundaries".
14 | *
15 | * Adds width breakpoints to the $global-breakpoints map with:
16 | *
17 | * breakpoint-a (as a min-width media query)
18 | * from-breakpoint-a (as a min-width media query)
19 | * upto-breakpoint-a (as a max-width media query)
20 | *
21 | * ... and all possible combinations of:
22 | *
23 | * from-breakpoint-a--upto-breakpoint-b (where breakpoint b > breakpoint a)
24 | */
25 | $global-breakpoints: map-merge(
26 | $global-breakpoints,
27 | make-width-breakpoints((
28 | small: 400px,
29 | medium: 800px,
30 | large: 1200px,
31 | ))
32 | );
33 |
34 | // Print all the breakpoints to check they have been generated as intended
35 | // @each $breakpoint-key, $breakpoint-value in $global-breakpoints {
36 | // @debug $breakpoint-key + ': ' + $breakpoint-value;
37 | // }
38 |
--------------------------------------------------------------------------------
/settings/_colors.scss:
--------------------------------------------------------------------------------
1 | // Global color variables
2 | $color-white: #ffffff;
3 | $color-black: #000000;
4 |
5 | // Colors used to automatically generate font and background color utilities.
6 | $auto-colors: (
7 | 'white': $color-white,
8 | 'black': $color-black,
9 | 'transparent': transparent,
10 | 'currentColor': currentColor
11 | );
12 |
--------------------------------------------------------------------------------
/settings/_global.scss:
--------------------------------------------------------------------------------
1 | $global-everything-as-class: true;
2 | $global-breakpoint-separator: '--';
3 | $global-pseudo-separator: \@;
4 | $global-unit-percent: 'pc';
5 | $global-grid-columns: 12;
6 | $global-size-step: .25rem;
7 | $global-size-range: 16;
8 |
--------------------------------------------------------------------------------
/style.scss:
--------------------------------------------------------------------------------
1 | @import
2 | 'tools/_import',
3 | 'settings/_import',
4 | 'base/_import',
5 | 'utilities/_import',
6 | 'objects/_import',
7 | 'scopes/_import',
8 | 'type/_import',
9 | 'components/_import';
10 |
--------------------------------------------------------------------------------
/tools/__import.scss:
--------------------------------------------------------------------------------
1 | @import
2 | 'breakpoints',
3 | 'error',
4 | 'lists',
5 | 'make-class',
6 | 'make-utility',
7 | 'map-use',
8 | 'math',
9 | 'strings',
10 | 'type';
11 |
--------------------------------------------------------------------------------
/tools/_breakpoints.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * Adds an automatically generated list of screen width
3 | * breakpoints to the $global-breakpoints map with:
4 | *
5 | * from-breakpoint-a (as a min-width media query)
6 | * upto-breakpoint-a (as a max-width media query)
7 | *
8 | * ... and all possible combinations of:
9 | *
10 | * from-breakpoint-a--upto-breakpoint-b (where breakpoint b > breakpoint a)
11 | *
12 | */
13 |
14 | @function min-width($value) {
15 | @return '(min-width: ' + $value + ')';
16 | }
17 |
18 | @function max-width($value) {
19 | @return '(max-width: ' + ($value - 1px) + ')';
20 | }
21 |
22 | @function make-width-breakpoints($width-breakpoints) {
23 | $output-breakpoints: ();
24 |
25 | @each $bp-a-key, $bp-a-value in $width-breakpoints {
26 | $a: index(($width-breakpoints), ($bp-a-key $bp-a-value));
27 |
28 | $output-breakpoints: map-merge(
29 | $output-breakpoints,
30 | (
31 | 'upto-' + $bp-a-key:
32 | 'screen and ' + max-width($bp-a-value)
33 | )
34 | );
35 |
36 | $output-breakpoints: map-merge(
37 | $output-breakpoints,
38 | (
39 | 'from-' + $bp-a-key:
40 | 'screen and ' + min-width($bp-a-value)
41 | )
42 | );
43 |
44 | @each $bp-b-key, $bp-b-value in $width-breakpoints {
45 | $b: index(($width-breakpoints), ($bp-b-key $bp-b-value));
46 |
47 | @if $a != $b and $bp-b-value > $bp-a-value {
48 | $output-breakpoints: map-merge(
49 | $output-breakpoints,
50 | (
51 | 'from-' + $bp-a-key + '--upto-' + $bp-b-key:
52 | 'screen and ' + min-width($bp-a-value) + ' and ' + max-width($bp-b-value)
53 | )
54 | );
55 | }
56 | }
57 | }
58 |
59 | @return $output-breakpoints;
60 | }
61 |
62 | /**
63 | * A breakpoint mixin.
64 | * Source: IotaCSS iota-breakpoint
65 | */
66 | @mixin breakpoint($size, $breakpoints: $global-breakpoints) {
67 | $breakpoint-found: map-has-key($breakpoints, $size);
68 |
69 | @if ($breakpoint-found == true) {
70 | $breakpoint: map-get($breakpoints, $size);
71 |
72 | @media #{$breakpoint} {
73 | @content;
74 | }
75 | } @else {
76 | @warn 'Breakpoint size \'#{$size}\' doesn\'t exist.';
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/tools/_error.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * Gives an element an :after pseudo, with an error message.
3 | *
4 | * Used with gulp-replace or similar build tool to removed it for production, e.g:
5 | * (just before gulp-clean-css)
6 | * .pipe(replace(/(\/\* dev-only:start \*\/[^]*\/\* dev-only:end \*\/)/g, ''))
7 | */
8 | @mixin error($message) {
9 | &::after {
10 | /* dev-only:start */
11 | width: 100%;
12 | font-size: 14px;
13 | font-family: monospace;
14 | content: 'Error: ' + $message;
15 | /* dev-only:end */
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/tools/_lists.scss:
--------------------------------------------------------------------------------
1 | @function first($list) {
2 | @return nth($list, 1);
3 | }
4 |
5 | @function last($list) {
6 | @return nth($list, length($list));
7 | }
8 |
--------------------------------------------------------------------------------
/tools/_make-class.scss:
--------------------------------------------------------------------------------
1 | @mixin make-class($selector, $properties, $value) {
2 | #{$selector} {
3 | @each $property in $properties {
4 | #{$property}: #{$value};
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/tools/_make-utility.scss:
--------------------------------------------------------------------------------
1 | @mixin make-class-from-placeholder($utility-name, $properties) {
2 | // For no breakpoint
3 | .#{$utility-name} {
4 | @extend %#{$utility-name};
5 | }
6 |
7 | // For every breakpoint
8 | // Disabled because it creates a TON of styles in style.css, because can't extend within @medias.
9 | // @each $breakpoint-key, $breakpoint-value in $global-breakpoints {
10 | // .#{$utility-name + '--' + $breakpoint-key} {
11 | // @include breakpoint($breakpoint-key) {
12 | // @each $property, $value in $properties {
13 | // #{$property}: $value;
14 | // }
15 | // }
16 | // }
17 | // }
18 | }
19 |
20 | @mixin make-placeholder($utility-name, $properties) {
21 | // For no breakpoint
22 | %#{$utility-name} {
23 | @each $property, $value in $properties {
24 | #{$property}: $value;
25 | }
26 | }
27 |
28 | // For every breakpoint
29 | @each $breakpoint-key, $breakpoint-value in $global-breakpoints {
30 | %#{$utility-name + $global-breakpoint-separator + $breakpoint-key} {
31 | @include breakpoint($breakpoint-key) {
32 | @each $property, $value in $properties {
33 | #{$property}: $value;
34 | }
35 | }
36 | }
37 | }
38 | }
39 |
40 | @mixin make-utility($args) {
41 | $class: map-use(
42 | $args,
43 | class,
44 | false
45 | );
46 |
47 | $args: map-remove($args, class);
48 |
49 | // If 'alias' key exists in $args, use that for the placeholder-name,
50 | // otherwise use the key and value of the first property in $args
51 | $utility-name: map-use(
52 | $args,
53 | alias,
54 | first(map-keys($args)) + '-' + first(map-values($args))
55 | );
56 |
57 | $utility-name: 'u-' + $utility-name;
58 |
59 | $properties: map-remove($args, alias);
60 |
61 | // Debug output to list off all the placeholders being made:
62 | // @if ($class) {
63 | // @debug('Making placeholder & class: ' + $utility-name);
64 | // } else {
65 | // @debug('Making placeholder: ' + $utility-name);
66 | // }
67 |
68 | @include make-placeholder($utility-name, $properties);
69 |
70 | @if ($class or $global-everything-as-class) {
71 | @include make-class-from-placeholder($utility-name, $properties);
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/tools/_map-use.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * If a map contains a specific key, return it's value, else return a fallback.
3 | *
4 | * For example:
5 | * $myMap: ('a': 'foo', 'b': 'bar');
6 | * property: map-use($myMap, a, 'that key is not in the map');
7 | *
8 | * Gives the results:
9 | * property: 'foo';
10 | *
11 | * If there were no 'a' key then the reults would be:
12 | * property: 'that key is not in the map';
13 | */
14 | @function map-use($map, $key, $fallback) {
15 | @return if(map-has-key($map, $key), map-get($map, $key), $fallback);
16 | }
17 |
--------------------------------------------------------------------------------
/tools/_math.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * Get a percentage value of the second value from a first, in a list.
3 | *
4 | * E.g. get-percent-from-list((16, 4)) returns 25, as 4 is 25% of 16
5 | */
6 | @function get-percent-from-list($list) {
7 | @return (100 / nth($list, 1) * nth($list, 2));
8 | }
9 |
--------------------------------------------------------------------------------
/tools/_strings.scss:
--------------------------------------------------------------------------------
1 | @function str-replace($string, $search, $replace: '') {
2 | $index: str-index($string, $search);
3 |
4 | @if $index {
5 | $before: str-slice($string, 1, $index - 1);
6 | $after: str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
7 | @return $before + $replace + $after;
8 | }
9 |
10 | @return $string;
11 | }
12 |
13 | @function to-string($list, $glue: '', $is-nested: false) {
14 | $result: null;
15 |
16 | @for $i from 1 through length($list) {
17 | $e: nth($list, $i);
18 |
19 | @if type-of($e) == list {
20 | $result: $result#{to-string($e, $glue, true)};
21 | } @else {
22 | $result: if($i != length($list) or $is-nested, $result#{$e}#{$glue}, $result#{$e});
23 | }
24 | }
25 |
26 | @return $result;
27 | }
28 |
29 | @function strip-unit($number) {
30 | @if type-of($number) == 'number' and not unitless($number) {
31 | @return $number / ($number * 0 + 1);
32 | }
33 |
34 | @return $number;
35 | }
36 |
37 | @function to-px($number) {
38 | /* stylelint-disable-next-line length-zero-no-unit */
39 | @return $number + 0px;
40 | }
41 |
42 | @function to-rem($number) {
43 | /* stylelint-disable-next-line length-zero-no-unit */
44 | @return $number + 0rem;
45 | }
46 |
--------------------------------------------------------------------------------
/tools/_type.scss:
--------------------------------------------------------------------------------
1 | @mixin font-scale($smallest, $largest) {
2 | font-size: #{to-px($smallest)};
3 |
4 | @media (min-width: #{to-px($breakpoint-smallest-font)}) and (max-width: #{to-px($breakpoint-largest-font)}) {
5 | $font-diff: strip-unit($largest) - strip-unit($smallest);
6 | $breakpoint-diff: strip-unit($breakpoint-largest-font) - strip-unit($breakpoint-smallest-font);
7 | $vw-minus-smallest-breakpoint: 100vw - #{to-px($breakpoint-smallest-font)};
8 |
9 | font-size: calc(#{to-px($smallest)} + #{$font-diff} * (#{$vw-minus-smallest-breakpoint}) / #{$breakpoint-diff});
10 | }
11 |
12 | @media (min-width: #{to-px($breakpoint-largest-font)}) {
13 | font-size: #{to-px($largest)};
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/type/__import.scss:
--------------------------------------------------------------------------------
1 | @import
2 | 'headings',
3 | 'p';
4 |
--------------------------------------------------------------------------------
/type/_headings.scss:
--------------------------------------------------------------------------------
1 | @for $level from 1 through 5 {
2 | .type-h#{$level} {
3 | line-height: 1.25;
4 | }
5 | }
6 |
7 | .type-h1 {
8 | @include font-scale(34, 40);
9 | }
10 |
11 | .type-h2 {
12 | @include font-scale(30, 34);
13 | }
14 |
15 | .type-h3 {
16 | @include font-scale(28, 32);
17 | }
18 |
--------------------------------------------------------------------------------
/type/_p.scss:
--------------------------------------------------------------------------------
1 | .type-p {
2 | @include font-scale(16, 18);
3 | line-height: 1.5;
4 | }
5 |
--------------------------------------------------------------------------------
/utilities/__import.scss:
--------------------------------------------------------------------------------
1 | @import
2 | 'background',
3 | 'border-radius',
4 | 'box-sizing',
5 | 'color',
6 | 'content',
7 | 'display',
8 | 'flex',
9 | 'gc',
10 | 'gc-start',
11 | 'height',
12 | 'margin',
13 | 'overflow',
14 | 'padding',
15 | 'pointer-events',
16 | 'position',
17 | 'transform',
18 | 'type',
19 | 'visibility',
20 | 'width',
21 | 'z-index';
22 |
--------------------------------------------------------------------------------
/utilities/_background.scss:
--------------------------------------------------------------------------------
1 | @each $key, $value in ($auto-colors) {
2 | @include make-utility((
3 | alias: 'bg-color-' + $key,
4 | class: true,
5 | background-color: $value
6 | ));
7 | }
8 |
9 | @each $value in (cover, contain) {
10 | @include make-utility((
11 | alias: 'bg-size-' + $value,
12 | background-size: $value
13 | ));
14 | }
15 |
--------------------------------------------------------------------------------
/utilities/_border-radius.scss:
--------------------------------------------------------------------------------
1 | @include make-utility((
2 | alias: rounded,
3 | class: true,
4 | border-radius: .25rem
5 | ));
6 |
7 | @include make-utility((
8 | alias: round,
9 | class: true,
10 | border-radius: 50%
11 | ));
12 |
13 | @include make-utility((
14 | alias: pill,
15 | class: true,
16 | border-radius: 1e3px
17 | ));
18 |
--------------------------------------------------------------------------------
/utilities/_box-sizing.scss:
--------------------------------------------------------------------------------
1 | @include make-utility((
2 | alias: border-box,
3 | class: true,
4 | box-sizing: border-box
5 | ));
6 |
7 | @include make-utility((
8 | alias: content-box,
9 | class: true,
10 | box-sizing: content-box
11 | ));
12 |
--------------------------------------------------------------------------------
/utilities/_color.scss:
--------------------------------------------------------------------------------
1 | @each $name, $hex in ($auto-colors) {
2 | @include make-utility((
3 | alias: 'color-' + $name,
4 | class: true,
5 | color: $hex
6 | ));
7 | }
8 |
--------------------------------------------------------------------------------
/utilities/_content.scss:
--------------------------------------------------------------------------------
1 | // Note that the utility alias MUST be the key of this map, because identical keys are not allowed
2 | $content-utilities: (
3 | '': '',
4 | '-none': '',
5 | '-colon': ':'
6 | );
7 |
8 | @each $alias, $value in ($content-utilities) {
9 | @include make-utility((
10 | alias: 'content' + $alias,
11 | content: $value
12 | ));
13 | }
14 |
--------------------------------------------------------------------------------
/utilities/_display.scss:
--------------------------------------------------------------------------------
1 | $aliases: (
2 | 'flex',
3 | 'inline-flex',
4 | 'inline',
5 | 'inline-block',
6 | 'grid',
7 | 'inline-grid',
8 | 'block',
9 | 'display-none',
10 | 'contents'
11 | );
12 |
13 | @each $alias in $aliases {
14 | $value: str-replace($alias, 'display-');
15 | @include make-utility((
16 | alias: $alias,
17 | class: true,
18 | display: unquote($value)
19 | ));
20 | }
21 |
22 | @include make-utility((
23 | alias: border-box,
24 | class: true,
25 | box-sizing: border-box
26 | ));
27 |
--------------------------------------------------------------------------------
/utilities/_flex.scss:
--------------------------------------------------------------------------------
1 | @each $direction in (row, row-reverse, column, column-reverse) {
2 | @include make-utility((
3 | alias: 'fd-' + $direction,
4 | flex-direction: $direction
5 | ));
6 | }
7 |
8 | @each $wrap in (nowrap, wrap, wrap-reverse) {
9 | @include make-utility((
10 | alias: 'fw-' + $wrap,
11 | flex-wrap: $wrap
12 | ));
13 | }
14 |
15 | @each $direction in (row, row-reverse, column, column-reverse) {
16 | @each $wrap in (nowrap, wrap, wrap-reverse) {
17 | @include make-utility((
18 | alias: 'ff-' + $direction + '-' + $wrap,
19 | flex-flow: $direction + ' ' + $wrap
20 | ));
21 | }
22 | }
23 |
24 | @each $value in (flex-start, flex-end, center, space-between, space-around) {
25 | @include make-utility((
26 | alias: 'jc-' + $value,
27 | class: true,
28 | justify-content: $value
29 | ));
30 | }
31 |
32 | @each $value in (center) {
33 | @include make-utility((
34 | alias: 'ji-' + $value,
35 | class: true,
36 | justify-items: $value
37 | ));
38 | }
39 |
40 | @each $value in (flex-start, flex-end, center, stretch, baseline) {
41 | @include make-utility((
42 | alias: 'ai-' + $value,
43 | class: true,
44 | align-items: $value
45 | ));
46 | }
47 |
48 | @include make-utility((
49 | alias: 'fb-0',
50 | flex-basis: 0
51 | ));
52 |
53 | @each $value in (0, 1) {
54 | @include make-utility((
55 | alias: 'fs-' + $value,
56 | flex-shrink: $value
57 | ));
58 |
59 | @include make-utility((
60 | alias: 'fg-' + $value,
61 | flex-grow: $value
62 | ));
63 | }
64 |
--------------------------------------------------------------------------------
/utilities/_gc-start.scss:
--------------------------------------------------------------------------------
1 | @for $i from -1 through $global-grid-columns {
2 | @include make-utility((
3 | alias: 'gc-start-' + $i,
4 | grid-column-start: $i
5 | ));
6 | }
7 |
--------------------------------------------------------------------------------
/utilities/_gc.scss:
--------------------------------------------------------------------------------
1 | $columns: $global-grid-columns;
2 |
3 | @for $start from 1 through $columns {
4 | @for $span from 1 through $columns {
5 | // Only add object if the specified values don't "overflow" out of the grid
6 | @if $start + $span < $columns + 2 {
7 | @include make-utility((
8 | alias: 'gc-' + $start + '-' + $span,
9 | grid-column: $start + ' / span ' + $span,
10 | width: 100%
11 | ));
12 | }
13 | }
14 | }
15 |
16 | @include make-utility((
17 | alias: 'gc-full',
18 | grid-column: '1 / -1'
19 | ));
20 |
--------------------------------------------------------------------------------
/utilities/_height.scss:
--------------------------------------------------------------------------------
1 | @include make-utility((
2 | alias: 'height-100' + $global-unit-percent,
3 | class: true,
4 | height: 100%
5 | ));
6 |
7 | @include make-utility((
8 | height: 1px
9 | ));
10 |
--------------------------------------------------------------------------------
/utilities/_margin.scss:
--------------------------------------------------------------------------------
1 | @mixin create-margin-utils($value, $alias: $value) {
2 | @include make-utility((
3 | alias: 'm-' + $alias,
4 | class: true,
5 | margin: $value
6 | ));
7 |
8 | @include make-utility((
9 | alias: 'mx-' + $alias,
10 | class: true,
11 | margin-right: $value,
12 | margin-left: $value
13 | ));
14 |
15 | @include make-utility((
16 | alias: 'my-' + $alias,
17 | class: true,
18 | margin-top: $value,
19 | margin-bottom: $value
20 | ));
21 |
22 | @include make-utility((
23 | alias: 'mt-' + $alias,
24 | class: true,
25 | margin-top: $value
26 | ));
27 |
28 | @include make-utility((
29 | alias: 'mr-' + $alias,
30 | class: true,
31 | margin-right: $value
32 | ));
33 |
34 | @include make-utility((
35 | alias: 'mb-' + $alias,
36 | class: true,
37 | margin-bottom: $value
38 | ));
39 |
40 | @include make-utility((
41 | alias: 'ml-' + $alias,
42 | class: true,
43 | margin-left: $value
44 | ));
45 | }
46 |
47 | // Create margin utilities for -1...-16, then 1..16
48 | @each $sign in -1, 1 {
49 | @for $i from 1 through $global-size-range {
50 | $alias: $sign * $i;
51 | $value: $alias * $global-size-step;
52 | @include create-margin-utils($value, $alias);
53 | }
54 | }
55 |
56 | // Create margin utilities for auto (e.g. u-mx-auto), then 0 (unitless)
57 | @each $value in auto, 0 {
58 | @include create-margin-utils($value);
59 | }
60 |
--------------------------------------------------------------------------------
/utilities/_overflow.scss:
--------------------------------------------------------------------------------
1 | $overflow-properties: (
2 | ov: overflow,
3 | ov-x: overflow-x,
4 | ov-y: overflow-y
5 | );
6 |
7 | $overflow-values-classes: (
8 | visible: false,
9 | hidden: true,
10 | scroll: false,
11 | auto: false
12 | );
13 |
14 | @each $property-alias, $property in ($overflow-properties) {
15 | @each $value, $is-class in ($overflow-values-classes) {
16 | @include make-utility((
17 | alias: $property-alias + '-' + $value,
18 | class: $is-class,
19 | $property: $value
20 | ));
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/utilities/_padding.scss:
--------------------------------------------------------------------------------
1 | @mixin create-padding-utils($value, $alias: $value) {
2 | @include make-utility((
3 | alias: 'p-' + $alias,
4 | class: true,
5 | padding: $value
6 | ));
7 |
8 | @include make-utility((
9 | alias: 'px-' + $alias,
10 | class: true,
11 | padding-right: $value,
12 | padding-left: $value
13 | ));
14 |
15 | @include make-utility((
16 | alias: 'py-' + $alias,
17 | class: true,
18 | padding-top: $value,
19 | padding-bottom: $value
20 | ));
21 |
22 | @include make-utility((
23 | alias: 'pt-' + $alias,
24 | class: true,
25 | padding-top: $value
26 | ));
27 |
28 | @include make-utility((
29 | alias: 'pr-' + $alias,
30 | class: true,
31 | padding-right: $value
32 | ));
33 |
34 | @include make-utility((
35 | alias: 'pb-' + $alias,
36 | class: true,
37 | padding-bottom: $value
38 | ));
39 |
40 | @include make-utility((
41 | alias: 'pl-' + $alias,
42 | class: true,
43 | padding-left: $value
44 | ));
45 | }
46 |
47 | // Create padding utilities for -1...-16, then 1..16
48 | @each $sign in -1, 1 {
49 | @for $i from 1 through $global-size-range {
50 | $alias: $sign * $i;
51 | $value: $alias * $global-size-step;
52 | @include create-padding-utils($value, $alias);
53 | }
54 | }
55 |
56 | // Create padding utilities for 0 (unitless)
57 | @include create-padding-utils(0);
58 |
--------------------------------------------------------------------------------
/utilities/_pointer-events.scss:
--------------------------------------------------------------------------------
1 | @include make-utility((
2 | alias: 'events-none',
3 | class: true,
4 | pointer-events: none
5 | ));
6 |
7 | @include make-utility((
8 | alias: 'events-all',
9 | class: true,
10 | pointer-events: all
11 | ));
12 |
--------------------------------------------------------------------------------
/utilities/_position.scss:
--------------------------------------------------------------------------------
1 | @each $value in (absolute, relative) {
2 | @include make-utility((
3 | alias: 'pos-' + $value,
4 | class: true,
5 | position: $value
6 | ));
7 | }
8 |
9 | @each $property in (top, right, bottom, left) {
10 | // E.g. `@extend %u-right;` To align to right
11 | @include make-utility((
12 | class: true,
13 | alias: $property,
14 | $property: 0
15 | ));
16 |
17 | @each $value in (50, 100) {
18 | @include make-utility((
19 | alias: $property + '-' + $value + $global-unit-percent,
20 | class: true,
21 | $property: $value * 1%
22 | ));
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/utilities/_transform.scss:
--------------------------------------------------------------------------------
1 | @each $property in (translateX, translateY) {
2 | @each $value in (-100, -50, 0, 50, 100) {
3 | @include make-utility((
4 | alias: $property + '-' + $value + $global-unit-percent,
5 | transform: $property + '(' + $value + '%)'
6 | ));
7 | }
8 | }
9 |
10 | @each $value in (-100, -50, 0, 50, 100) {
11 | @include make-utility((
12 | alias: 'translate-' + $value + $global-unit-percent,
13 | transform: unquote('translate' + '(' + $value + '%, ' + $value + '%)')
14 | ));
15 | }
16 |
--------------------------------------------------------------------------------
/utilities/_type.scss:
--------------------------------------------------------------------------------
1 | @each $value in (capitalize, lowercase, uppercase) {
2 | @include make-utility((
3 | alias: $value,
4 | text-transform: $value,
5 | class: true
6 | ));
7 | }
8 |
9 | @each $value in (left, center, right) {
10 | @include make-utility((
11 | text-align: $value
12 | ));
13 | }
14 |
15 | @include make-utility((
16 | alias: underline,
17 | text-decoration: underline
18 | ));
19 |
--------------------------------------------------------------------------------
/utilities/_visibility.scss:
--------------------------------------------------------------------------------
1 | @each $value in (hidden, visible) {
2 | @include make-utility((
3 | visibility: $value
4 | ));
5 | }
6 |
--------------------------------------------------------------------------------
/utilities/_width.scss:
--------------------------------------------------------------------------------
1 | @include make-utility((
2 | alias: 'width-100' + $global-unit-percent,
3 | class: true,
4 | width: 100%
5 | ));
6 |
7 | @include make-utility((
8 | width: 1px
9 | ));
10 |
--------------------------------------------------------------------------------
/utilities/_z-index.scss:
--------------------------------------------------------------------------------
1 | @for $i from -1 through 9 {
2 | @include make-utility((
3 | alias: 'z-index-' + $i,
4 | z-index: $i
5 | ));
6 | }
7 |
--------------------------------------------------------------------------------