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

[css-nesting]The parent selector should not be placed inside the subselector #2909

Closed
wangmeijian opened this issue Jul 12, 2018 · 12 comments
Closed

Comments

@wangmeijian
Copy link

About The Nesting At-Rule: @nest

.foo {
  color: red;
  @nest .parent & {
    color: blue;
  }
}
/* equivalent to
   .foo { color: red; }
   .parent .foo { color: blue; }
 */

if .parent have three child selectors ".foo",".foo2",".foo3",I must write "@nest .parent &" in every child selectors,this is very tedious

@tabatkins
Copy link
Member

tabatkins commented Jul 16, 2018

Yes? That is indeed what you must do. What do you think it should look like instead?

@tabatkins tabatkins added the css-nesting-1 Current Work label Jul 16, 2018
@wangmeijian
Copy link
Author

@nest .parent {
	.foo {
	  color: red;
	}
	.foo2 {
	  color: yellow;
	}	
	.foo3 {
	  color: blue;
	}
}

like less, I just write .parent once @tabatkins

@tabatkins
Copy link
Member

I'm not sure I understand. That seems like ordinary nesting, which you can do with just:

.parent {
  & .foo { color: red; }
  & .foo2 { color: yellow; }
  & .foo3 { color: blue; }
}

The only reason you'd need to use @nest is if you wanted to put the .parent-based styling inside of the foo/foo2/foo3 blocks, like:

.foo {
  ...
  @nest .parent & { color: red; }
}
.foo2 {
  ...
  @nest .parent & { color: yellow; }
}
.foo3 {
  ...
  @nest .parent & { color: blue; }
}

If that's the style you want, to keep all of the .foo styles together and separate from the .foo2 or .foo3 styles, then yes, you'd have to write that .parent & selector a few times.

But your proposal doesn't seem to do anything about that, so I'm not sure I understand what you're trying to propose.

@matthew-dean
Copy link

matthew-dean commented Jul 20, 2018

@tabatkins

With your proposal, can someone write:

.foo {
  @nest .parent & {
    & .foo1 { color: red; }
    & .foo2 { color: yellow; }
    & .foo3 { color: blue; }
  }
}

Just curious. (Maybe that addresses the OP's question?)

@tabatkins
Copy link
Member

Yeah, sure.

@flavi1
Copy link

flavi1 commented Jan 27, 2019

(Not sure if i post it in the good place. And sorry for my poor english)

It maybe less powerfull than your proposal.
I just discovered the "nest" proposal.
And i probably don't have all optimisation in mind too.
But i trust it could be more simple and easy to maintain if we just have something like that (at least in a first time).
(idea from https://github.com/flavi1/lcss)

@(body aside.left, body aside.right ) {
  . {      /* point should mean "current selector full path itself" */
    color:red;
  }
  span.my-sub-span {
    color red
  }
}

equal this

 body aside.left,   body aside.right {
    color:red;
}

 body aside.left span.my-sub-span,   body aside.right  span.my-sub-span {
    color red
}

Example

This :

@(#parent1) {
  @(.sub1.myClass > span, .sub2.active) {
    body { color: #888; }
    @media print {
      body { color: #333; }
    }
  }
  @(.sub3) {
    code { color: red; }
  }
  code { color: blue; }
}

@(#parent) {
  .sous-style {
    display: none;
  }
}

equivalent to :

#parent1 .sub1.myClass > span body, #parent1  .sub2.active body {
 color: #888; 
}

@media print {
#parent1 .sub1.myClass > span body, #parent1  .sub2.active body {
 color: #333; 
}


}

#parent1 .sub3 code {
 color: red; 
}

#parent1 code {
 color: blue; 
}

#parent .sous-style {
    display: none;
}

Think about playing with

  • css files importations "@import"
  • default variables value "var(--my-var, defalut_val)"
  • and assignement in a highter level "--my-var: assigned_val;"
    And imagine all you can do with it...

https://github.com/flavi1/lcss

@tabatkins
Copy link
Member

@(body aside.left, body aside.right ) {
  . {      /* point should mean "current selector full path itself" */
    color:red;
  }
  span.my-sub-span {
    color red
  }
}

You can already write this in my proposal as:

body aside.left, body aside.right {
  & {
    color: red;
  }
  & span.my-sub-span {
    color: red;
  }
}

Your second example can also be written in my proposal just fine. (I'm not going to show it rewritten, because it's long and doesn't demonstrate anything new, just more nesting.) The only exception is that @media can't be nested into style rules yet, but that's a separate proposal.

@flavi1
Copy link

flavi1 commented Jan 28, 2019

Ok...
But what's about @import? One of my goals is to have classic css children files (without the need of the "&" symbol)
Our proposals are they incompatibles or complementary?

@flavi1
Copy link

flavi1 commented Jan 28, 2019

I understand.
For a lot of reason your's is realy more powerfull that mine. I totaly agree.
Now i will try to describe clearly my motivation, starting with your proposal : I'm interesting about a way to silently have the '& ' prefix on children element. For example.

body aside.left, body aside.right {
  & {
    color: red;
  }
  & span.my-sub-span {
    color: red;
  }
  html.no-js & {
    color: green;
  }
}

As an extension of your proposal, i propose an equivalent:

@nest("^= *") body aside.left, body aside.right {
  color: red;
  
  span.my-sub-span {
    color: red;
  }
  html.no-js & {
    color: green;
  }
}

(note the '&' after html.no-js)
The idea is that @nest("^= *") indicate the default placement of "&" if no present.
'&' becomes facultative. Then if I have a form.css file (without any "&")

...
input[type=checkbox]:checked ~ label:before {
    content: "[X]";
    background-color: var(--input-bg-color, white);
}
input[type=radio]:checked ~ label:before {
    content: "(*)";
}
...

Considere a second file "specific-website.css"

...
@nest("^= *") form.suscribe {

    /* css variables as unobstrusives parameters */
    --input-bg-color: gray;

    @import(form.css);

    /*Some overides*/
    input[type=checkbox] ~ label {
        font-family: monospace;
    }
}
...

And in another project, form.css can be directly included in a link html tag since it can, but does not have '&' inner, it does'nt need a "nested context" to be used.

We can have "start with" @nest("^= "), "ends with" @nest("=^ "), @nest("^="), or @nest("=^").
(Note spaces are absents for the two last that means "&.my-class" )

@tabatkins
Copy link
Member

I'm interesting about a way to silently have the '& ' prefix on children element.

Unfortunately this isn't possible, for reasons explained in the Nesting proposal; selectors and declarations have overlapping grammars and can't be told apart with any finite number of tokens; you have to look forward an unbounded amount before you can be sure in all cases whether you're looking at a selector or a declaration. In particular, seeing something like color:blue might be the color property, or it might be a <color> element selector with a :blue pseudoclass selector; you can't tell which it is until you get to a { (indicating it was a selector) or a ; (indicating it was a declaration).

Requiring the & in front (or @nest) solves this, as it means you can tell immediately that you're in a nesting-rule situation, rather than a declaration.

Additionally, the & is useful to have because it clarifies your intent. There's a huge difference between .foo :hover and .foo:hover, but in .foo { :hover {...}} it's not immediately clear which one you intended. With & you instead have either & :hover or &:hover on the inner rule, and it's immediately obvious. So even if there weren't any parsing issues, I'd still want to require an & in the selector.

[idea about @import]

Currently, @import can't even be placed between rules, let alone within them; all @import rules have to be at the very beginning of the document. This greatly simplifies implementation, as it means you don't have to track specificity across stylesheets; all imported sheets just come before the sheet that imports them, identical to just having multiple <link> elements in order.

So, it's unlikely that @import will be changed in this way. If it ever does, it'll be a separate proposal that relaxes the @import restrictions in general, allowing it to show up between rules as well.

@flavi1
Copy link

flavi1 commented Jan 28, 2019

Okay!...

I think the root problem is older. Honestly i doesn't agree with the confusion between style blocks space and selector definition space introduced by actual preprocessors. I think that increase sementic and structure dependencies between css and html. Then i think preprocessors functions are not bad, but in this context appears like the antidote of its own poison... But it's another discussion. And if people wants it, i will need to deal with :)

Never mind. I will keep my started idea as a separate preprocessor css-compatible

So, it's unlikely that @import will be changed in this way. If it ever does, it'll be a separate proposal that relaxes the @import restrictions in general, allowing it to show up between rules as well.

If it happens one day, it should be better to call it "@include" to avoid possible confusion and respect retro-compatibility... Then i will add "@include" in my preprocessor. Thanks for this note!

@tabatkins
Copy link
Member

Closing, since the requests in the thread are already possible, and the one wrinkle about the limitations of nesting syntax are now moot since we changed how we parse nested rules.

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

4 participants