Skip to content
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

Open
scottrippey opened this issue Dec 13, 2012 · 123 comments
Open

Parent Selectors should have targets #1075

scottrippey opened this issue Dec 13, 2012 · 123 comments

Comments

@scottrippey
Copy link

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.

@scottrippey
Copy link
Author

Example usage:

.main-content {
    .button {
        .button-icon {
            background-image: @button-icon;
            (.button):hover { background-image: @button-icon-hover; }
            (.button).focus { background-image: @button-icon-focus; }
            .ie8 (.main-content) { background-image: @button-icon-ie8; }
        }
    }
}

This may be a contrived example, but I have several real-world scenarios where such a syntax would be a life saver.

@matthew-dean
Copy link
Member

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 & is not really a parent selector in the CSS4 sense of the term. It literally just appends the inherited selectors to wherever you place them.

@matthew-dean
Copy link
Member

I usually just end up writing these code blocks like this:

.main-content {
    .ie8 & { background-image: @button-icon-ie8; }
    .button {
        &:hover { background-image: @button-icon-hover; }
        &.focus { background-image: @button-icon-focus; }
        .button-icon {
            background-image: @button-icon;
        }
    }
}

@scottrippey
Copy link
Author

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.
FYI, in your example, the background-image needs to be applied to the .button-icon, so you'd have way more duplication.

@scottrippey
Copy link
Author

Can you explain "assign variables and use those as part of selector chains"?

@matthew-dean
Copy link
Member

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?

.button {
.main-content {
    .button {
        .main-content {
            .button-icon {
                background-image: @button-icon;
                (.button):hover { background-image: @button-icon-hover; }
                (.button).focus { background-image: @button-icon-focus; }
                .ie8 (.main-content) { background-image: @button-icon-ie8; }
            }
        }
    }
}
}

It's messy CSS, but it's perfectly valid CSS.

@scottrippey
Copy link
Author

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.

@scottrippey
Copy link
Author

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 /\([^()@]\)/ which means it's already being parsed correctly. I don't know if these parenthesis are valid.

I just realized that the parenthesis syntax looks almost exactly like a mixin definition ... with the exception of the class dot .. So maybe it's not a good idea. Feedback?

@lukeapage
Copy link
Member

Your use case sounds like what is discussed in #965 .. what do you think?

Bearing in mind & is quite powerful already and we are bringing in :extend() in 1.4.0, it seems to me if the only thing missing is being able to call a mixin that adds selectors to your selector chain, then if we decide to add that functionality it should be as simple as possible.. the more we add to selectors, the more complicate less gets to learn and understand.

@matthew-dean
Copy link
Member

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.

@scottrippey
Copy link
Author

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.

@matthew-dean
Copy link
Member

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:

.main-content {
    .button {
        .button-icon {
            background-image: @button-icon;
            &{2}:hover { background-image: @button-icon-hover; }
            &{2}.focus { background-image: @button-icon-focus; }
            .ie8 &{3} { background-image: @button-icon-ie8; }  // In this case, &{3} is the same as & because it goes to top
        }
    }
}

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:

.grandparent {
  .parent {
    /.child {   // Ordered logically, but outputs cleaner CSS
      background: white;
    }
  }
  background: blue;
}

or, borrowing from the top example:

.grandparent {
  .parent {
    &{0}.child {   // inherit NONE of the parents
      background: white;
    }
  }
  background: blue;
}

Both outputting:

.grandparent {
  background: blue;
}
.child {
  background: white;
}

Thoughts?

@lukeapage
Copy link
Member

I like it. I prefer my suggestion of &1 or @Soviut &(1). I think probably that is my current winner.

@lukeapage
Copy link
Member

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 &(2..n) .var &(1) ? or could you do & .var &(1) and the first & would be all the selectors not chosen already. alternatively should it default to putting the selector parts you don't use at the begining unless you use \ ?

@matthew-dean
Copy link
Member

One question: why &(1) and not &{1}? The latter is similar to inline variable syntax, whereas parentheses feels kind of like a math operation. Or a mixin, and it's not similar to either. It's more like a reference.

How would it break mixins? Not understanding that.

@lukeapage
Copy link
Member

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 &(2..n)).. but having said that I don't have a strong preference between ( and {.. I'm more interested in the above.. how to step up 1 inheritance level verus breaking out of the current selector.

@Smolations
Copy link

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 .bar within the first block. Perhaps something like:

