Closed kfigiela closed 4 months ago
Hey, thanks for opening this discussion! I really appreciate you voicing your frustration with that choice, which is obviously very opinionated. I suspect other users feel the same.
First, have you used a framework with utility styles? TailwindCSS is really popular in the front-end community, and for good reason. I've worked with CSS for more than 20 years, and this method of CSS reuse scales much better than traditional approaches. My reaction would have been exactly the same as yours before learning this method. I'd highly recommend giving Tailwind and/or web-view a deep dive before giving up on the idea. I think you'll really enjoy it.
That said, your points are all valid. Let's focus in on a couple of them to start:
class name collisions on row and col
Can you explain? What were they conflicting with? Bootstrap?
hyper adding col, being unable to pass mods to it
HTML and CSS are really great at using nesting for composability. I haven't yet found any use-case that couldn't be solved by nesting another container inside the hyper
.
hyper MyView $ do
-- use styles and layout here
col (pad 20 . gap 20 . color Green) $ do
el_ "Hello"
Would your issue be solved using the above technique?
browser dev tools experience was not that great as CSS rules were rendered as a part of dynamic content – overwritten in my case every 1s because of polling,
Interesting. I never ran into this using tailwind or web-view because views that poll are so rare. But the JS client is modifying the HTML with vdom, so if the css isn't changing, it won't change in the devtools. I just verified this with the LazyLoading example. The classes inside the polling container don't ever change. Are you changing the styles based on the poll?
lot of this was just prop with text-based values, as web-view support is not yet there.
Agreed that web-view needs a lot of improvement. I think we should open some issues over there for those that don't involve Hyperbole. Prefixing classes is a good idea. I'd like to know which attributes you need that aren't currently provided.
Thanks again for all your feedback! I've added you to the contributors list.
Well, I haven't been doing a lot of frontend work over recent years, so I'm not up-to-date with the current best practice. Still, my use case, which is an internal tool with a couple of screens total and no potential for scaling/reusing, it hardly matters – essentially, in such circumstances, I'll pick whatever gets job done, e.g. has ready to use well decent looking components that I may need.
class name collisions on row and col
That's the case for Milligram, but row
and col
are super generic, therefore collision-prone.
I haven't yet found any use-case that couldn't be solved by nesting another container inside the hyper.
I eventually figured it out, possibly doing some override there, but that was a little annoyance that there was element/attribute that I could not control. As for more reasonable (but not necessarily practical) example. How about having hyper view in an inline element?
I never ran into this using tailwind or web-view because views that poll are so rare.
My use-case is essentially based on polling to display status of background process, so the milage varies ;)
Are you changing the styles based on the poll?
Classes defined should be static, but the set of classes used may change as statuses change. Dev-tools also accumulate a ton of historical (but empty) class definitions. Will report this as a separate issue when time permits.
I'd like to know which attributes you need that aren't currently provided.
Will document as I do refactoring pass in this week if time permits.
BTW, I've opened a PR on web-view a couple of days ago https://github.com/seanhess/web-view/pull/3
Thanks for the answers. This definitely boils down to the decision to force the web-view / utility css approach. This was the most opinionated design decision I made. It scales MUCH better than other approaches, mostly because you don't start with any base styles, but you can't be the only user to want something like bootstrap that looks good out of the box. That's especially true because we Haskellers aren't CSS experts and we don't want to dive in and understand.
At a minimum, the decision to use web-view needs to be explained better.
What if we were to create a bootstrap-like base UI library that looked good? It doesn't have to be much more complicated than Example.Style.
The problem is that if we provide something like that, people are going to try to modify or "inherit" them to customize their app instead of building their own definitions and composing Mods as intended. That's why I like it being an example instead of a module, but it wasn't visible or complete enough to give you confidence to avoid reaching for css frameworks.
This makes me go back to thinking its a documentation problem. Thoughts?
Having opinion on this is actually a good thing :) Web-view alone in there is not a problem, as it's pleasant to work with and you don't need to use it's CSS machinery. Hyperbole should encourage using web-view/utility css approach, but should not force using it. You can use it, or you can use whatever you want that suits your setup.
We all work in different environments or team setups and there is no silver bullet. What may scale well from CSS architecture, may not scale well in team/company setup. In one of my previous projects, we often introduced PureScript based components into existing RoR or Ember.js apps (migrating them incrementally to the modern tech) – the styles had already been there and the buisness requirement was that they looked the same. Even if "the new approach" would be much better, full rewrite would not be a feasible option, neither porting existing look'n'feel into another CSS paradigm and possibly maintaining both implementations for a while. There would be also a lot of friction if you have dedicated design/CSS team members who are not Haskellers and are not necessarily willing to learn some obscure technology.
Yet another case, is any sort of internal tooling or prototypes – you want for them to look decent, but don't need to look great. These are often one-off projects with no potential to code reuse. Ideally, you would prefer not to write any CSS, and having to use CSS library with ready to use components seems to provide the best bang for the buck.
Ok, let me think about how we could strongly encourage the utility approach, but still allow for an escape hatch when needed
My motivation creating this issue was to open up discussion on long term design. Once too much incidental coupling is introduced, rectifying it requires introducing breaking changes which is not great for open-source library.
At the moment the only blocker/struggle I can think of is #8. I haven't used forms yet, but I don't recall any issues reviewing the code. It'd be also nice to add helper such as externalClass = addClass . cls
(I defined this as cls_
) to have neat Mod
to refer to "external" CSS classes. Web-view happily adds such class to class
attribute, but since there are no props defined it's noop. Furthermore, in https://github.com/seanhess/web-view/pull/3 in addition to escaping, I specifically changed CSS rendering so web-view does not render "useless" empty class definitions to keep code tidy.
Otherwise, more examples and documentation can definitely help. I volunteer to make a small example with one of component-rich popular CSS libraries.
We added extClass
to web-view, and we are waiting on examples for #8. Closing for now, but feel free to reopen a PR/issue related to #8 with the requested information, or another issue with a narrower focus if we've missed anything else
Opening this in a response to the comment.
web-view's tagline says "write Haskell instead of CSS". This is quite interesting idea and I pretty much like it for ad-hoc styling – especially the dynamic (content-dependent) part. However, I'm not fully sold to use this as the primary way of doing styling. In the real world this may not be always optimal, for instance:
I've been playing with hyperbole for a few days now doing some prototyping work for internal tool I work on at work. What I ended up in the end is a mix of:
There were a few friction points:
row
andcol
,col
, being unable to pass mods to it.prop
with text-based values, as web-view support is not yet there.That all being said, I propose the following:
Mod
argument whenever applicable to pass extra attributes/styles without hardcoding them (that specifically applies to forms),Mod
to easily add "external" class.As for the first item, the only annoyance I found was is
hyper
that addscol
class. For that one I opened a pull request.