Skip to content

Instantly share code, notes, and snippets.

@satya164
Created May 12, 2017 02:01
Show Gist options
  • Save satya164/d23b0031c24098c409fa01a396ac37ac to your computer and use it in GitHub Desktop.
Save satya164/d23b0031c24098c409fa01a396ac37ac to your computer and use it in GitHub Desktop.

JavaScript Style Library Wishlist

  • Familiar CSS syntax: Using CSS syntax makes it easier to copy/paste code from devtools and the internet, and a huge productivity boost.
  • SCSS like & shorhand: Super nice to write things like &:hover without having to write selectors again.
  • Nesting media queries: Nice to nest media queries inside a style block instead of having to declare it like plain CSS.
  • Support for CSS animations: CSS animations are great :)
  • No coupling to HTML tag: HTML tags have semantic meaning, and coupling styles to HTML tags makes it harder to re-use the same styles, for example, sometimes some of my buttons and links have similar styles and I don't wanna repeat them.
  • Easy to override styles: Overriding styles is one of the main pain points. Many libs don't do anything special and just produce different class names for the styles I declare. Due to no class name having higher specificity, the styles depend on the declaration order which can produce inconsistent results.
  • Easy theming support: Theming is not super-common, but can be very important for some apps. Some libraries require you to declare 2 different class names, and build own theming architecture, which is not very nice.
  • Statically analyzable: Makes it possible to statically analyze CSS makes it possible to avoid JS for the CSS entirely. However, it's still nice to use declared constants etc, or things like theme === dark ? 'black' : 'white', where the library could do some static analysis to include the constant, produce separate class names etc.
  • Flow support: Some libraries break Flowtype. It'll be nice if types flow naturally even if you need to wrap the component in something.
  • Correctness - Libraries should verify that my CSS is properly terminated etc. Many times I forget to write a semi-colon etc. and break the styles.
  • Linting: No-one does it, but it'd be super-helpful to lint CSS properies to verify there are no typos. So many times I accidentally use camel case where I should've used hyphens.
  • Auto-completion: CSS should get auto-completed just like CSS files.
  • Syntax highlighting: It's important to have a good syntax highlighter just like CSS files.
@steida
Copy link

steida commented May 12, 2017

https://github.com/este/este/tree/next/test/components

My attempt for styled props built on top of the great Fela.

  • SCSS like & shorhand
  • Nesting media queries
  • No coupling to HTML tag
  • Easy to override styles
  • Easy theming support
  • Statically analyzable
  • Flow support
  • Correctness
  • Linting
  • Auto-completion
  • Syntax highlighting

But it doesn't support familiar CSS syntax, so it's a bummer. Oh, wait!
To be fair, I suppose "familiar CSS syntax" for CSS in JS makes the same sense as Angular HTML compiler.
It's unnecessary abstraction.

It's refactored version what I have in Este right now, except theme must be added manually for now (because HOC typing is hard), and React Native version wasn't yet ported.

@satya164
Copy link
Author

satya164 commented May 14, 2017

@steida it's not unnecessary abstraction. it just makes things much easier. JS objects for CSS are more of an abstraction, because the actual CSS text is abstracted out and you right it in a different syntax from what's the end product. That's one reason why I like JSX, because it's familiar and looks close to what will be the final product.

Also:

  • it's tedious when you copy CSS from somewhere/devtools and then have to change properties to camel case to make it a JS object, this has always been super annoying to me whenever I use something like aphrodite
  • it's not possible to specify multiple properties with the same name in JS, useful when you have multiple properties with same name as fallback for older browsers

Regarding your stuff, few questions:

  • What do you use for autocompletion, can't find an editor plugin which autompletes css prop names in JS?
  • What do you use as linter for css prop names and values?
  • How do you handle theming?
  • How does overriding styles work?

@steida
Copy link

steida commented May 14, 2017

it's not unnecessary abstraction. it just makes things much easier.

Or not, as we can see...

because the actual CSS text is abstracted out

For browsers, but what about React Native? React VR? Etc.

it's tedious when you copy CSS from somewhere/devtools and then have to change properties to camel case to make it a JS object

That's probably how Angular was born.

it's not possible to specify multiple properties with the same name in JS

