How to select an element when a sibling is not present? - css

I have a structure like this:
<div class="parent">
<div class="child-1"></div>
<div class="child-2"></div>
<div class="child-3"></div>
<div class="child-4"></div>
<div class="child-5"></div>
</div>
I want to target .child-4 only when .child-2 is not a child of the same parent, without knowing the order of children, but the .child-2 would never come after .child-4.

The classic CSS approach to such problems is to write a general case, then a more specialized case, where in this situation you would override the general case:
/* case where there may or may not be a preceding child-2 */
.child-4 { color: red; }
/* case where there IS a preceding child-2 */
.child-2 ~ .child-4 { color: inherit; }
<div class="parent">
<div class="child-1">child1</div>
<div class="child-2">child2</div>
<div class="child-3">child3</div>
<div class="child-4">child4</div>
<div class="child-5">child5</div>
</div>
<br/>
<div class="parent">
<div class="child-1">child1</div>
<div class="child-3">child3</div>
<div class="child-4">child4</div>
<div class="child-5">child5</div>
</div>
This uses the general sibling combinator, represented by a tilde (~).

Related

How to display adjacent sibling on hover using SASS?

.parent{
&__child-1:hover + &__child-2{
background-color: green;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/sass.js/0.6.2/sass.min.js"></script>
<div class="parent">
<div class="parent__child-1">child 1</div>
<div class="parent__child-2">child 2</div>
<div class="parent__child-3">child 3</div>
</div>
Hello, I'm trying to target an adjacent sibling of an element. The method I used works with CSS but doesn't work with SASS, is there something I'm missing here?

Is it possible to have scss selector that selects class only if it is last child of other element?

I have layout that is generated dynamically so order of elements could change. Each element that is part of this layout has its own different class. I want to be able to select element of certain class but only if it is last child of its parent to apply styling. If element with different class is last child of its parent, it should not be selected. Is it possible to have this kind of scss selector and achieve this functionality without using javascript?
Example:
<div class="parent">
<div class="child1">Hello!</div>
<div class="child2">Hello!</div>
<div class="child3">Hello!</div>
</div>
I want to select element with class child3 only if it is last child of div with class parent.
So if child2 class element is last child of div class parent it is not selected, for example here:
<div class="parent">
<div class="child1">Hello!</div>
<div class="child3">Hello!</div>
<div class="child2">Hello!</div>
</div>
Yes, and this is the normal CSS behaviour. You can do something like this:
.parent .child3:last-child {}
This is a rule that selects:
a .child3 element inside .parent.
.child3 element comes as the last, there's no other elements after that including text.
For SCSS, you can do something like this:
.parent {
.child3 {
&:last-child {
// Rules.
}
}
}
Example Snippet
.parent .child3:last-child {
background: #ccf;
}
<strong>Trial 1</strong>
<div class="parent">
<div class="child1">Hello!</div>
<div class="child2">Hello!</div>
<div class="child3">Hello!</div>
</div>
<hr />
<strong>Trial 2</strong>
<div class="parent">
<div class="child1">Hello!</div>
<div class="child3">Hello!</div>
<div class="child2">Hello!</div>
</div>
Preview
You can select elements by their attributes, so something like this would achieve your goal.
.parent div {
width: 50px;
height: 50px;
background-color: blue;
border: solid 1px black;
}
.parent div:last-of-type[class="child3"] {
background-color: red;
}
<div class="parent">
<div class="child1">Hello!</div>
<div class="child3">Hello!</div>
<div class="child2">Hello!</div>
</div>
<div class="parent">
<div class="child1">Hello!</div>
<div class="child2">Hello!</div>
<div class="child3">Hello!</div>
</div>
https://www.w3schools.com/cssref/css_selectors.asp

Do I need to specify every selector to style a nested element?

What is the proper way style a specific element that is deeply nested.
For example:
<div class="wrapper">
<div class="content">
<div class="main">
<div class="profile">
<div class="description">
<div class="name">John Doe</div>
</div>
</div>
</div>
</div>
</div>
If I want to make the name "John Doe" bold, do I name every selector:
.wrapper .content .main .profile .description .name { font-weight:bold; }
or do I just specify the selector directly like this:
.name { font-weight:bold; }
I am confused on what is the proper coding method. Thanks for your time!
No, you do not need to reference every parent element to target a nested element; you can simply target the element itself (such as with .name):
.name {
font-weight: bold;
}
<div class="wrapper">
<div class="content">
<div class="main">
<div class="profile">
<div class="description">
<div class="name">John Doe</div>
</div>
</div>
</div>
</div>
</div>
Also, note that you can simply target any of the ancestor elements directly as well, where the rule will cascade down (targetting .profile will target .profile as well as everything nested within .profile, but not any of the ancestors or siblings of .profile):
.profile {
font-weight: bold;
}
<div class="wrapper">
<div class="content">
<div class="main">Main (not bold)
<div class="profile">Profile
<div class="description">
<div class="name">John Doe</div>
</div>
</div>
</div>
</div>
</div>
When you specify additional parent elements such as with .wrapper .content .main .profile .description .name, you're increasing what's known as the specificity.
This can play an important part when you have two rules that both target the same element, where the most specific rule will be applied (in the following, .name is a valid selector, but .description .name targets the same element and is more specific, so .description .name overrides .name):
/* This gets applied */
.name {
color: red;
}
/* This gets applied and takes priority, as it is more specific */
.description .name {
color: blue;
}
<div class="wrapper">
<div class="content">
<div class="main">
<div class="profile">
<div class="description">
<div class="name">John Doe</div>
</div>
</div>
</div>
</div>
</div>
And this increased specificity also be used to denote when you have two elements with the same class or selector, where you only want the rule to apply to a particular element (the second .name here doesn't have the parent .description, so although .name would be a valid selector for it, .description .name is not):
.description .name {
font-weight: bold;
}
<div class="wrapper">
<div class="content">
<div class="main">
<div class="profile">
<div class="description">
<div class="name">Name One -- targetted</div>
</div>
<div class="name">Name Two - not targetted</div>
</div>
</div>
</div>
</div>
It depends if the only hierarchy you want to be selected is the one in your example. If the hierarchy does not matter, use only one class name (.name). If you want to limit your selection to a specific hierarchy (how specific depends on your situation), go for more. It's not entirely uncommon for selectors to consist of many class names, each of them going even deeper into the hierarchy.
However, looking at your code, I want to suggest giving some of your tags IDs instead of class names. IDs are like class names, but they are unique across the whole document (there can/should be only one element with the same ID per document). In your example, is there more than one .wrapper, .content, and .main? Probably not. You'll judge for yourself, but those kinds of structures are typically unique and exist only once in a document.
If you give them IDs, they are #wrapper, #content, and #main respectively.
<div id="wrapper">
<div id="content">
<div id="main">
<div class="profile">
<div class="description">
<div class="name">John Doe</div>
</div>
</div>
</div>
</div>
</div>
If you choose to do so, you can then get rid of the first three class names in your selector.
.profile .description .name
would be the same as:
#wrapper #content #main .profile .description .name
Except if there were elements in the document that had the same class names, but were outside of your #wrapper, #content, and #main.
The decision is yours, but it is commonplace to give such global structures (like main) IDs instead of class names, because they tend to be unique.

Is there a CSS selector for all grandchildren except first?

In this JSFiddle, how can I style all <a> elements except the first grandchild? (abc) with a single selector? I want to avoid using two rules at all costs.
#outer a:not(:first-child){
color: red;
}
<div id="outer">
<div id="firstParent">
<a>abc</a>
<a>def</a>
<a>hij</a>
</div>
<div id="secondParent">
<a>klm</a>
<a>opq</a>
</div>
</div>
You can do this (not sure if you can avoid more than 1 selector)
#outer >div:first-child a:not(:first-child),
#outer >div:not(:first-child) a{
color: red;
border:1px solid;
}
<div id="outer">
<div id="firstParent">
<a>abc</a>
<a>def</a>
<a>hij</a>
</div>
<div id="secondParent">
<a>klm</a>
<a>opq</a>
</div>
</div>
One rule 2 selectors:
a ~ a The general sibling combinator covers any <a> that follows another <a>. This basically selects all but the first <a> of sibling <a>.
div:nth-of-type(n+2) a This targets all <a> inside the second div and any preceding sibling divs in the future🟊.
Demo
a~a,
div:nth-of-type(n+2) a {
color: red
}
<div id="outer">
<div id="firstParent">
<a>abc</a>
<a>def</a>
<a>hij</a>
</div>
<div id="secondParent">
<a>klm</a>
<a>opq</a>
</div>
</div>
🟊 Props to Temani Afif for suggesting (n+2).
This works, not exactly sure why!
#outer :not(:first-child) {
color: red;
}
<div id="outer">
<div id="firstParent">
<a>abc</a>
<a>def</a>
<a>hij</a>
</div>
<div id="secondParent">
<a>klm</a>
<a>opq</a>
</div>
</div>

Complex css to only select first instance of an element

I need to be able to apply a width to a div but only if any of it's parents have a class of grid.
Obviously the child selector allows me to select an element if it's a direct child of the grid div:
.grid > .test {
width: 300px;
}
<div class="grid">
<div class="test"></div>
</div>
I need a selector that allows me to select the .test div even if its not the direct child of grid:
<div class="grid">
<div class="another">
<div class="test"></div>
</div>
</div>
You'd imagine that I could just use a bog-standard selector like:
.grid .test
Problem with this is that I only want to match the first instance of the .test div. The above selector matches all instances even if they're nested. Any subsequent div's with a class of test should be ignored.
<div class="grid">
<div class="another">
<div class="test">
<div class="test"></div> <!-- this should be ignored somehow -->
</div>
</div>
</div>
http://jsfiddle.net/hs3G9/1/
Is there any way to do this with css or do I need to resort to JS?
There isn’t a way of excluding that inner .test element without JavaScript. If the two had been siblings, you could do something like:
.grid .test:first-of-type {}
edit: Right you are; you can cook something up with the :not selector.
Using the :first-child selector in css should work.
So for you case:
<style>
.grid .test:first-child {
background-color: rgba(0,0,0,.2);
}
</style>
<div class="grid">
<div class="another">
<div class="test">
<div class="test"></div> <!-- this should be ignored somehow -->
</div>
</div>
</div>

Resources