2.2.13 • Published 8 years ago

scoped-css v2.2.13

Weekly downloads
5
License
MIT
Repository
github
Last release
8 years ago

WARNING: This module has been renamed to style-it. Please install it instead. See http://github.com/buildbreakdo/style-it

scoped-css Version Maintenance Status

Scoped CSS in two easy steps.

Install with npm.

npm install scoped-css --save

Use with node.js or webpack (barebones covered here, see Usage section below):

var Style = require('scoped-css');

// Create classes for the root element; optionally pass in a className for the
// root element if you would like to style it using your CSS style object
Style.scoped('fooRootClassName'); // => <div class='fooRootClassName _scoped-1'>

// Compile your Style object into CSS; use this for the innerHTML of your style element
Style.CSS({ '.btn:hover' : { color: 'red' } }); // => '_scoped-1 .btn:hover {background-color: red}'

Why Make This

scoped-css was created to have ↑ cohesion and ↓ coupling of files without sacrificing the power of CSS (classes, pseudo-elements, pseudo-classes, and media queries).

Loved the cohesion of Inline styles, no more flipping between HTML and CSS, with React it is all in one place. However-- ended up needing features of CSS not possible with Inline styles. And worse, found myself in the unenviable position of reimplementing CSS features in JavaScript.

With Inline styling we lose access to pseudo-classes like :hover and :nth-of-type or pseudo-elements like :before and :after, and media queries. When we start recreating CSS features in JavaScript--especially at scale--we end up with what basically amounts to custom CSS APIs on a per component or developer basis (Spaghetti served daily@work from 9:00AM - 5:00PM).

Reimplementing CSS features in JavaScript:

  • creates more code to maintain
  • adds style noise to components (index === 0 ? //do : //something; vs .foo:first-of-type)
  • slows the pace of development
  • reduces agility
  • and is a productivity barrier as new developers are onboarded (each devs implementation must be learned for each component).

Hence the conclusion: Inline styles do not scale.

There must be a better way.. lets have our cake and eat it too: scoped-css takes a middle-of-the-road approach bringing together benefits of Inline styling and External stylesheets by way of an Embedded style element and scoped selectors (read more about scoped style elements on MDN).

Inline ---- Embedded ---- External

Top Reasons to Use scoped-css Instead of Inline Styles:

  1. You already know and understand it, this is just CSS wrapped in JavaScript objects; selectors are keys and declaration blocks are objects of property-value pairs
  2. Media queries, pseudo-classes, pseudo-elements, selectors are available: full power of CSS at your fingertips
  3. Linting of CSS rule property-value pairs (internally leverage Reacts CSSPropertyOperations and warning system); Selector linting coming soon
  4. Reduce noise in components (no more index based conditionals in loops to recreate pseudo-classes like nth-of-type() or :first-child)
  5. Inline style cohesion and scoping benefits without the selector tradeoff
  6. ...

Problems with CSS at Scale (from FB Christopher Viuexx) and the ones scoped-css solves:

  • Global namespace (via scoped)
  • Dependencies (via composition, JavaScript modules, and scoped)
  • Dead code elimination
  • Minification (Possible relative to Inline styles with a CSS declaration block registry system)
  • Sharing Constants (via JavaScript modules and variables)
  • Non-deterministic Resolution (Possible; linting to warn against identical selector statements)
  • Isolation (via scoped)

Usage

import React, { Component } from 'react');
import Style from 'scoped-css';

class myComponent extends Component {

  render() {
    return (
      <section className={ Style.scoped('root') }>  // => <section class="root _scoped-1">
        <style type="text/css">{ Style.css({  // =>   <style type="text/css">
          '.root' : {                         // =>     ._scoped-1.root {
            width: '50%',                     // =>       width: 50%;
            height: '100%'                    // =>       height: 100%;
          },                                  // =>     }
          '.btn': {                           // =>     ._scoped-1 .btn {
            backgroundColor: 'blue',          // =>       background-color: blue;
            color: 'white'                    // =>       color: white;
          },                                  // =>     }
          '.btn:hover': {                     // =>     ._scoped-1 .btn:hover {
            fontWeight: 'bold'                // =>       font-weight: bold;
          }                                   // =>     }
          })}                                 // =>
        </style>                              // =    </style>
                                              // =
        <button className="btn"></button>     // =    <button class="btn"></button>
      </section>                              // =  </section>
    );
  }
}

export default myComponent;

Using Media Queries

Media queries are conditonal wrapping statements that execute a set of Styles if conditions are true. Just like in CSS, scoped-css uses nesting to signal that the parent is to wrap the child.

This looks something like:

import React, { Component } from 'react');
import Style from 'scoped-css';

class myComponent extends Component {

  render() {
    return (
      <section className={ Style.scoped() }>
        <style type="text/css">{ Style.css({
          '.root' : {
            width: '50%',
            height: '100%'
          },
          '@media only screen and (min-device-width: 320px) and (max-device-width: 480px) and (-webkit-min-device-pixel-ratio: 2)'() {
              '.btn': {
                backgroundColor: 'red'
              }
          }
          })}
        </style>

        <button className="btn"></button>
      </section>
    );
  }
}

export default myComponent;

And is output as:

  <section class="root _scoped-1">
    <style type="text/css">
     ._scoped-1.root {
        width: 50%;
        height: 100%;
      }
      @media only screen and (min-device-width: 320px) and (max-device-width: 480px) and (-webkit-min-device-pixel-ratio: 2) {
        ._scoped-1 .btn {
          background-color: 'red';
        }
      }
    </style>

    <button class="btn"></button>
  </section>

With ES6 there is support for computed property names. So we can prettify long @media strings with + operators if the key is wrapped in []. Looks something like this:

...
	<style type="text/css">{ Style.css({
	  '.root' : {
	    width: '50%',
	    height: '100%'
	  },
	  ['@media only screen and' +
			'(min-device-width: 320px) and' +
  		'(max-device-width: 480px) and' +
  		'(-webkit-min-device-pixel-ratio: 2)']() {
	      '.btn': {
	        backgroundColor: 'red'
	      }
	  }
	  })}
	</style>
...

In the near future short strings like '@media iphone6' or '@media iphone6plus' will map to the proper media query.

License

MIT. Copyright (c) 2016-present Joshua Robinson.

2.2.13

8 years ago

2.2.12

8 years ago

2.2.11

8 years ago

2.2.10

8 years ago

2.2.9

8 years ago

2.1.9

8 years ago

2.1.8

8 years ago

2.1.7

8 years ago

2.1.6

8 years ago

2.0.6

8 years ago

2.0.5

8 years ago

1.0.5

8 years ago

1.0.4

8 years ago

1.0.3

8 years ago