Example?

What do you use for autocompletion

Nuclide, because it's JavaScript with Flow. Component props are not autocompleted yet, but I still remember marginBottom or color props. The theme is autocompleted fully. Of course, it's type checked.

What do you use as linter for css prop names and values?

Flow. And because Este CSS in JS is aimed to be multiplatform, I can use only numbers or percents. React Native checks wrong values, browser... I am not sure. I think I am able to write width={10} without linter. Anyway, components are jested with a lot of snapshots.

How do you handle theming?

Via context, of course. Previous implementation https://medium.com/@steida/css-in-js-the-argument-refined-471c7eb83955 used enhanced style={theme => ({})} syntax, but it I didn't like that syntax for various reasons, so now I am using theme from context without HOC helper, because HOC with types sucks. I remember some article on callstack.io, but didn't work. Anyway, I can add theme HOC anytime. No it's super explicit and 100% typed.

How does overriding styles work?

Read my article, it's super easy. Every style prop is default, so it can be overriden. Styles can be projected to any element via as property, check source code in https://github.com/este/este/tree/next (React Native version wasn't migrated yet but the principle is the same.)

https://medium.com/@steida/css-in-js-the-argument-refined-471c7eb83955

@steida
Copy link

steida commented May 14, 2017

I strongly believe that style props are better than CSS strings.

// @flow
import type { State } from '../types';
import Button from './button';
import { connect } from 'react-redux';
import { toggleDark } from '../lib/app/actions';

const ToggleDark = ({ darkEnabled, toggleDark }) => (
  <Button primary outline size={-1} onPress={toggleDark}>
    {darkEnabled ? 'Disable Dark' : 'Enable dark'}
  </Button>
);

export default connect(
  (state: State) => ({ darkEnabled: state.app.darkEnabled }),
  { toggleDark }
)(ToggleDark);

For platform-specific styles, we can use plain old style prop, which is actually processed by Fela.

@satya164
Copy link
Author

satya164 commented May 14, 2017

For browsers, but what about React Native? React VR? Etc.

I don't really care about using a CSS in JS library for React Native. It doesn't solve a problem I have and RN has it's own styling API. The problems with web are different as you are copying styles from the web and dev-tools, which is not true for RN. The main pain-point is browser's CSS which I want to optimize the DX for. I don't mind if the same DX is there or RN.

That's probably how Angular was born.

It's not about angular or any template language. Why do you use JSX instead of React.createElement? Also it's not a template language. There are no custom control flow or anything. It's just a plain string. This is just a preference IMO. I despised CSS in strings initially until I actually got to use one. Despite the lack of maturity, I loved it because of the familiarity and convenience of being able to paste styles from devtools, and I don't think JS objects can convince me otherwise.

And not to mention, when writing media queries, CSS keyframes etc. you now need to learn a completely new thing while you could have used your previous knowledge. Each library does things differently, so you don't even know what's valid.

Also even though it doesn't make a difference for me, folks who only work with CSS and not JS will have a better time with CSS syntax than JS. I get confused with style props in JS all the time, (is it '--webkitRadius' or '--webkit-radius' or webkitRadius)?

There's a tooling issue regarding linting the syntax, but it's solvable. Syntax highlighting already works for styled-components, styled-jsx etc. Autocomplete is a problem with JS objects too. Though I'm sure we'll solve these someday. We could reuse lots of existing data from the CSS linters and autocomplete plugins.

Example?

.header {
  margin: 20px;
  margin: 2rem;
}

This is just one example, but depends on browser support etc. I remember doing such things.

Nuclide, because it's JavaScript with Flow

I'm talking about CSS properties. I'm not aware of any editor plugin which will autocomplete CSS properties right now. It will certainly be super useful in RN or libraries like aphrodite.

Flow

Are there Flow types defined for each CSS property? I'm talking about a linter which actually validates the CSS properties, like display: iline-block won't be valid.

Every style prop is default, so it can be overriden

So my question was, since themes are based on context which is dynamic, how does it work if the CSS is static? Or you just use inline styles for theming and overriding.

I strongly believe that style props are better than CSS strings.

I'd say that's a personal preference. I don't like to mix my styles with other props.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment