Open rtfeldman opened 7 years ago
To me the benefit of not having to change my build pipeline to use elm-css is very appealing. Also not having the mirror css
folder as proposed before is a big deal. The Html.Styled
is very elegant and easy to understand.
So I'm all in favour of this path unless there are big performance issues that are not unknown. I can ask @geelen about his experience in building styled components. But it seems that you have done plenty of research already.
I strongly agree that not introducing a build step is incredibly valuable and I do like the design of Html.Styled
.
I'm a bit saddened that it wouldn't play nicely with something like tesk9/accessible-html, since both it and Html.Styled
replace the core Html
import, but as long as there exists some possibility to extract the CSS to a .css-file, that wouldn't be too much of a problem.
To summarize my requirements/wishes:
Html msg
.A bit off topic
About the last point, I have a strong feeling that elm-css
and style-elements
should work together to a common goal (and single package). This discussion shows that elm-css
is not being a pure css generator anymore. Separating layout and theming feels like the correct approach. Elm has a very opinionated way to generate html, I think it should have a similarly opinionated way to doing styling because HTML without styles is just a pile of text. Ideally, I'd like to see a single solution to manage styling in elm app (a mix of elm-css
and style-elements
) under elm-lang
umbrella.
Thanks for your feedback @kuon!
Some thoughts:
- Keyframe animations. Media queries, I can live without if I propagate the layout to my views, like style element does.
I think elm-css
should have first-class support for keyframe animations and media queries. π
- Ability to define the styling alongside my views. On this, I'll be more nuanced. Ability to define the layout alongside my views, theming can go elsewhere.
The Html.Styled
approach supports this. π
- Autoprefixer like feature [...] there are still too many important part of css that require a prefix.
Prefixing can be implemented as a package of helper functions. I don't want to make autoprefixing support an explicit design goal because browsers have deprecated prefixing.
This means that prefixing is necessarily a short-term concern; long-term, it is already being phased out. I don't want to base long-term design decisions on something we already know will not be a long-term need!
It's already possible to do prefixing via a package that exposes helper functions, and I think that's the right approach to making it easier to work with properties that are currently prefixed.
- I need to be able to bundle a package [...] to be reused in someone's app, I don't want them to have anything else to do than including my package. This is not only an issue with css, but also images... only way now is base64 or svg.
I totally understand why you'd want that, but my high-level goal is for elm-css
to be a way to write CSS in Elm, and that's it. Sorry!
I think it makes sense to choose one approach for how that CSS is deployed, but at the end of the day I want the scope of elm-css
to be about CSS and CSS alone.
I have a strong feeling that
elm-css
andstyle-elements
should work together to a common goal (and single package).
I have a different perspective: I think elm-css
and style-elements
have polar opposite design goals and should always be separate.
Use cases that are mutually exclusive in my mind:
style-elements
being decoupled from CSS means it can do a great job at this in a way elm-css
never can because of its tight coupling to CSS.elm-css
has a very mild learning curve for a team with a lot of existing CSS knowledge (and code), it can facilitate a team transitioning from e.g. React and glamorous to Elm and elm-css
, in a way that styled-elements
never can because transitioning to it requires fundamentally rethinking how existing UI elements fit together.The point of elm-css
is to let you write CSS in Elm. The point of style-elements
is to build a UI without thinking about CSS.
I don't think it's possible to make a library that's both great at letting you think in CSS while also being great at letting you not think in CSS. π
I understand your points and even if it's not my ideal world, I agree with you. I'd just say that most of my current work targets enterprise customer that will require prefixes for at least 10 years. And today, even if you can target the most bleeding edge browser, you need prefix ( for example http://caniuse.com/#search=user-select )
I have an idea about merging elm-css
and style-elements
. Why not create a package with some type that hold style. Like StyledHtml msg
with helper functions to make it into Html msg
. This package would then be common group for elm-css
or style-elements
. I still have that very strong feeling that a standard interface to work with "styled HTML" is needed.
Both of them share a common underlying type -
VirtualDom.Node
- so they can already be used together in the same view
! π
Sorry for jumping in, but I really felt the need to share this, because I think it might be relevant for elm-css
, Html.Styled
, etc.
I think the real beauty of CSS Modules is that it allows you to decouple styling from your module entirely. If you ask me that is huge! When you create a module like the datepicker you won't know what styling is needed for each of the many websites it will appear on. The best way to solve the problem as a module developer would be to offer a default style and an interface for the module consumer to overwrite the defaults with their own CSS.
Here is an example of such interface in React (it's really simple):
The component developer loads a default style object in her component with CSS Modules. The default style object would be used in case the component consumer doesn't replace them with her own CSS Modules object that she passes in via props.classes
:
// Shared Component.
import defaultClasses from "./default.css";
const Headline = (props) => {
const classes = props.classes || defaultClasses;
return (
<div className={classes.wrap} >
<h1>
{props.title}
</h1>
</div>
);
};
The component consumer can use her own styles to style the component as simple as that:
import Headline from 'headline-package'
import myCss from "./custom.css";
<Headline classes={myCss} title="Hello"/>
All it needs is custom.css
to have a wrap
class.
With such interface the component consumer can style the third party component any way she likes. Awesome!
Unfortunately the trend in React goes into another direction. The current cool kid on the block is Styled Components. Styled Components follows another approach in which the component developer hardcodes all styles into the component. As far as I can tell, there is no way for the component consumer to overwrite the hardcoded component styles. I think this is really bad. From my experience, you always need to fiddle with the CSS of third party modules/components. I cannot just import a third party module/component and expect all its CSS align well with my page. I need to have access to the classes/ids/elements for customization.
I know React is not Elm, but when it comes to shared modules, I think the situation is similar. The module developer must expose some sort of interface that allows the module consumer to customize styles. I think it would be nice if there was a standardized interface for that. Hope it makes sense :)
I think this is another problem, customization in elm should be handled by passing view functions to the component.
On November 24, 2017 11:43:07 AM GMT+01:00, feluxe notifications@github.com wrote:
Sorry for jumping in, but I really felt the need to share this.
I think the real beauty of CSS Modules is that it allows you to decouple styling from your module entirely. If you ask me that is huge! When you create a module like the datepicker you won't know what styling is needed for each of the many websites it will appear on. The best way to solve the problem as a module developer would be to offer a default style and an interface for the module consumer to overwrite the defaults with their own CSS.
Here is an example of such interface in React:
The component developer loads a default style object in her component with CSS Modules. The default style object would be used in case the component consumer doesn't replace them with her own CSS Modules object that she passes in via
props.classes
:// Shared Component. import defaultClasses from "./default.css"; const Headline = (props) => { const classes = props.classes || defaultClasses; return ( <div className={classes.wrap} > <h1> {props.title} </h1> </div> ); };
The component consumer can use her own styles to style the component as simple as that:
import Headline from 'headline-package' import myCss from "./custom.css"; <Headline classes={myCss} title="Hello"/>
All it needs is
custom.css
to have awrap
class.With such interface the component consumer can style the third party component any way she likes. Awesome!
Unfortunately the trend in React goes into another direction. The current cool kid on the block is Styled Components. Styled Components follows another approach in which the component developer hardcodes all styles into the component. As far as I can tell, there is no way for the component consumer to overwrite the hardcoded component styles. I think this is really bad. From my experience, you always need to fiddle with the CSS of third party modules/components. I cannot just import a third party module/component and expect all its CSS align well with my page. I need to have access to the classes/ids/elements for customization.
I know React is not Elm, but when it comes to shared modules, I think the situation is similar. The module developer must expose some sort of interface that allows the module consumer to customize styles. I think it would be nice if there was a standardized interface for that. Hope it makes sense :)
-- You are receiving this because you were mentioned. Reply to this email directly or view it on GitHub: https://github.com/rtfeldman/elm-css/issues/327#issuecomment-346798753
-- Sent from my Android device with K-9 Mail. Please excuse my brevity.
Check it out!
type alias DatepickerStyles =
{ primaryColor : Css.Color
, accentColor : Css.Color
, headerStyle : Css.Style
}
datepicker : DatepickerStyles -> Html Msg
You can totally make a datepicker with customizable styles via elm-css
. π
I've been going around asking various people "If
elm-css
had One Way to Do It," what should that one way be?A major part of the motivation for this question is to figure out how people should share code with
elm-css
.For example, @abadi199's datepicker uses
elm-css
. Today, he could have chosenasPairs
, compiling to a.css
file, or compiling to a<style>
element. What if someone who wants to use his package chose differently? If they choose.css
files and he chooses<style>
elements, then their users are stuck downloading both the compiled.css
file as well as theelm-css
runtime. If he chooses.css
files and they choose<style>
, they now have to introduce a new step to their build process and asset deployment if they want to use it.If we converged on One Way to Do It, the sharing experience would get much more coherent. There are other benefits, but sharing is one case where there is no substitute for converging on one approach. Overall, I'm convinced that One Approach is a goal worth aiming for.
Which Approach?
I've been thinking a lot about what folks said in #302 and #303, and have been talking about it with a bunch of people.
A few comments that stood out to me:
Html.Styled
approach looks good.css
files would be "desirable but non-essential" and that media queries and pseudo-elements are the real key.Overall, it seems pretty clear to me that the
Html.Styled
approach is best for sharing. Users add the package as a dependency and it Just Works. Even beyond sharing,Html.Styled
also has the advantage requiring no build process or asset deployment changes; anyone could runelm package install rtfeldman/elm-css
and start using it right away.The research I've been doing in talking with folks in the JS community has been overwhelmingly positive in favor of the "render to a
<style>
tag" approach thatHtml.Styled
would use. It seems like this approach has been broadly working out very well, and even the creator of CSS Modules says he'd use one of these systems if he were starting a new project tomorrow (instead of CSS Modules, which he continues to use at work; they of course have lots of legacy code using it).Still, there are some clear downsides to
Html.Styled
.elm-css
code into your.js
bundle. There are a lot of functions in there! This will presumably be insignificant in 0.19, which has dead code elimination, but today it's a significant factor for anyone who cares about downloaded bundle size.Html.Styled
is not battle-tested the way.css
files are. (Especially considering it's still a WIP PR! :smile:)insertRule
, for example), and we can't count on having the same performance characteristics until we're using the same internals under the hood. (This is part of the Web API that's been deferred until post-0.19, but I think it's a safe bet that we'll end up having what we need to make this fast.)In talking through some other use cases with @eeue56 (theming and other things), it became apparent that
elm-css
could embraceHtml.Styled
and that anyone could build a CLI on top of it which used server side rendering under the hood to render the contents of the resulting<style>
tag to a.css
file.In a world where such a CLI existed, it would still be very clear that
Html.Styled
is the way to do it (and in this world, the README forelm-css
would probably only link to the CLI briefly), while making it possible (if less convenient than it is today) to continue using.css
files even though there would no longer be first-class support for them.Short-term implications
Having said all of this, even if this is ultimately the right path, I don't want to remove the CLI right now. I would instead prefer to introduce
Html.Styled
, describe it as the preferred choice in the README, and continue maintaining the CLI alongside it until such time asHtml.Styled
has become battle-tested enough for me to be comfortable making it the only first-class option.There would still be short-term implications to going down this path, though. Making a serious commitment to rendering styles at runtime invalidates a lot of my original design assumptions, e.g. that it didn't really matter that
none
is represented by instantiating an object with 23 fields in it because we could afford be a lot more lax with memory and CPU usage at build time.Concretely, I can imagine removing warnings (e.g. for
rgb
values over 255), and also replacing the current extensible records type trickery with phantom types, since they can provide the same compile-time guarantees but get erased at runtime. (Sonone
would become an object with 1 field at runtime, and then someday once the compiler unboxes single-constructor union types, it would become just the string"none"
at runtime.) I'm sure there would be other implications I haven't thought of yet.I ran this overall strategy by Evan and it seemed like the way to go.
Thoughts?
I'm curious to get feedback on this direction. I realize it's a lot to digest, and much has been discussed already, but there are a lot of benefits to be had!
The idea of
elm-css
being presented as "Install this like any other package, make zero modifications to your build process or asset deployment process, and now you can add type-checked styles in your code, including media queries and pseudo-classes, with styles defined right next to the view code that renders them, and while easily sharing things like datepickers with anyone else." - that idea appeals to me a great deal.I'd love to know what you all think!