Reputation: 1019
Is there anyway to write the following code without the individual blocks for each parent?
#parent1
{
#parent1child1
{
display: none;
}
}
#parent2
{
margin-top: 1em;
margin-bottom: 1em;
}
#parent1, #parent2
{
.child2
{
display: none;
margin-top: 1em;
.textbox
{
width: 97%;
}
.anchor
{
margin-right: 0.5em;
}
}
}
I'm trying to remove the need to have the blocks for each parent and use some sort of not operator within the overall block to style individual parents.
Upvotes: 2
Views: 112
Reputation: 72271
As you can tell from my comments under onetrickpony's answer, I do not find that solution acceptable at all (even though as of the initial writing of this it was the "accepted" answer). While it was a somewhat creative solution to get it "working," the production of pointless selectors like #parent2#parent1 #parent1child1
that it produces, and the annoying redundancy of the #parent2#parent2
selector it makes seems too lackadaisical and uncaring about proper coding. Whether onetrickpony has such an attitude is unclear, though seems further evidenced by his comment that "The point of using a CSS preprocessor is to save some development time, not to generate efficient CSS." In my opinon, both should be the goal. Here is the specific output of his solution and what I find unacceptable:
CSS Output of onetrickpony's nested parent calls using &
with my objections noted
#parent1#parent2, /* <- pointless selector */
#parent2#parent2 { /* <- ugly and redundant (potentially buggy?) selector */
margin-top: 1em;
margin-bottom: 1em;
}
#parent1#parent1 #parent1child1, /* <- ugly and redundant selector */
#parent2#parent1 #parent1child1 { /* <- pointless selector */
display: none;
}
#parent1 .child2,
#parent2 .child2 {
display: none;
margin-top: 1em;
}
#parent1 .child2 .textbox,
#parent2 .child2 .textbox {
width: 97%;
}
#parent1 .child2 .anchor,
#parent2 .child2 .anchor {
margin-right: 0.5em;
}
It's not very helpful to just criticize, so I felt it necessary to at least offer a solution to the issue besides just critiquing an existing answer given for it. My answer would have come sooner if the site I use to test LESS with had not been down.
Your title to the question asks something slightly different than the stated requirements within the question. The title states: "Maintain individual parent styling whilst including child in multiple parents," which implies an inclusion of the child code in the individual parent styling (while not having to reduplicate code). For this, see Solution #2 below. Your requirements in the question restated it differently, "Is there anyway to write the following code without the individual blocks for each parent," which narrows the requirements of the title to a specific solution of defining everything in one code block (which I believe is a poor coding practice, as it becomes far less clear what is happening... and onetrickpony noted the OP's original code was more clear than the solution he was offering). To actually achieve a parent grouping in the CSS while keeping code clarity and shortness in the LESS, see Solutions #3a and #3b.
However, I'm going to start with Solution #1, which first is to step back and reexamine whether or not a nesting is even needed. Only the OP can determine that based off his site requirements, but if it is not necessary, then Solution #1 is best--everything is kept separate. If nesting is needed, Solution #3b is probably closest to what the OP desires.
This just points out the obvious that many times people design for nesting when nesting is not needed. If not .child2
elements exist outside of a #parent1
or #parent2
wrapper, then there is normally no need to have the css with the nested relationship. The exception to this would be for a specificity override because the .child2
has other styles applying that need to be overridden, and so it needs the added specificity of the id from the parent.
#parent1 {
#parent1child1 {
display: none;
}
}
#parent2 {
margin-top: 1em;
margin-bottom: 1em;
}
.child2 {
display: none;
margin-top: 1em;
.textbox {
width: 97%;
}
.anchor {
margin-right: 0.5em;
}
}
This keeps the parents separate, which keeps the clarity of what is clearly expected to be two different sets of styling rules for them. It uses a mixin to keep the .child2
code as only having to be entered once. This is more how LESS is designed to work for including repeated code in selectors.
#parent1 {
#parent1child1 {
display: none;
}
.makeChild2Code(); /* call mixin to generate code */
}
#parent2 {
margin-top: 1em;
margin-bottom: 1em;
.makeChild2Code(); /* call mixin to generate code */
}
.makeChild2Code() {
.child2 {
display: none;
margin-top: 1em;
.textbox {
width: 97%;
}
.anchor {
margin-right: 0.5em;
}
}
}
This solution will result in some excess CSS code "bloat," but the difference here from onetrickpony's answer is that the code bloat has purpose and meaning rather than being pointless and unmeaningful. The resulting CSS is:
#parent1 #parent1child1 {
display: none;
}
#parent1 .child2 {
display: none;
margin-top: 1em;
}
#parent1 .child2 .textbox {
width: 97%;
}
#parent1 .child2 .anchor {
margin-right: 0.5em;
}
#parent2 {
margin-top: 1em;
margin-bottom: 1em;
}
#parent2 .child2 {
display: none;
margin-top: 1em;
}
#parent2 .child2 .textbox {
width: 97%;
}
#parent2 .child2 .anchor {
margin-right: 0.5em;
}
Both of these use the functionality of :extend()
found in LESS 1.4+ to group the parents together. This is also how the latest version of LESS is intended to be used for such a situation.
Opt "a"
This uses the fact that #parent1child1
should be unique to the page and thus does not need to reside under #parent1
in most cases (however, there are occasionally legitimate cases for such nesting of id's). It also assumes that #parent1
does not have any other properties that need to be applied to it that do not also apply to #parent2
.
#parent1 {
.child2 {
display: none;
margin-top: 1em;
.textbox {
width: 97%;
}
.anchor {
margin-right: 0.5em;
}
}
}
#parent1child1 {
display: none;
}
#parent2 {
margin-top: 1em;
margin-bottom: 1em;
&:extend(#parent1 all); /* this causes the #parent1 selector to become
#parent1, #parent2 in the output css, thus
making the connection to .child2 */
}
This produces grouped CSS for the parent with .child2
relation:
#parent1 .child2,
#parent2 .child2 {
display: none;
margin-top: 1em;
}
#parent1 .child2 .textbox,
#parent2 .child2 .textbox {
width: 97%;
}
#parent1 .child2 .anchor,
#parent2 .child2 .anchor {
margin-right: 0.5em;
}
#parent1child1 {
display: none;
}
#parent2 {
margin-top: 1em;
margin-bottom: 1em;
}
Opt "b"
This is probably the best solution for grouping and code clarity/conciseness in the LESS, and keeps the nesting of the id's as the OP originally had and also allows for #parent1 to have its own properties if needed:
#parent1 {
#parent1child1 {
display: none;
}
.child2 { /* define child element first in #parent1 */
display: none;
margin-top: 1em;
.textbox {
width: 97%;
}
.anchor {
margin-right: 0.5em;
}
}
}
#parent2 {
margin-top: 1em;
margin-bottom: 1em;
.child2 {&:extend(#parent1 .child2 all);} /* extend child def for #parent2 */
}
This produces this CSS with parents nicely grouped as well:
#parent1 #parent1child1 {
display: none;
}
#parent1 .child2,
#parent2 .child2 {
display: none;
margin-top: 1em;
}
#parent1 .child2 .textbox,
#parent2 .child2 .textbox {
width: 97%;
}
#parent1 .child2 .anchor,
#parent2 .child2 .anchor {
margin-right: 0.5em;
}
#parent2 {
margin-top: 1em;
margin-bottom: 1em;
}
This could be reversed (the #parent2
could contain the .child2
definition, and the #parent1
extended into it, which would place all the combined code following #parent2
).
Summary: Solutions #1 or #3b are likely best for what I imagine the OP's actual needs may be.
Upvotes: 3
Reputation: 16719
I guess you could use the parent combinator (&
) and select #parent2
in your second block:
#parent1, #parent2
{
&#parent2{ /* <- styles applied to #parent2 only */
margin-top: 1em;
margin-bottom: 1em;
}
&#parent1 #parent1child1 /* note: IDs are supposed to be unique, */
{ /* so just select #parent1child1 */
display: none;
}
.child2
{
display: none;
margin-top: 1em;
.textbox
{
width: 97%;
}
.anchor
{
margin-right: 0.5em;
}
}
}
But I think your original code is more clear.
Upvotes: 1