blakeembrey / free-style

Make CSS easier and more maintainable by using JavaScript
MIT License
707 stars 29 forks source link

Some style reuse is causing specificity issues #41

Closed basarat closed 7 years ago

basarat commented 7 years ago

I have code like this :

const className = typestyle.classes(
    props.className,
    typestyle.style(
      csx.content,

      /** Lower than breakpoint: Vertical Margined */
      csx.vertical,
      csx.verticallySpaced(spacing),

      /** Bigger than breakpoint: Horizontal Margined */
      {
        [`@media screen and (min-width: ${breakpointPx})`]: typestyle.extend(
          /** Clear stuff from the previous layout `&&` to increase specificity */
          {
            '&&>*': {
              marginBottom: '0px !important',
            }
          },
          csx.horizontal,
          csx.horizontallySpaced(spacing),
        )
      },
    )
  );

It starts off like this :

image

However as more styles are loaded the specificity changes as .f16roitj is used along with other classes:

image

What happens : even though it should be row it goes into column mode cause there are three classes (including .f16roitj) that are reusing that style object.

basarat commented 7 years ago

Recommended solution

Disable the sharing objects across different class names .f14b848v, .f16roitj, .f1d62zt {/*something*/} should actually be repeated like .f14b848v{/*something*/} .f16roitj {/*something*/} .f1d62zt {/*something*/}

basarat commented 7 years ago

Actually no. The specificity is the same and its just an ordering issue. If I just put both layouts in seperate media queries its fixed. Nevermind and thanks again ! :rose: :heart:

jamiewinder commented 7 years ago

@basarat - Hi. Sorry, I realise this isn't the ideal way to ask but in your example above you use '&&>*' to increase specificity. Is this a TypeStyle or a Free Style thing, and is it documented anywhere? It's got me out of a jam (having found it referenced here) and I'd like to know more about it, but this seems to be the only place I've seen it used!

basarat commented 7 years ago

Is this a TypeStyle or a Free Style thing

FreeStyle, called Interpolation. Docs in TypeStyle : http://typestyle.io/#/core/concept-interpolation

&& trick in docs : http://typestyle.io/#/advanced/concept-ordering-pseudo-classes :rose:

blakeembrey commented 7 years ago

Just a note on the discussion and https://github.com/typestyle/typestyle/issues/68, I'd love to find a way where possible to patch (if needed). In the majority use-case where styles are used as immutable hashes, there's no concern with conflicts with ordering, but I realise a lot of people can and will use it like traditional CSS and less JS-like. The current behaviour works by de-duping rules and styles, and every time a style is added it is added to the end of the document (e.g. a conflict would move to the bottom).

Working around this, there's two solutions I can think of:

  1. Don't re-order or de-dupe - unlikely to happen, de-duping is handy
  2. Re-think de-duping rules - we could implement something that instead generates independent classnames for each style instance and returns a list of class names to use.
Style.registerStyle({
  color: 'red',
  background: 'blue'
}) //=> ['c1', 'c2']

However, this doesn't entirely solve the media query issue - so maybe we avoid de-duping nested styles altogether or introduced a well-defined order (e.g. alphabetical in output CSS, order by sizes, always at the end, etc) to free-style.

Another note: Media query are not currently sorted internally (last insertion wins) while class properties are always alphabetically sorted.

basarat commented 7 years ago

I am happy with the way it is. The distinct set rational hasn't let me down. Same for && trick for states :rose:

blakeembrey commented 7 years ago

@basarat Thanks 😄 At the very least, if people want to avoid de-duping right now there's an opt-in way with the unique tag.