Open edkv opened 6 years ago
But it actually can be harmful. For example if you render some third-party view inside that div and its top-level element also has a
.test
class, you will break its styles.
Yup. Such are the dangers of global selectors! This is why I called the module Css.Foreign
instead of Css.Global
- I recommend using it only for styling DOM nodes you do not control.
I understand that maintaining a hover state in your Elm Model
may seem like an unnecessary amount of effort to avoid using a global selector, but the upside is that you don't have to worry about it breaking your styles in surprising ways in the future. 😄
I'm hitting the same issue, before we were doing everything by using Html.CssHelpers.withNamespace
. But I understand that this is not the recommend way anymore. Because something to do with toString
going away, right?
Targeting descendants is a common thing. But putting hover state in Elm is an unnecessary complex solution when we already have :hover
. And hover is not the only case when targeting descendants is needed.
For now I think I will just create a function that adds a namespace to my classes
nsClass className =
class ("someNamespace-" ++ className)
div [ nsClass "label" ] []
But something nicer in the spirit of Html.Styled would be great. But I don't have any ideas.
But something nicer in the spirit of Html.Styled would be great. But I don't have any ideas.
Off the top of my head, here's an idea:
Html.Styled.keyedChildren
"div"
[ backgroundColor blue
, hover
[ backgroundColor black
, childrenWithKey "test"
[ color white
]
]
]
[]
[ ( "test", span [] [ text "Hello" ] )
, ( "", span [] [ text " world!"] )
]
This could generate CSS like:
._d74fa3 {
background-color: blue;
}
._d74fa3:hover {
background-color: black;
}
._d74fa3:hover > ._d74fa3_test {
background-color: white;
}
Then it would add class "._d74fa3_test"
to the "Hello!"
span and nothing to the other element.
However, this approach only works with children, not arbitrary descendants. 🤔
Unsure if this makes any sense, but I imagine something like diving the process into two steps.
First you create the styles, these styles can be used inside other styles to obtain their hash.
labelStyles =
Html.Styled.styles [
color red
]
buttonStyles =
Html.Styled.styles
[ backgroundColor blue
, hover
[ class labelStyles.hash
[ color white
]
]
]
And then they can be used in the Styled.Html
button [ css buttonStyles.hash ] [
label [ css labelStyles.hash ] [ text "Hello" ]
]
I've tried the approach with storing hover state in the Model
and now I think it's actually not that bad. The problem is that it will probably introduce many stateful components that need to maintain their hover/focus/etc state and also to be reusable. And I'm actually okay with this because I'm building my app with components anyway. But for people who want to follow the "reusable views" philosophy this might be an issue.
@sporto Unfortunately that approach will have hash collisions with styles that happen to be identical in the non-hover state.
So if I do this:
labelStyles =
Html.Styled.styles [
color red
]
iconStyles =
Html.Styled.styles [
color red
]
...and then I do this:
hover
[ class labelStyles.hash
[ color white
]
, class iconStyles.hash
[ color black
]
]
That hover
will always set the color to black
, and it will do so both for descendants that use iconStyles
and for descendants that use labelStyles
- because both labelStyles
and iconStyles
will necessarily have the same hash.
There's no workaround (aside from asking the user for a namespace, i.e. not actually using a hash) because it's impossible to implement a styles
function which returns different hashes given identical arguments.
hover [ descendants [typeSelector "..." [color black ]]
Consider the following example:
Now imagine that we also need to change the font color of the first
span
onhover
over thatdiv
. I tried to useCss.Foreign
inside thecss
function and it actually works:We'll get something like
._1eea206b:hover > .test
. At first it seems that this selector isn't globally scoped and we only need to make sure that our class is unique among children. I was going to propose that selector functions should be moved back to theCss
module because of such use cases. But it actually can be harmful. For example if you render some third-party view inside that div and its top-level element also has a.test
class, you will break its styles.The same applies to
focus
and similar use cases. Also it's not only about styling children, sometimes it's useful to style siblings as well (input:focus + label
orinput[type="password"]:-webkit-autofill + label
, etc).Are there any recommendations/ideas on how to deal with such situations?