Is there a way to select nth-child globally? - html

This question already has answers here:
Select nth-child across multiple parents
(2 answers)
Closed 3 hours ago.
I have an HTML structure looks like this, I want to select all odd <span>s globally ignoring their parent elements.
Is there a way to make 1, 3, 5, 7, 9 red? I tried :nth-child(odd) but I think it only counts locally.
body {
counter-reset: spans;
}
span {
counter-increment: spans;
}
span::after {
content: counter(spans);
}
span:nth-child(odd) {
color: red;
}
<div>
<span></span>
</div>
<div>
<span></span>
<span></span>
</div>
<div>
<span></span>
<span></span>
<span></span>
</div>
<div>
<span></span>
<span></span>
<span></span>
<span></span>
</div>

No, that's not how :nth-child() and :nth-of-type() selectors work:
:nth-child(expr) only selects elements with an ordinal position within their containing parent element that satisfies expr, and not their ordinal position in the entire document, or any other arbitrary ancestor: only their ordinal position within immediate parent element matters.
:nth-of-type only selects elements with an ordinal position within their siblings that satisfies expr, which also implies the selector is evaluated independently of "cousin" elements in the DOM tree.
...so what you're asking is not currently possible using only CSS selectors: there is no :nth-overall or :nth-of-type-overall pseudoclass selector.
You can still implement this using a client-script to add a named classes to those elements manually when the document loads.
i.e. something like this:
const allSpans = document.getElementsByTagName("span");
for( let i = 1; i < allSpans.length; i += 2 ) {
allSpans[i].classList.add( 'isGloballyOdd' );
}
body {
counter-reset: spans;
}
span {
counter-increment: spans;
}
span::after {
content: counter(spans);
}
span.isGloballyOdd {
color: red;
}
<div>
<span></span>
</div>
<div>
<span></span>
<span></span>
</div>
<div>
<span></span>
<span></span>
<span></span>
</div>
<div>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
...which looks like this:

Related

CSS only - same width for multiple <span> elements, based on the largest

I'm curious if there is a way to set the width property for multiple <span> elements to the same value if they are not siblings to each other. The width should be based on the largest
span element.
The expected result would be something like a table where the left text will automatically grow.
So instead of this:
Text: Value
Larger Text: Value
I want it like this:
Text: Value
Larger Text: Value
I know this can be done with JavaScript (see example at the end), but I want to know if this is possible with CSS only.
And at best without changing the HTML structure, but I'm open for such an answer as well.
Some similar questions I've found, but they are about direct sibling spans. So it's not really fitting in my case:
Make adjacent sibling elements same width using only CSS
How can I make multiple spans equal width within a div
Why I want a CSS only solution and no JS?
Because I have to loop those elements twice:
To determine which of those elements is the largest and get the width from it
To set all elements the same width
Here is the working example with JS:
const variantNames = document.querySelectorAll('.variant-name');
let greatestWidth = 0;
variantNames.forEach( (name) =>
{
if(name.offsetWidth > greatestWidth)
{
greatestWidth = name.offsetWidth;
}
});
variantNames.forEach( (name) =>
{
name.style.width = greatestWidth + 'px';
});
.container,
.variant {
width: 100%;
}
.variant-name {
display: inline-block;
margin-right: 5px;
}
<div class="container">
<div class="variant">
<span class="variant-name">Size:</span>
<span>28</span>
</div>
<div class="variant">
<span class="variant-name">Waterproof:</span>
<span>Yes</span>
</div>
<div class="variant">
<span class="variant-name">Color:</span>
<span>Azure</span>
</div>
</div>
Easiest solution, that will work with the HTML structure you have - format the whole thing as a table.
.container {
display: table;
}
.container .variant {
display: table-row;
}
.container .variant span {
display: table-cell;
}
<div class="container">
<div class="variant">
<span class="variant-name">Size:</span>
<span>28</span>
</div>
<div class="variant">
<span class="variant-name">Waterproof:</span>
<span>Yes</span>
</div>
<div class="variant">
<span class="variant-name">Color:</span>
<span>Azure</span>
</div>
</div>

Selecting Multiple General Siblings of Elements Within Separate Div's

