mdgriffith / style-elements-design-discussion

BSD 3-Clause "New" or "Revised" License
8 stars 0 forks source link

Style, Layout, Position - Categorized Style Classes #10

Closed mdgriffith closed 7 years ago

mdgriffith commented 7 years ago

Going a bit with the idea that style properties can be categorized, one potential design is to have style classes which only allow a specific kind of style property.

So, for example, a layout style could only have layout properties. Here's an example showing a stylesheet with both a layout style class and a style class which can have any property except layout.

stylesheet =
    Style.render
        [ style Nav
            [ font "Roboto"
            , fontsize 18
            , textColor (Color.darkGrey)
            , letterSpacing 10
            , light
            , property "text-transform" "uppercase"
            , textAlign center
            ]
        , layout Centered
            [ spacing (all 20)
            , flowRight
                { wrap = True
                , horizontal = center
                , vertical = center
                }
            ]
        ]
-- example of it being rendered
view =
    div [ style Nav, layout Centered ]
        [ button [] []
        , button [] [ text "button 2" ]
        ]

What does this achieve?

The goal is to make every style portable. Meaning you could grab a a class from your stylesheet and put it on any element in your view and it would look fine.

By forcing these to be separate we can move both our Nav style or our Centered layout classes to any other element and they'll generally have the effect we want.

Also, layout as a category is especially interesting because it's entirely concerned with modifying something about it's children elements. This makes it a piece of information that feels natural to include as a part of the html markup instead of hidden in your stylesheet. This means I know a style affects it's children if it's a layout style.

Similarly, I believe breaking out position into it's own "enforced style class group" makes sense because position information generally cares about an element's place in the html hierarchy.

I toyed with the idea of breaking every property category into it's own enforced class, but after some experimentation I don't think that's really the right way to go. position and layout make sense because they specifically care about the html hierachy. Other properties don't. As well, most normal styles involve one or two properties from multiple categories, which would make that separation a huge pain.

I also think that the majority of combining styles should happen in the stylesheet or else tracking down weird style interactions is difficult.

One Class Per Element and Variations

One of the challenges of managing CSS is that there are so many different places to combine styles, either as mixins, using multiple classes on an element, and inherited properties.

style-elements only allows top level classes to be defined. Children selectors can't be expressed.

As well, classes in style-elements are not meant to be combinable in your DOM willy-nilly.

The only way to render multiple classes is to create a variation, which is a style class that can only be rendered as a variation of the class it's embedded.

Here's an example:

stylesheet =
    Style.render
        [ style Button
            [ backgroundColor (Color.blue)
            , textColor (Color.white)
            , variation Disabled
                [ backgroundColor (Color.grey)
                , textColor (Color.black)
                ]
            ]
        ]

view =
     button [ Style.styleVariations Button [ Disabled => True ] ]
             [text "Yay, button!"]

The variation Disabled is only valid for the Button class.

Btw, if anyone has a better name than Style.styleVariations, I'm all ears.

mdgriffith commented 7 years ago

So, in thinking about only allowing top level classes (i.e. no child selectors).

One alternative is to only allow the > selector and only allow it to go one level deep.

I was thinking about this while reading rcss

stylesheet =
    Style.render
        [ style Nav
            [ font "Roboto"
            , fontsize 18
            , textColor (Color.darkGrey)
            , letterSpacing 10
            , light
            , property "text-transform" "uppercase"
            , textAlign center
            , child ProfileButton  -- Compiles to .nav > .profile-button {}
                   [ textColor Color.red
                   -- though I'd want to prevent any sort of deeper level nesting of children.
                   ]
            ]

        ]
Dremora commented 7 years ago

Hi! Thanks for putting the effort into the new design, I think this is the biggest thing that Elm is currently missing.

First, I'd like to share this great article which pretty much expresses my thoughts on writing maintainable and scalable CSS.

Second, I'd like to point out some aspects of styling in React Native. <Text> and <TextInput> are the only components that can receive text and font-related styles. These are the only properties that can be inherited. <Text> can only have other <Text> children. It is thus impossible to override, say, text color of a child component. I think it's a great design. CSS originally allowed inheritance as was used to style documents. Now that we are designing applications, inheritance as a concept is only relevant within text nodes. I can thus suggest creating a category for all properties related to text (and that includes color).

For some inspiration, I also recommend looking at the design of styled-components, a new library for React which has already gained a lot of traction and is my favourite CSS-in-JS solution.

Now I'll make some comments.

The goal is to make every style portable. Meaning you could grab a a class from your stylesheet and put it on any element in your view and it would look fine.

I don't think it's a good goal as it leads to extensive styling reuse. In my experience, it in turn always leads to maintenance issues. The article I have linked above goes into more details.

However, the separation still might be useful if you can prevent certain groups of styles to be applied to certain elements. E.g. don't allow styling div with text-level information.

One Class Per Element and Variations

I like this section!

Btw, if anyone has a better name than Style.styleVariations, I'm all ears.

In BEM this is commonly known as “modifier”.

mdgriffith commented 7 years ago

Only allowing inheritance for text/font sounds like a very good idea! I knew limiting inheritance was going to be an important concept in style-elements, but that is nice and specific.

I've added the resources you've mentioned to the references page.

mdgriffith commented 7 years ago

A lot of these ideas made it into the library! I'm archiving this though, we've kinda moved past it.