elm-ui/notes/CHANGES-FROM-STYLE-ELEMENTS.md

10 KiB

Compared to Style Elements

This was a MAJOR rewrite of Style Elements.

  • Major Performance improvement - Style Elements v5 is much faster than v4 due to a better rendering strategy and generating very minimal html. The rewritten architecture also allows me to explore a few other optimizations, so things may get even faster than they are now.

  • Lazy is here! - It works with no weird caveats.

No Stylesheet

You now define styles on the element itself.

el [ Background.color blue, Font.color white ] (text "I'm so stylish!")

These styles are gathered and rendered into a stylesheet. This has a few advantages:

  1. Much faster than rendering as actual inline styles
  2. More expressive power by allowing style-elements compile to pseudoclasses, css animations and the like.
  3. Defining styles like this is a really nice workflow.

Reorganization

  • No Style modules anymore, it's all under Element.
  • Style.Color and Style.Shadow have been merged into Element.Font, Element.Border, and Element.background. So things like Font.color and Border.glow now exist.
  • No more Element.Attributes, everything has been either moved to Element or to a more appropriate module.

Wait isn't Style Elements about separation of layout and style?!

It was! So why is there only Element and no StyleSheet now?

The key insight is that it's not so much the separation of layout and style that is important as it is that properties affecting layout should all be in the view function. The main thing is not having layout specified through several layers of indirection, but having everything explict and in one place.

The new version moves to a more refined version of this idea: Everything should be explicit and in your view!

Style Organization

Your next question might be "if we don't have a stylesheet, how to we capture our style logic in a nice way?"

The main thing I've found is that stylesheets in general seem to be pretty hard to maintain. Even well-typed stylesheets that only allow single classes! You have to manage names for everything, and in the case of large style refactors it's not obvious that style classes would be organized the same way.

So, I'm not sure that stylesheets or something like stylesheets are the way to go.

My current thinking is that you have 2 really powerful methods of capturing your styling logic.

  1. Just put it in a view function. If you have a few button variations you want, just create a function for each variation. You probably don't need a huge number of variations. You don't need to think of it like recreating bootstrap in style-elements.

  2. Capture your colors, font sizes, etc. Create a Style module that captures the values you use for your styling. Keep your colors there, as well as values for spacing, font names, and font sizes all in one place. You should consider using a scaling function for things like spacing and fontsizes.

Element.Region

The Element.Region module is now how you can do accessibility markup.

You can do this by adding an area notation to an element's attributes.

import Element.Region as Region

row [ Region.navigation ] 
    [ --..my navigation links
    ]

Or you can make something an <h1>

el [ Region.heading 1 ] (text "Super important stuff")

This means your accessibility markup is separate from your layout markup, which turns out to be really nice.

Alignment

Alignment got a bunch of attention to make it more powerful and intuitive.

  • Alignment now applies to the element it's attached to, so Alignment on row and column does not apply to the children but to the row or column itself.

  • It works everywhere! Previously, if you set a child as alignLeft in a row, nothing would happen. The main weirdness that had to be resolved is what happens to the other elements when an el in the middle of a row is aligned. The answer I came up with is that it will push other elements to the side.

         alignLeft(pushes element on the left of it, to the left)
         |              center(is the default now)
         |              |                    alignRight
         v              v                    v
  |-el-|-el-|---------|-el-|---------------|-el-|

Also of note, is that if something is center, then it will truly be in the center.

  • Centered by Default - els are centered by default.

Things that have been removed/deprecated

Percent - percent is no longer there for width/height values. Just use fill, because you were probably just using percent 100, right? If you really need something like percent, you can manage it pretty easy with fillPortion. The main reason this goes away is that percent allows you to accidently overflow your element when trying to sum up multiple elements.

Grids - grid, and namedGrid are gone. The reason for this is that for 95% of cases, just composing something with row and column results in much nicer code. I'm open to see arguments for grid, but I need to see specific realworld usecases that can't be done using row and column.

WrappedRows/Columns - wrappedRow and wrappedColumn are gone. From what I can see these cases don't show up very often. Removing them allows me to be cleaner with the internal style-elements code as well.

When/WhenJust - when and whenJust are removed, though you can easily make a convenience function for yourself! I wanted the library to place an emphasis on common elm constructs instead of library-specific ones. As far as shortcuts, they don't actually save you much anyway.

Full, Spacer - full and spacer have been removed in order to follow the libraries priority of explicitness. full would override the parents padding, while spacer would override the parent's spacing. Both can be achieved with the more common primitives of row, column and spacing, and potentially some nesting of layouts.

New Version of the Alpha

  • Font.weight has been removed in favor of Font.extraBold, Font.regular, Font.light, etc. All weights from 100 - 900 are represented.
  • Background.image and Background.fittedImage will place a centered background image, instead of anchoring at the top left.
  • fill |> minimum 20 |> maximum 200 is now present for minWidth, maxWidth, minHeight and maxHeight behavior. It works like fill, but with an optional top and lower bound.
  • transparent - Set an element as transparent. It will take up space, but otherwise be transparent and unclickable.
  • alpha can now be set for an element.
  • attribute has been renamed htmlAttribute to better convey what it's used for.
  • Element.Area has been renamed Element.Region to avoid confusion with WAI ARIA stuff.
  • center has been renamed centerX

New Default Behavior

The default logic has been made more consistent and hopefully more intuitive.

All elements start with width/height shrink, which means that they are the size of their contents.

PseudoClass Support

Element.mouseOver, Element.focused, and Element.mouseDown are available to style :hover, :focus and :active.

Only a small subset of properties are allowed here or else the compiler will give you an error.

This also introduced some new type aliases for attributes.

Attribute msg - What you're used to. This cannot be used in a mouseOver/focused/etc.

Attr decorative msg - A new attribute alias for attributes that can be used as a normal attribute or in mouseOver, focused, etc. I like to think of this as a Decorative Attribute.

Input

Input.select has been removed. Ultimately this came down to it being recommended against for most UX purposes.

If you're looking for a replacement, consider any of these options which will likely create a better experience:

  • Input.checkbox
  • Input.radio/Input.radioRow with custom styling
  • Input.text with some sort of suggestion/autocomplete attached to it.

If you still need to have a select menu, you can either:

Input.Notices have been removed, which includes warnings and errors. Accessibility is important to this library and this change is actually meant to make it easier to have good form validation feedback.

You can just use above/below when you need to show a validation message and it will be announced politely to users using screen readers.

Notices were originally annotated as errors or warnings so that aria-invalid could be attached. However, it seems to me that having the changes be announced politely is better than having the screen reader just say "Yo, something's invalid". You now have more control over the feedback! Craft your messages well :)

Type aliases for the records used for inputs were also removed because it gives a nicer error message which references specific fields instead of the top level type alias.

New Testing Capabilities

A test suite of ~1.6k layout tests was written(whew!). All of these tests pass on Chrome, Firefox, Safari, Edge, and IE11.

Overview of other changes

  • Font.lineHeight has been removed. Instead, spacing now works on paragraphs.
  • Element.empty has been renamed Element.none to be more consistent with other elm libraries.
  • Device no longer includes window.width and window.height. Previously every view function that depends on device was forced to rerender when the window was resized, which meant you couldn't take advantage of lazy. If you do need the window coordinates you can save them separately.
  • Fewer nodes rendered - So, things should be faster!
  • fillBetween has been replaced by Element.minimum and Element.maximum.

So now you can do things like

view =
    el 
        [ width 
            (fill
                |> minimum 20
                |> maximum 200
            )
        ]
        (text "woohoo, I have a min and max")