I know can control the display of a single class by using the following CSS:
.some-random-class{
display: none;
}
input[type=checkbox]:checked ~ .some-random-class{
display: flex;
}
I understand that this code controls the display of any object with the class of "some-random-class" that is a sibling of whatever checkbox is checked. If I have 3 classes I want to control the display of, I can do so with 3 separate input "functions" addressing each class individually. What I can't quite seem to figure out is how to control multiple classes in with the same "function" and control classes that are not in the same generation as in the following HTML:
<div>
<input type="checkbox">
<div class="first-class">
stuff to hide
</div>
<div class="second-class">
stuff to hide
<input type="checkbox">
<div class="third-class">
stuff to hide
</div>
</div>
</div>
When I try to control all three using what I think logically should work, it breaks the whole thing.
The following CSS is what I thought SHOULD work, however doesn't:
input[type=checkbox]:checked ~ .first-class ~ .second-class ~ .third-class {
display: flex;
}
Is this even possible, or am I asking too much of CSS?
If what I want to accomplish is possible, what am I not understanding about the above function?
You need to separate each rule with , , not just concatenate them with ~, because that only can select a single element.
input[type=checkbox]:checked ~ .first-class,
input[type=checkbox]:checked ~ .second-class,
input[type=checkbox]:checked ~ .third-class {
color: red;
}
input[type=checkbox]:checked ~ .third-class {
color: blue;
}
<div>
<input type="checkbox">
<div class="first-class">
stuff to hide
</div>
<div class="second-class">
stuff to hide
<input type="checkbox">
<div class="third-class">
stuff to hide
</div>
</div>
</div>

remove outline from button when clicked

#hamburger-btn :focus :active{
outline: 0 !important;
border: 0 !important;
}
<button id="test">
<div id="hamburger-btn">
<span></span>
<span></span>
<span></span>
<span></span>
</div>
</button>
I am trying to remove the blue outline from the hamburger btn when clicked however it is not working. My html is the following:
however it is not working
A space is a descendant combinator, you aren't trying targetting the descendants of the button, you are targetting the button itself.
Remove the descendent combinators from your selector.
Also note that to add an OR condition you will need to use a , and repeat every part of selector that is shared between the two parts.
Also note that the focus is applied to the button and not to the div inside the button, so you need to target the correct element in the first place.
Danger: Focus indicators are important accessibility features. Not everybody can or wants to use a mouse. They may need to know where the focus is in a document in order to interact with it. Reconsider removing all signs of the focus.
Do not do this
#test:focus,
#test:active {
outline: 0;
}
<button id="test">
<div id="hamburger-btn">
Needs content to be visible
<span></span>
<span></span>
<span></span>
<span></span>
</div>
</button>

CSS selection query for just parent content

Say I have the following.
<div class="price">$64 used
<span class="originally">$160 new</span>
<span class="you-save">You save 60%</span>
</div>
I only want to select the "$64 used", not the rest in the child spans. How would I do something like this? I have tried selecting like below and none work.
article > .price
article > .price:not(span)
article > div:not(span)
article > div:not(.originally):not(.you-save)
EDIT: For clarification..
const test = document.querySelector('section > div.price');
console.log(test.innerText);
$64 Used$160 New
You save 60%
I only want $64 Used. Is this even possible? I did not make the site, I am trying to scrape this.
div.price
do the work. For me, better is just use
.price.
Just make a small change:
<div class="price">
<span>$64 used</span>
<span class="originally">$160 new</span>
<span class="you-save">You save 60%</span>
</div>
CSS:
article > .price > span:not([class]) { color: red; }
This is not how tag:not() works. You can exclude a span tag from taking the style for span tags. But you can not select children this way.
Just apply a style to the div and overwride the properties for the children.
.price {
color: blue;
}
span.originally {
color: green;
}
span.you-save {
color: red;
}
<article>
<div class="price">$64 used
<span class="originally">$160 new</span>
<span class="you-save">You save 60%</span>
</div>
</article>

Selector for class prefix inside another class

I want to know what the proper selector is for the example below
<span class="A">
<span class="B_C"></span>
<span class="B_D"></span>
<span>
I want to select all the classes starting with B_ nested inside of A. I have tried each of these, but none of them worked:
.A + [class^="B_"], .A + [class*=" B_"]
.A > [class^="B_"], .A > [class*=" B_"]
.A [class^="B_"], .A [class*=" B_"]
An Element can have multiple classes so you can make it much easier if you just select by class:
<span class="A">
<span class="class_b class_c"></span>
<span class="class_b class_d"></span>
<span>
you can select all class that have b:
.A .class_b
.A [class^="B_"] works. Typically you'd put that attribute selector with another element though, like .A span[class^="B_"] (which also works).
Demo:
Output:
CSS:
.A [class^="B_"] {
color: red;
}
HTML:
<span class="A">
<span class="B_C">B_C</span>
<span class="B_D">B_D</span>
<span class="C_D">C_D</span>
<span>