jigsass-tools-selectors

0.9.2 • Public • Published

JigSass Tools Selectors

NPM version Build Status Dependency Status

Create predictable, manageable and composable CSS with zero bloat and scalability in mind

Installation

Using npm:

npm i -S jigsass-tools-selectors

Usage

@import 'path/to/jigsass-tools-selectors';

Managing CSS at scale is hard, even very hard. Code bases easily grow out of control, and dead code elimination is an onerous task.

JigSass borrows much of its architecture from inuit and ideas on CSS structure expressed elsewhere by Harry Roberts, and as such is, at its core, based on two main pillars:

  • Objects: Abstract design pattern, such as the media object meant for reuse in many unrelated contexts. Can be extended, with modifer classes, but directly mutating an object will have rippling effects. Should consist of minimal styling, to later be expanded with modifiers, utiliies and within components themselves.
  • Components: An implementation-specific piece of UI. Should not be reused outside the context of the specific component. Will often consist mostly of including objects and utils within the ruleset.
  • Utilities: Low-level, single-purpose immutable units of style, often only declaring a single declaration. These are not bound to any spcific ui or design abstruction, and can be used to change, adjust or augment

JigSass Selectors is an attempt to provide tools for better tackling these tasks, and assisting with defining and generating clean and easy to maintain CSS based on responsive-enabled, reusable object and utility classes.

In order to keep a CSS footprint to a minimum, not even a single line of the defined CSS is generated unless it is explicitly included for use.

Objects

CSS rulsets of objects and object modifiers are generated based on settings in its configuration map (passed as a parameter to the jigsass-object mixin), where classes must be explicitly enabled in the associated configuration map (passed to the mixin as the $config param) BEFORE the object is @included.

By default, CSS rulsets of objects and object modifiers are not automatically generated generated by including the jigsass-object mixin. For any output to be generated, classes must be explicitly enabled in the Object's associated configuration map (passed to the mixin as the $config param) BEFORE the object is @included.

The structure of configuration maps is:

// _objects.foo.scss 
$foo-map: (
  no-breakpoint: (
    no-modifier: true,  // Enables generation of the `.o-foo`
                        // class outside of any media query.
    bar: true,          // Enables generation of the `.o-foo--bar`
                        // modifier class outside of any media query.
  ),
  from-<bp-name>: (
    no-modifier: true,  // Enables generation of the `.o-foo--from-<bp-name>`
                        // class inside a min-width media query
                        // defined ins `$jigsass-breakpoints.length`.
    bar: true,          // Enables generation of the `.o-foo--bar--from-<bp-name>`
                        // class inside a min-width media query
                        // defined ins `$jigsass-breakpoints.length`.
  ),
  until-<bp-name>: (
    no-modifier: true,  // Enables generation of the `.o-foo--until-<bp-name>`
                        // class inside a max-width media query
                        // defined ins `$jigsass-breakpoints.length`.
   bar: true,          // Enables generation of the `.o-foo--bar--until-<bp-name>`
                        // class inside a max-width media query
                        // defined ins `$jigsass-breakpoints.length`.
  ),
  when-<bp-name>: (
    no-modifier: true,  // Enables generation of the `.o-foo--when-<bp-name>`
                        // class inside a misc media query
                        // defined ins `$jigsass-breakpoints.features`.
    bar: true,          // Enables generation of the `.o-foo--bar--when-<bp-name>`
                        // class inside a misc media query
                        // defined ins `$jigsass-breakpoints.features`.
  ),
  from-<bp-name>-until-<bp-name>: (...);
  from-<bp-name>-when-<bp-name>: (...);
  until-<bp-name>-when-<bp-name>: (...);
  from-<bp-name>-until-<bp-name>-when-<bp-name>: (...);
);
Utilities

Instead of using configuration maps or variables, which eventually become difficult to maintain and keep track of for utility classes, JigSass offers the jigsass-define-util and jigsass-util mixins, used to define utils and dynamically CSS output for them without creating duplication or changing the cascade.

Let's take a look at a simplified example:

/* _object.media.scss */
$media-conf: (
  from-large: (
    no-modifier: true,
    middletrue,
  ),
);
$media-item-conf: (
  from-large: (
    bottomtrue,
  ),
);
 
@jigsass-object(o-media, $media-conf{
  @include jigsass-classname {
    display: flex;
  }
 
  @include jigsass-classname($modifer: middle) {
    align-items: center;
  }
 
  @include jigsass-classname($modifer: reverse) {
    flex-direction: row-reverse;
  }
}
 
@jigsass-object(o-media__item, $media-item-conf{
  @include jigsass-classname($modifier: bottom) {
    align-self: flex-end;
  }
} 
 
 
/* _component.foo.scss */
.c-foo {
  // Styles unique for `.c-foo`: 
  mix-blend-mode: multiply;
}
 
  .c-foo__fig {
    @include jigsass-util(u-ml, $from: large, $modifier: 1);
    @include jigsass-util(u-mr, $from: large, $modifier: 1);
 
    // Styles unique for `.c-foo__fig`: 
    filter: blur(3px);
  }
 
    // `.foo__fig--bottom` will not actually be generated,  
    // as it has no styles of its own. 
    .c-foo__fig--bottom {
      @include jigsass-util(u-ml, $from: large, $modifier: 1);
    }
 
  // `.foo__body` will not actually be generated,  
  // as it has no styles of its own. 
  .c-foo__body {
    @include jigsass-util(u-mr, $from: large, $modifier: 1);
  }
 
 
/* _util.margin.scss */
@include jigsass-define-util(u-mr) {
  $modifier: $jigsass-util-modifier or 0;
  
  margin-right: $jigsass-util-modifier * 12px;
}
 
@include jigsass-define-util(u-ml) {
  $modifier: $jigsass-util-modifier or 0;
  
  margin-left: $jigsass-util-modifier * 12px;
}
 
 
// style.scss 
@import 'object.media';   // `.o-media` will be generated here 
@import 'component.foo';  // `.c-foo` and `.c-foo__fig` will be generated here. 
@import 'util.margin';    // `.u-ml` and `.u-mr` will be generated here. 

Will generate:

/* style.css */
@media (min-width: 65em) {
  .o-media--from-large {
    display: flex;
  }
 
  .o-media--middle--from-large {
    align-items: center;
  }
}
 
@media (min-width: 65em) {
  .o-media__item--bottom--from-large {
    align-self: bottom;
  }
}
 
 
.c-foo {
  mix-blend-mode: multiply;
}
 
  .c-foo__fig {
    filter: blur(3px);
  }
 
 
@media (min-width: 65em) {
  .u-mr--1--from-large {
     margin-right: 12px;
  }
}
@media (min-width: 65em) {
  .u-ml--1--from-large {
     margin-left: 12px;
  }
}

Notice how only the styles we actually used ended up in our CSS? How they were generated where they were defined, and only once?

When managing the generation of css utility classes through config files, it eventually becomes damn near impossible to keep track of where each class is used, and when it is safe to remove, often leaving us with codebases that are larger than they need to be.

In contrast, generating the styles by simply including them where they are being used is a lot easier to grasp and manage, while still keeping our CSS stringent and modular.

Now, with the above CSS and following html:

<article class="[ o-media--from-large  o-media--middle--from-large ]  c-foo">
  <figure class="c-foo__fig  u-mr--1--from-large">
    <!-- img1 here -->  
  </figure>
  <div class="foo__body">
    <!-- content here -->
  </div>
  <figure class="o-media__item--bottom--from-large  c-foo__fig  u-ml--1--from-large">
    <!-- img2 here -->  
  </figure>
</articel>

We can get something like this:

┌─────────────╥╥─────────────────────────────╥╥─────────────┐
│############ ║║CONTENT HEAD                 ║║             │
│############ ║║                             ║║             │
│############ ║║ minus saepe sequi velit a,  ║║ ############│
│##  IMG1  ## ║║ sit veniam quia quibusdam   ║║ ############│
│############ ║║ odio itaque non! Dolores    ║║ ############│
│############ ║║ deserunt atque repudiandae  ║║ ##  IMG2  ##│
│############ ║║ asperiores rerum velit      ║║ ############│
│             ║║ magnam deleniti deleniti    ║║ ############│
│             ║║ sed aspernatur commodi?     ║║ ############│
└─────────────╨╨─────────────────────────────╨╨─────────────┘

The jigsass-object and jigsass-util mixins will generate selectors according to the following logic:

.class-name[--modifier][-[-from-{breakpoint-name}][-until-{breakpoint-name}][-misc-{breakpoint-name}]]

Please check the full documentation for a better understanding of how to use jigsass-tools-selectors.

Development

It is a best practice for JigSass modules to not automatically generate css on @import, but rather have to user explicitly enable the generation of specific styles from the module.

Contributions in the form of pull-requests, issues, bug reports, etc. are welcome. Please feel free to fork, hack or modify JigSass Tools Selectors in any way you see fit.

Writing documentation

Good documentation is crucial for scalability and maintainability. When contributing, please do make sure that all Sass functionality (functions, mixins, variables and placeholder selectors) is well documented.

Documentation is auto-generated using SassDoc

Running tests

gulp lint will, well, lint the contents scss files in the scss directory.

gulp test with run module's test using Mocha and Sassaby.

gulp tdd will watch both the Sass files and the test specs for changes, and will run tests automatically upon them.

Writing tests

JigSass Tools Selectors tests are written using Sassaby and Mocha. Spec files are located in the test directory.

Mocha allows us to place a call to before() in the root of any test file and it will be run once, before all the other tests in every test_*.js file. We can also require() files and assign them to the global object to make them available to all test_*.js files.

jigsass-tools-selectors uses a file called helper.js can be used to set up mocha globals requires and before().

In addition to Sassaby's testing functions, jigsass-tools-selectors makes a few Sass functions available to the test suite, for use inside Sassaby tests:

jig-var-equals($value, $var) -> {boolean}
Check if a variable equals a value.
$value {*}: A value to compare the value of $var to.
$var {*}: The variable to test
jig-var-type-is($type, $var) -> {boolean}
Check if a variable is of a certain type.
$type {string}: A type to compare with the type of $var.
$var {*}: The variable to test
jig-map-key-equals($value, $map, $keys...) -> {boolean}
Check if a map's key is assigned a cerain value.
$value {*}: A value to compare the value of a key in $map with.
$map {map}: The map to test.
$keys... {arglist}: A recursive chain of keys.
jig-map-key-type-is($type, $map, keys...) -> {boolean}
Check if a map's key is of a certain type
$type {string}: A type to compare with the type of $var.
$map {map}: The map to test.
$keys... {arglist}: A recursive chain of keys.

File structure

┬ ./
├─┬ scss/ 
│ └─ index.scss # The module's importable file. 
├── sassdoc/    # Generated documentation  
│               # of the module's sass features 
└─┬─ test/
  │
  ├─┬ helpers/
  │ │
  │ ├── importer.scss       # Used for easilty importing tested scss files 
  │ │
  │ └── _test_helpers.scss  # JigSass's assertion helpers, 
  │                         # for use inside Sassaby tests. 
  │                         
  ├── helper.js             # Used for defining global `before()` 
  │                         # functions and requiring modules. 
  │                         
  └── test_jigsass-tools-selectors  # Specs. Mocha will automatically  
                                    # run all javascript files located 
                                    # in the `test` directory. 

License: MIT

Package Sidebar

Install

npm i jigsass-tools-selectors

Weekly Downloads

34

Version

0.9.2

License

MIT

Last publish

Collaborators

  • txhawks