-
Notifications
You must be signed in to change notification settings - Fork 3.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Parent Selectors should have targets #1075
Comments
Example usage:
This may be a contrived example, but I have several real-world scenarios where such a syntax would be a life saver. |
There's a variety of solutions in LESS to handle this. You can assign variables and use those as part of selector chains (new in 1.3.1 I think). The |
I usually just end up writing these code blocks like this:
|
I do the same thing -- I duplicate my nested blocks with the overrides. In a real-world scenario, this results in an unmanageable amount of duplication. |
Can you explain "assign variables and use those as part of selector chains"? |
I'm probably wrong about that quote, so probably shouldn't try to explain it. That is, I haven't tried it personally. So, it looks like what you want to do is modify a selector in the inherited chain. How would this work in this case?
It's messy CSS, but it's perfectly valid CSS. |
That's a good example ... if the "parent target" matches multiple items, we'd want to choose just one. Choosing the "closest" one is my first reaction. But I think this would be an edge case. |
So far, I've scratched down several attempts to invent a syntax that I like ... and the parenthesis so far is my favorite. It seems readable, and definitely catches your attention to highlight that this is no normal selector. The only problem -- does this interfere with any existing CSS selector rules? Looking at the less parser, I see that a selector element can match I just realized that the parenthesis syntax looks almost exactly like a mixin definition ... with the exception of the class dot |
Your use case sounds like what is discussed in #965 .. what do you think? Bearing in mind |
Yeah, I feel like, unfortunately, the logic gets a little messy, and like @agatronic, there may be other ways to fill in what you want in the future. |
I agree. This over-complication is a result of a very complicated LESS structure, and time would probably be better spent in simplifying the LESS code instead of introducing a very complicated syntax. |
I'm going to re-open this. We've seen variations on this idea (such as #1154), and I feel like there's a possibility of a solution. That is, there are times when people have a logical stack of elements, but don't necessarily want to inherit the entire stack in their output. Also, there are times when people want to inherit SOME of the stack, but not all of it. I think we can all agree that we don't want messy syntax, but I'd like to see a variety of ideas. As we've explored here, targeting by name seems problematic. But we could also target by level:
Basically, step "up" the inheritance tree to the level we want to inherit / append to the current selectors. Or, something like, maybe "breaking" the inheritance and starting over, without having to move the class outside of the block. I dunno, like:
or, borrowing from the top example:
Both outputting:
Thoughts? |
I like it. I prefer my suggestion of |
One thought.. Matthews solution doesn't allow you to have a mixin (with unknown inheritance) and just work within your current selectors (as in #1158). Is it too complicated to have |
One question: why How would it break mixins? Not understanding that. |
in a selector you have lots of pseudo classes using brackets and then you have variable substitution which borrows its syntax from the more verbose ~"@{var}" so for me normal brackets work better (especially if we should allow |
I'm surprised no one has mentioned how to target specific (immediate) parents when more than one are present. Here's some CSS which I'd like to arrive at: /* regular css */
.foo, .bar {
margin: 0 auto;
line-height: 1.2;
}
.bar {
line-height: 2; /* override */
} Unfortunately, I actually have to write it like that in LESS syntax as well. It'd be nice to target /* LESS css */
.foo, .bar {
margin: 0 auto;
line-height: 1.2;
&(2) {
line-height: 2;
}
} Then the ancestors could be accessed with additional & combinators (I like the "targeting by level" idea): /* LESS css */
.mommy {
.foo, .bar {
margin: 0 auto;
line-height: 1.2;
&(2) {
line-height: 2;
}
/* same results for &&(1) */
&&.mommyClass {
color: #000;
}
}
} |
@Smolations that came up in a different issue. We thought that this might be done using guards on css rulsets combined with being able to test parent selectors in the guard condition. but good to bring it up. |
Ah, I see what you mean. I just didn't see that issue thread because it's subject didn't catch my eye (you wouldn't happen to know where I could find that discussion, would you? =] ). I think that any time you can marry various functionality to a unified syntax, you contribute to the intuitiveness of the final product. Even if I hacked that functionality by using guards, and assuming this thread's idea is implemented in any of the suggested forms, achieving the desired result in my example would require using two separate syntax's. My suggestion tries to use the already-familiar syntax of the ampersand. If my request (the ability to access a specific parent selector) isn't implemented in the future, I'd still like to see a solution to this thread's problem that uses the ampersand because it's already meaningful when accessing the LESS selector family tree. =] |
here #1174 for every feature we like to make sure it has real value-add.. if it makes it easier to not refactor your css to a better structure then it doesn't have value add. if it makes your less harder to understand, thats not good and if it makes less harder to learn, that isn't good either. So, I mostly support the simple functionality in this post (but not enough to make it high priority - unfortunately there are things more important), but I am really wary about how complex it should become. If we combine 2 existing features that have been asked for and as a side product allow you to do what you want to do, without making selectors more complicated, I think thats better unless your use-cases are general enough that special functionality should be added because they have so much value-add. lets see if we can re-write your last example...
and lets say we want to not have to write the
With these examples, its quite easy to understand what the result css will be.. with yours, it isn't, without learning some more.. What we need to convince us of the more complicated parts of this proposal are real use cases that can't be done any other way. |
note - to implement the extend syntax options we will need to add a rule that the basics of the original request.. e.g. to escape the current nesting. We don't have to expose it, but we may as well. Do we really need specific parent targets? For "escaping" I was thinking |
Initially, we considered a lot of syntactic approaches for this feature in Sass but ultimately decided to do something much simpler because the number of use cases was very large: We are exposing For example: .foo, .bar > a { first: nth(&, 1); second-combinator: nth(nth(&,2),2) } would generate: .foo, .bar > a { first: ".foo"; second-combinator: ">"} We will have this feature in Sass 3.3. I suspect we'll also ship with a few standard selector manipulation functions and then wait to see what the community develops before standardizing any more. |
@chriseppstein, nice, I really like the flexibility of that approach. thank you |
@jonschlinkert :) |
@chriseppstein That's pretty cool, I like how |
@matthew-dean are you saying you walk up to the root node (possible with less) and then use a saved selector to ? Your example is not complete as it appears to be taken from a real code source. Not sure what it is supposed to do and generate. In my example, it could target any ancestor selector and then apply a rule from there, so in my example this
is the same as
|
As far as figuring out the code-base, I'd be perfectly willing to tell you what I know / have learned about the code base if you want to take a look. Feel free to DM me on Twitter and I'll see what I can do to help - https://twitter.com/matthewdeaners |
I've updated my example.
Interesting. I'd be curious if someone used the word "stupid". Otherwise, it may be that someone couldn't see the value, and it can be difficult to advocate for your own use cases, especially for a general-purpose library. To be fair, this whole thread was entirely theoretical until I needed this today and there would have been no other way to implement this in an abstracted way. Also, to this:
Note that my use-case doesn't address "inserting" something like a |
"So your use-case may have very well been impossible in Sass, as it is in Less" No it wasn't impossible functionality wise. Sure, i had to add an extension method but it was considered impossible because Less or Sass couldn't look up because it's compiled and doesn't know about it's surroundings (html). It was considered "useless", not beneficial in any way. Well, your coding standards are not good enough I guess. I wasn't talking about walking up the dom tree, but the declared css/less/sass tree. It's really not that complex to understand and my example is simple enough. Do you think it's difficult to understand? Mine basically solves most, if not all of these issues. The idea is that if your styling something, and need to walk up to some ancestor, say for hover or class add, or attribute, or whatever, that code should live in the same location, not have to be declared separately at the ancestor level and repeated all the way down to the same element that needs to be styled. That causes code fragmentation and in the end you have code to style the same elements in several locations. I was advocating a for solution that allowed you to walk up by targeting a certain selector, or walk up N parents. For instance
also works
If my code is to be made public, I want an apology first, because I am still frustrated, mostly because I kept hitting a wall like most here and the lack of this feature has been a major irritant for years because it always led to code getting more complex than it needed as the less/css code in a project grew. Also, you just reopened a closed ticket. Why was it closed? Who the **** decided to close it? I hate Reddit, censorship and people who think they know better or have all of the answers. So for making a question that originated six years ago, if not longer (other previous issues) that was closed down, finally addressed and solved by me without any help to understand that shit code, I want an apology. (<- "Keep dreaming. It's free." - spm). Yes, sound just like Trump. I am fully aware, but then again, this is a rant. |
Speaking of your example at #1075 (comment). |
And it's beatiful code: |
All offtopic is cleared (for those interested I moved all the accusations with my comments here). |
Then that's just someone completely misunderstanding your example. No, your example is simple and I understand what you're going for. It's a similar request to the "capture" and "replace" examples throughout this thread, you're just demonstrating using different syntax. I wonder if the easiest isn't just:
Then you could just do: .grandparent {
.something {
@grandparent-hover: replace(&, '.grandparent', '.grandparent:hover');
^ @{grandparent-hover} {
color: red;
}
}
} It's a few features in one, which is why this thread's discussion has been so complex, because when people raise examples, they're talking about several features for one use case. |
Oops, I had this tab open on my browser and didn't see the vitriolic comments that happened in the interim. |
Or build in replace? ... .grandparent {
.something {
// & currently = .grandparent .something
&:visited {
color: yellow;
}
&(.grandparent; .grandparent:hover) {
// & now = .grandparent:hover .something
color: red;
&:visited {
color: blue;
}
}
}
}
// output CSS
.grandparent .something:visited {
color: yellow;
}
.grandparent:hover .something {
color: red;
}
.grandparent:hover .something:visited {
color: blue;
} Spitballin'... seems more robust and clear than numerical index referencing, which can be ambiguous. Just selector search / replace built into a This still requires the feature additions of:
|
Or explicitly declaring a placeholder within the selector of interest to not make potentially independent code to guess, know or hack specific element name or position (where not necessary). For my taste the Sassish .foo {
@at-root .bar {color: red}
} then in a far away galaxy: .baz {
@import "foo.less"; // oops
} |
That example looks a bit confusing to me, although I think that's essentially "capture" and "replace"? I couldn't tell. Like this but only with explicit names? If that's the case, that's also reasonable to me.
I don't disagree, that's why I wrote a second example that doesn't require it. I don't think it's completely unnecessary, though. I just think it shouldn't be built into a potential solution here. I think "in-place alteration of But, to be clear, as I mentioned above, capture/replace also seems appropriate. @seven-phases-max One thing that might help this thread from just spinning its wheels forever and ever. Of these solutions: a) in-place alteration of |
What's wrong with:
You can do a bunch of other stuff two. |
There's nothing particularly "wrong" with it. In fact, for a while now, Less has allowed functions to be called at practically any node. So you could likely do this as a Less But, as far as syntax, IMO it's not a good fit in the Less language, because there are a few oddities / outliers in that construction, such as wrapping selectors in quotes, and calling a function at the root. Which you CAN do and define functions for that purpose. So if you want to solve this as a plugin, you can do it today, without any Less syntax changes whatsoever. It would be called literally with: @plugin "closest";
.body {
.main {
.section {
.article {
// This will parse, as there's nothing invalid about this syntax
closest(".main", {
&:hover {
background-color: red;
}
&.someclass {
background-color: blue;
}
});
}
}
}
} The only tricky part: whatever selector is returned by |
Exactly. Regarding the quotes not being ideal, I agree with you, however considering the complexity and time it has taken to resolve this issue using other means and the perceived downside of using quotes, I think it is basically a non issue, especially if we want to speed up the adding of such a functionality. Surely it can and should ideally be done prior to the plugin method kicking in (performance being one reason), but this could showcase the desired functionality and pave the way as it is not even clear right now, what the desired functionality should do. There's also a lot of other issues, syntax wise with Less that are far worse. Please contact me on opensource ATTT momomo DOTTT com and we can take it from there. I do not use Twitter unfortunately. |
Per comment here, in discussion about how to "consume" a captured
The tricky thing about that is: is it a modification of selector inheritance for all further children? Or is it just a modification for that particular selector? As in: .component {
&(.foo) .child { // selector is now .foo .child ?
& .grandchild { // is & now .foo .child? Have we altered it permanently? I would presume yes
}
}
} Also, this would prevent things like: .something:not {
&(.selector) {}
} I'm not sure anyone would ever have reason to write that, but it's worth pointing out. |
What about this approach: ^ - back one selector
Source: sass/sass#2193 |
Hi. This mixin's parent selector .with-count(@n, @content) when (@n > 1) {
&:first-child:nth-last-child(@{n}),
&:first-child:nth-last-child(@{n}) ~ & {
@content();
}
} |
I later implemented this myself into the less.js lib but I later on moved on from less to other solutions. Not sass either. I think my syntax was |
@hawkerboy7 I think the reason this mostly didn't go anywhere is that needing to grab just the parent selector often indicates a structural or logic problem in your stylesheet. As in, there are probably other ways to get to the desired output. |
Hi @matthew-dean, Thank you for your answer! |
@matthew-dean I think it is just your mind that has a structural or logical problem thinking that this is the only reason that it wasn't implemented. Like if you can target the nearest parent with & ... why not two parents, or higher ? If the goal is to manipulate an element I am defining stuff for, say for :hover higher up, why should I not define all of its logic in one place. Why force a different way or place of declaring things that affect this particular element. |
When creating a Parent Selector rule, everything before the
&
gets prepended to the outermost scope.The feature could be greatly improved by allowing for "parent targeting", where you could apply the parent selector to a specific parent (in the case where you have deeply nested selectors).
The syntax for this feature is probably the biggest hindrance, so I would love to start a discussion on the possibilities.
The text was updated successfully, but these errors were encountered: