CSS :not() selector. Apply style if parent does not exist - css

I am trying to apply a style to a div based on its parent class. I am using the :not() selector to select the div whose parent is not .container1, the second div should be red, but it's not working.
Example 1
.myDiv:not(.container1) > .myDiv {
color: red;
}
<div class="container1">
<div class="myDiv">Div 1</div>
</div>
<div class="container2">
<div class="myDiv">Div 2</div>
</div>
Example 2
.myDiv:not(.container1 .myDiv) {
color: red;
}
<div class="container1">
<div class="myDiv">Div 1</div>
</div>
<div class="container2">
<div class="myDiv">Div 2</div>
</div>
Is this even possible with CSS? Or is my syntax just off?

You're selecting wrong elements. No reverse lookups possible, see here:
div:not(.container1) > .myDiv {
color: red;
}
<div class="container1">
<div class="myDiv">Div 1</div>
</div>
<div class="container2">
<div class="myDiv">Div 2</div>
</div>
Ideally, you'd group those parent divs under the same class in order to avoid the super-generic div selector:
.container:not(.container1) > .myDiv {
color: red;
}
<div class="container container1">
<div class="myDiv">Div 1</div>
</div>
<div class="container container2">
<div class="myDiv">Div 2</div>
</div>

CSS can't do "parent lookups" like that. You would need to reverse the structure to something like:
.my-container:not(.container1) .myDiv
Granted, you would need to add the shared my-container class to all "parent" divs of interest.

Related

css/sass :not(:first-of-type) not working, is hiding all elements of type

I have a sass block that i have tried several different ways:
I've tried this:
.progress-body {
display: none;
&:first-of-type {
display: block;
}
}
and this:
.progress-body {
&:not(:first-of-type) {
display: none;
}
}
and this:
.progress-body:not(:first-of-type) {
display: none;
}
when applied to HTML that looks like this:
<div class="panel">
<div class="panel-heading">
</div>
<div class="panel-body progress-body">
<div class="row">
<div class="col-md-12">
<p class="lead">Step 1: Choose your template...</p>
</div>
</div>
</div>
<div class="panel-body progress-body">
<div class="row">
<div class="col-md-12">
<p class="lead">Step 2: Compose your email...</p>
</div>
</div>
</div>
</div>
the result is that it hides all the elements with the progress-body class. This is normally pretty straight forward CSS so no idea what is wrong here...
In this case progress-body is not the first-of-type, this would technically be .panel-heading since the first-of-type refers to the type element selector (div) and not the class.
The :first-of-type CSS pseudo-class represents the first element of
its type among a group of sibling elements.
Ref: :first-of-type - CSS | MDN
Consider wrapping your .progress-body elements in a containing element, you will achieve the expected behaviour, since .progress-body would be the first of its type with the class name .progress-body.
Code Snippet Demonstration:
.progress-body:not(:first-of-type) {
display: none;
}
<div class="panel">
<div class="panel-heading">
</div>
<div class="panel-outer-body">
<div class="panel-body progress-body">
<div class="row">
<div class="col-md-12">
<p class="lead">Step 1: Choose your template...</p>
</div>
</div>
</div>
<div class="panel-body progress-body">
<div class="row">
<div class="col-md-12">
<p class="lead">Step 2: Compose your email...</p>
</div>
</div>
</div>
</div>
</div>
If you can't wrap as UncaughtTypeError wrote in his answer, youcan use (general) sibling selectors.
.progress-body + .progress-body {display: none;}
or
.progress-body ~ .progress-body {display: none;}
I expect the first is block by default, if you didn't change it elsewhere.

Select the parent class within same class names

If i use "nth-of-type(1)" selector, its select all of them. How can i select only parent div ?
Thanks
<div class="parent_div">
<div class="parent_div"></div>
<div class="parent_div"></div>
<div class="parent_div"></div>
</div>
You should include directive parent container into your selector and use direct child selector >:
.container > .parent_div:nth-of-type(1) {
border: 1px red solid;
}
<div class="container">
<div class="parent_div">
<div class="parent_div"></div>
<div class="parent_div"></div>
<div class="parent_div"></div>
</div>
</div>

Target the first element only if it has other siblings

Without adding any classes (or touching the HTML) is there a way to target the first element inside a div ONLY if there is a second element in that div? Below is my HTML:
<div class="grid">
<div class="content">I WANT TO APPLY CSS TO THIS</div>
<div class="content">But only if there is 2nd .content element in the same parent element</div>
</div>
<div class="grid">
<div class="content">Don't apply here</div>
</div>
<div class="grid">
<div class="content">Don't apply here</div>
</div>
<div class="grid">
<div class="content">I WANT TO APPLY CSS TO THIS</div>
<div class="content">But only if there is 2nd .content element in the same parent element</div>
</div>
A few context to this for a better picture ... I want to center the .content if it's the only .content inside .grid. But if there are two .content divs, then I want them to float next to each other.
Note:
I already know I can target the second .content by
.grid .content:nth-child(2) { ... }
.grid > .content:first-child:not(:only-child) {
color: blue;
}
<div class="grid">
<div class="content">I WANT TO APPLY CSS TO THIS</div>
<div class="content">But only if there is 2nd .content element in the same parent element</div>
</div>
<div class="grid">
<div class="content">Don't apply here</div>
</div>
<div class="grid">
<div class="content">Don't apply here</div>
</div>
<div class="grid">
<div class="content">I WANT TO APPLY CSS TO THIS</div>
<div class="content">But only if there is 2nd .content element in the same parent element</div>
</div>
:first-child:not(:only-child) would be your selector.

Select all but first element using CSS3

I need to select all headers but the first
<div class="block">
<div class="header">first</div>
</div>
<div class="block">
<div class="header">second</div>
</div>
<div class="block">
<div class="header">third</div>
</div>
<div class="block">
<div class="header">fourth</div>
</div>
Using jquery I would do this $(".header:not(:first)"), I'm however restricted to CSS/CSS3. I cannot tag the elements other than in my example.
Using .header:not(:first-child) wont do the trick
The .header elements are not siblings, therefore you should probably select all but the first .block element, then select the descendant .header from there:
.block:not(:first-child) .header {}
Depending on your markup, you may also want to negate the first of type if the element's types differ:
.block:not(:first-of-type) .header {}
.block:not(:first-child) .header {
color: #f00;
}
<div class="block">
<div class="header">first</div>
</div>
<div class="block">
<div class="header">second</div>
</div>
<div class="block">
<div class="header">third</div>
</div>
<div class="block">
<div class="header">fourth</div>
</div>
As David Thomas points out, you can also use the adjacent sibling combinator, + or the general sibling combinator, ~ in order to select all following siblings:
.block ~ .block .header {}
or:
.block + .block .header {}
.block + .block .header {
color: #f00;
}
<div class="block">
<div class="header">first</div>
</div>
<div class="block">
<div class="header">second</div>
</div>
<div class="block">
<div class="header">third</div>
</div>
<div class="block">
<div class="header">fourth</div>
</div>

CSS general sibling combinator (ie ~)

I am trying to understand why the following example does not behave as expected. I have a style that selects general siblings, but I also have children which I would not expect to be selected, but occasionally are. Here is a minimal example that illustrates the problem.
The first div>div.h is a descendant, and the ~ does NOT match it. The second p>div.h is clearly a descendant, but the ~ selector DOES match it. I tried in Chrome,Safari and Firefox, all behave the same. I must be missing something. Is p "special"?
<html>
<head>
<style>
.anchor ~ .h { color: orange }
.anchor2 ~ .h { color: blue }
</style>
</head>
<body>
<div>
<div class="h">black 1</div>
<div class="h">black 2</div>
<p class="anchor">the anchor</p>
<div class="h">orange 1</div>
<div>
<div class="h">should be black</div>
</div>
<p>
<div class="h">why isn't this black</div>
</p>
<div class="h">orange 2</div>
<p class="anchor2">anchor2</p>
<div class="h">blue 1</div>
<div class="h">blue 2</div>
</div>
</body>
</html>
<div> elements are not valid children of <p>.
Your browser corrects your errors (takes your <div> and places it after <p> instead of inside it) and by doing so, makes div.h a sibling of .anchor:
Now, if you use inline elements in your paragraphs, the browser doesn't correct your markup and you get your expected result:
.anchor ~ .h {
color: orange
}
.anchor2 ~ .h {
color: blue
}
<div>
<div class="h">black 1</div>
<div class="h">black 2</div>
<p class="anchor">the anchor</p>
<div class="h">orange 1</div>
<div>
<span class="h">should be black</span>
</div>
<p>
<span class="h">why isn't this black</span>
</p>
<div class="h">orange 2</div>
<p class="anchor2">anchor2</p>
<div class="h">blue 1</div>
<div class="h">blue 2</div>
</div>

Resources