GithubHelp home page GithubHelp logo

gi972 / free-style Goto Github PK

View Code? Open in Web Editor NEW

This project forked from blakeembrey/free-style

0.0 2.0 0.0 102 KB

Make CSS easier and more maintainable by using JavaScript

License: MIT License

TypeScript 100.00%

free-style's Introduction

Free-Style

NPM version NPM downloads Build status Test coverage

Free-Style is designed to make CSS easier and more maintainable by using JavaScript.

Installation

npm install free-style --save

Why?

There's a great presentation by Christopher Chedeau you should check out.

Solved by using CSS in JS

  • No global variables (Where and what is .button? Why does it conflict?)
  • Built in dependency system (CommonJS, Require.js, <script />)
  • Dead code elimination (Automatically remove unused styles)
  • Minification (Minify JS with existing tools)
  • Shared constants and reusable styles (Using variables and objects)
  • Isolation (Every style is automatically namespaced)
  • Extensible (Just use JavaScript - everything from math to color manipulation already exists!)

Also solved with Free-Style

  • Working with legacy DOM components (You can nest .class-name in your styles)
  • Expose third-party and semantic hooks/theming through ordinary class names (.button)
  • Consistently generates styles and class names (Generates the exact same on client and server, and will magically merges duplicate styles)
  • Develop components alongside the style (No more hunting CSS files for estranged ul > li > a)
  • Create isomorphic applications by serving styles for only the components rendered (With third-parties, see React Free-Style)
  • Continue using CSS you already know ({ '&:hover': { ... } })
  • Automatically namespace @-rule styles ({ '@media (min-width: 500px)': { ... } })
  • Overload CSS properties using arrays ({ backgroundColor: ['red', 'linear-gradient(to right, red 0%, blue 100%)'] })
  • Integrates with any third-party system
  • Extremely small and powerful API that works with any ecosystem (~360 SLOC)

But How?

Free-Style generates a consistent hash from the style, after alphabetical property ordering and formatting, to use as the class name. This allows duplicate styles to automatically be merged by checking for duplicate hashes. Every style is "registered" and assigned to a variable, which gets the most out of linters and features like dead code minification that will warn on unused variables. Using "register" returns the class name to the Style instance and style instances (returned by create()) can be merged together at runtime to output only the styles on page (see React Free-Style). Styles should generally be created outside of the application run loop (E.g. render) so the CSS string and hash are generated once only. Any time a style is added/removed/merge/unmerged an event is triggered that allows libraries and other FreeStyle instances to propagate style changes.

Ways to Use

  • stylin - The simplest abstraction, create styles, rules and keyframes, and the <style /> stays in sync.
  • easy-style - Light-weight singleton API for browsers and node
  • react-free-style - React implementation that renders styles used on the current page (universal use-case)
  • This module! - Create, compose and manipulate style instances and change events

Usage

var FreeStyle = require('free-style')

// Create a container instance.
var Style = FreeStyle.create()

// Register a new, uniquely hashed style.
var STYLE = Style.registerStyle({
  backgroundColor: 'red'
}) //=> "f14svl5e"

// Inject a `<style />` element into the `<head>`.
Style.inject()

// Figure out how to render the class name after registering.
React.render(
  <div className={STYLE}>Hello world!</div>,
  document.body
)

Styles

var BUTTON_STYLE = Style.registerStyle({
  backgroundColor: 'red',
  padding: 10
})

console.log(BUTTON_STYLE) //=> "f65pi0b"

Tip: The string returned by registerStyle is a unique hash of the content and should be used as a class in HTML.

Overload CSS Properties

Style.registerStyle({
  background: [
    'red',
    '-moz-linear-gradient(left, red 0%, blue 100%)',
    '-webkit-linear-gradient(left, red 0%, blue 100%)',
    '-o-linear-gradient(left, red 0%, blue 100%)',
    '-ms-linear-gradient(left, red 0%, blue 100%)',
    'linear-gradient(to right, red 0%, blue 100%)'
  ]
}) //=> "f1n85iiq"

Nest @-rules

Style.registerStyle({
  color: 'red',
  '@media (min-width: 500px)': {
    color: 'blue'
  }
}) //=> "fk9tfor"

Nest Selectors

Style.registerStyle({
  '.classname': {
    color: 'blue'
  }
}) //=> "fc1zv17"

Parent Selector Reference

Style.registerStyle({
  '&:hover': {
    color: 'blue'
  }
}) //=> "f1h42yg6"

Tip: The ampersand (&) will be replaced by the parent selector at runtime. In this example, the result is .f1h42yg6:hover.

Use JavaScript

var extend = require('xtend')

var ellipsisStyle = {
  whiteSpace: 'nowrap',
  overflow: 'hidden',
  textOverflow: 'ellipsis'
}

var RED_ELLIPSIS_STYLE = Style.registerStyle(extend({
  color: 'red'
}, ellipsisStyle)) //=> "fvxl8qs"

Tip: This is a shallow extend example. There are modules on NPM for deep extending objects. You can also take advantage of new JavaScript features, such as const and computed properties:

const mediaQuery = '@media (min-width: 400px)'

const style = Style.registerStyle({
  backgroundColor: 'red',
  [mediaQuery]: {
    backgroundColor: 'pink'
  }
})

Keyframes

var COLOR_ANIM = Style.registerKeyframes({
  from: { color: 'red' },
  to: { color: 'blue' }
}) //=> "h1j3ughx"

var STYLE = Style.registerStyle({
  animationName: COLOR_ANIM,
  animationDuration: '1s'
}) //=> "fibanyf"

Tip: The string returned by registerKeyframes is a hash of the contents, and the name of the animation.

Rules

Style.registerRule('@font-face', {
  fontFamily: '"Bitstream Vera Serif Bold"',
  src: 'url("https://mdn.mozillademos.org/files/2468/VeraSeBd.ttf")'
})

Style.registerRule('@media print', {
  body: {
    color: 'red'
  }
})

Style.registerRule('body', {
  margin: 0,
  padding: 0
})

Tip: Interpolation is not supported with registerRule.

Multiple Instances

var Style1 = FreeStyle.create()
var Style2 = FreeStyle.create()

// Changes in `Style2` get reflected in `Style1`.
// Use this to compose entire stylesheets or components!
Style1.merge(Style2)
Style1.unmerge(Style2)

Output

CSS String

Style.getStyles() //=> ".f65pi0b{background-color:red;padding:10px}"

Inject Styles

Please note: This is a thin wrapper around Style.getStyles() that creates and appends a <style /> element to the head (or a target element). A more complex solution would listen and react to style changes.

Style.inject(/* optional target */)

Utilities

URL

Style.url('http://example.com') //=> 'url("http://example.com")'

Join

Style.join(STYLE, 'string', { yes: true, no: false }) //=> "f1e8b20b string yes"

Useful Libraries

Lower Level Methods

Custom Hash Algorithm

Initialize Free-Style with a custom CSS class hash algorithm (by default it uses a simple, internal string hash).

create([hash]) //=> `FreeStyle.FreeStyle`

Creating Instances Manually

FreeStyle.FreeStyle // Main stylesheet instance - returned from `create()`.
FreeStyle.Style // Style's hold CSS and a generate a consistent hash of the contents.
FreeStyle.AtRule // AtRule's are lighter-weight containers that can be nested inside `FreeStyle`.
FreeStyle.Selector // Selector's hold the CSS selector and can be nested inside `Style`.
FreeStyle.Cache // `FreeStyle`, `Style` and `AtRule` all extend the cache which maintains reference counts.

Change Events

Style.addChangeListener(fn)
Style.removeChangeListener(fn)

Other Methods

Style.add(Style | AtRule) // Add to internal cache and emit change.
Style.has(Style | AtRule) // Check if the style already exists.
Style.remove(Style | AtRule) // Remove from internal cache and emit change.
Style.count(Style | AtRule) // Return the number of instances mounted.

var ChildStyle = Style.create()

Style.merge(ChildStyle) // Merge the child styles and manage changes from instance.
Style.unmerge(ChildStyle) // Unmerge the child styles and stop listening for changes.

Legacy Browsers

To support legacy browsers (<= IE8) you'll need to polyfill some ES5 features, such as Object.keys, Array.isArray and Array.prototype.map.

License

MIT

free-style's People

Contributors

blakeembrey avatar dmitrage avatar ericmatthys avatar gi972 avatar greenkeeperio-bot avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.