/* 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;
        }
    }
}

@lukeapage
Copy link
Member

@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.

@Smolations
Copy link

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. =]

@lukeapage
Copy link
Member

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...

.mommy {
   .foo, .bar {
       margin: 0 auto;
       line-height: 1.2;
   }
   .bar {
       line-height: 2;
   }
   .mommyClass {
       color: #000;
   }
}

and lets say we want to not have to write the .bar selector twice..

.mommy {
   .foo {
       margin: 0 auto;
       line-height: 1.2;
   }
   .bar:extend(.mommy .foo) {
       line-height: 2;
   }
   .mommyClass {
       color: #000;
   }
}

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.

@lukeapage
Copy link
Member

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 >| or something like that.. but yes, if we do need specific parent selectors &(0) to escape and the rest to target a specific nesting level seem to make some sense.

@chriseppstein
Copy link

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 & to SassScript as a comma separated list of space separated values. Then all of the manipulation of the selectors can be done in "user space" by simply manipulating selectors with Sass functions.

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.

@jonschlinkert
Copy link
Contributor

@chriseppstein, nice, I really like the flexibility of that approach. thank you

@chriseppstein
Copy link

@jonschlinkert :) & is a feature that Less adopted from Sass; I think the dev community is best served if they both continue to work similarly.

@scottrippey
Copy link
Author

@chriseppstein That's pretty cool, I like how & acts like a variable, on which you can perform funcitons. Makes this concept much easier to understand and read.

@momomo
Copy link

momomo commented Jun 11, 2018

@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

.grandparent {
       .something {
              closest('.grandparent', { &:hover { color:red: } })
      }
}

is the same as

.grandparent { &:hover { .something { color:red; } } }

@matthew-dean
Copy link
Member

matthew-dean commented Jun 11, 2018

@momomo

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

@matthew-dean
Copy link
Member

@momomo

Your example is not complete

I've updated my example.

the question was considered stupid, censored and closed down

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:

Even the Sass guys said it was impossible.

Note that my use-case doesn't address "inserting" something like a :hover within a parent (inherited) selector. So your use-case may have very well been impossible in Sass, as it is in Less. So my example was just posted to illustrate that SOME use cases could be solved, but doesn't solve all, including some earlier ones I posted.

@momomo
Copy link

momomo commented Jun 11, 2018

"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

closest(3, { :hover { walks up three parents } }

also works

closest(1, { :hover { walk up one parent } } which is the same as &{ :hover { walk up one parent }}

closest('.someAncestorVeryHighUp', { :hover { walks up all the way up to that class } })

closest('[attribute=valueAlsoWorks]', { :hover { walks up all the way up to that attribute val match } })

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.

@seven-phases-max
Copy link
Member

seven-phases-max commented Jun 12, 2018

@matthew-dean

Speaking of your example at #1075 (comment).
We even have a working plugin prototype for this: #2619 (comment)
(also at https://github.com/seven-phases-max/less-plugin-reflections).
The only problem is that (even if the plugin works as you expect) there's some theoretical trickery from the language point of view: because of lazy-evaluation the value of @grandparent is not supposed to be "frozen" at the @grandparent: &; line (i.e. unless there's some specific syntax and/or some specific function to force its evaluation, the LE-principle dictates @{grandparent}:hover & to be expanded to the same &:hover & thing). I.e. we can't really save that value just like this: @grandparent: &; - more research needed.

@momomo
Copy link

momomo commented Jun 12, 2018

And it's beatiful code:

https://imgur.com/a/RWCEYtB

@less less deleted a comment from momomo Jun 13, 2018
@less less deleted a comment from momomo Jun 13, 2018
@less less deleted a comment from krnlde Jun 13, 2018
@less less deleted a comment from momomo Jun 13, 2018
@less less deleted a comment from momomo Jun 13, 2018
@less less deleted a comment from krnlde Jun 13, 2018
@less less deleted a comment from momomo Jun 13, 2018
@seven-phases-max
Copy link
Member

All offtopic is cleared (for those interested I moved all the accusations with my comments here).

@matthew-dean
Copy link
Member

No it wasn't impossible functionality wise. Sure, i had to add an extension method but it was considered impossible because less couldn't look up because it's compiled and doesn't know about it's surroundings (html).

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:

  1. Allowing assigning & to a variable, or as a param to a function.
  2. Using the replace function.
  3. Adding an "at-root" type selector (^?)

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.

@matthew-dean
Copy link
Member

matthew-dean commented Jun 15, 2018

Oops, I had this tab open on my browser and didn't see the vitriolic comments that happened in the interim.

@matthew-dean
Copy link
Member

matthew-dean commented Jun 15, 2018

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 &() function.... one downside is we may want other "& alteration" extensions in the future?

This still requires the feature additions of:

  1. Passing selectors to functions.
  2. & as a function

@seven-phases-max
Copy link
Member

seven-phases-max commented Jun 15, 2018

Or build in replace? ...

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 @at-root thing has typical hardcoded backdoor problem (of being easily broken):

.foo {
   @at-root .bar {color: red}
}

then in a far away galaxy:

.baz {
    @import "foo.less"; // oops
}

@matthew-dean
Copy link
Member

matthew-dean commented Jun 15, 2018

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).

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.

For my taste the Sassish @at-root thing has typical hardcoded backdoor problem (of being easily broken):

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 & inheritance" is probably better (than something using an @at-root-like solution).

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 &, b) capture/replace, c) other - Do you have a preference? Because part of the wheel-spinning is literally approach, not just syntax. If there was some consensus on approach, syntax might eventually gel here.

@momomo
Copy link

momomo commented Jun 15, 2018

What's wrong with:

css  = '' +
'.body {  ' +
                                
        '.main { ' +
                                
            '.section {' +
                                
                '.article {' +
                        // --- Call made here! ---
                                
                        // Climb up to .main, and then add the selectors inside the body below
                        'closest(".main", {' +
                                
                            '&:hover {' +
                                'background-color:red;' +   // Meaning that when you hover .main then .article will get background-color:red;
                            '}' +
                                
                            '&.someclass {' +
                                'background-color:blue;' +   // Meaning that when .someclass is added to .main then .article will get background-color:blue;
                            '}' +
                                
                        '})' +
                                
                        // Do note that purpose of climbing up is to style article, nothing else.
                                
                    '}' +
                                
                '}' +
        '}' +
'}';
                                
less.render( css ,function (error, output) {
        console.log('xxx');  console.log(output.css);
});

You can do a bunch of other stuff two.

@matthew-dean
Copy link
Member

matthew-dean commented Jun 16, 2018

@momomo

What's wrong with:

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 @plugin. I wonder if that's not the best way to resolve this.

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 closest() will still have all the same merging rules applied. I still think that a plugin could manage to give the desired behavior.

@momomo
Copy link

momomo commented Jun 16, 2018

@matthew-dean

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.

@matthew-dean
Copy link
Member

Per comment here, in discussion about how to "consume" a captured & selector, there was discussion about replacing & in-place, which then lead back to this issue. Since this is more in line, I thought I'd continue that here of what was being discussed, which was similar to what I mentioned at #1075 (comment)

  • &() - return in-place &
  • &(arg) - replace & with arg and return
  • &(arg1, arg2) - replace arg1 in & with arg2 and return as new &

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.

@sorcamarian
Copy link

What about this approach:

^ - back one selector
^(x) - back x selectors
(sign: "^" is inspired from: http://docs.emmet.io/ )

#wrapper {
  .row {

   .text-side {
      h2{
        color : #000;
        }// h2
      .text-description{
          p{
            color : #333;
            mark{
              background-color: green;
              } // mark
            } // p
        } // .text-description  
    }

    ^ .image-side {
   // avoid 1 selectors: .row
      .image-block {
        ^(2) img{
        // avoid 2 selectors: .image-block .image-side
          width: 100%;
          } // img
        } // .image-block
      } // .image-side

  }// . row
} // #wrapper

Source: sass/sass#2193

@hawkerboy7
Copy link

hawkerboy7 commented Oct 27, 2023

Hi.
After about 5 years of no update on this issue, is there a solution for this ability to select / restrict the parent selector, that might not yet have been added in this issue?
I've asked a question in discussions about this behaviour as well.

This mixin's parent selector ~ & will select the whole tree up (which makes sense) though it should only (in this case) select its nearest ancestor for this :first-child:nth-last-child trick to style children (/siblings) based on children count.

.with-count(@n, @content) when (@n > 1) {
	&:first-child:nth-last-child(@{n}),
	&:first-child:nth-last-child(@{n}) ~ & {
		@content();
	}
}

@momomo
Copy link

momomo commented Nov 12, 2023

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 closest(.parentclass) { &.something { ... } }

@matthew-dean
Copy link
Member

@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.

@hawkerboy7
Copy link

hawkerboy7 commented Nov 13, 2023

Hi @matthew-dean,

Thank you for your answer!
How would you structurally or logically resolve this situation?
To me this seems to be a very normal and regularly used way of selecting.
I am here to learn :)

@momomo
Copy link

momomo commented Nov 13, 2023

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests