I have this structure in html
<div id="A">
....
<div id="B">
....
</div>
....
</div>
How can I write a CSS rule, that says, make all a tags color white inside #A, but ignore what's in #B?
I would prefer to have something like :not(#B) and not put another wrapper tag or anything too hardcoded.
Thanks
Best solution (although still not perfext):
(Corrected after the comment and with the code of #Amit)
/* Either directly under #A, or in an element in #A that's not #B */
/* The element that's not #B must be a direct child of #A, otherwise */
/* children of children of #B will be selected anyway, as #Amit pointed out. */
#A > a, #A > :not(#B) a { color:red }
<div id="A">
<a>red</a>
<div id="B">
<a>black</a>
<p>
<a>black</a>
</p>
</div>
<p>
<a>red</a>
</p>
</div>
This still has problems (IE 9+ and not working if #B is wrapped), but it is the best solution we've got.
Incorrect, failing solution (just to show what's wrong):
#A > a, #A :not(#B) a { color:red }
<div id="A">
<a>red</a>
<div id="B">
<a>black</a>
<p>
<a>black</a>
</p>
</div>
<p>
<a>red</a>
</p>
</div>
Why not do simply:
#A a {
color:#fff;
}
#B a {
color:green;
}
There's no solution that "just works" without restrictions. Your best effort would be to set explicit rules to elements within your negated selector (:not(#B)).
The reason for this is that rules are evaluated "positively", they look for a positive match, so for example (taken from one of the other "inaccurate" answers):
#A > a, #A :not(#B) a { color:green; }
/* for illustration purposes only */
#B { border:1px solid red; }
#B:before { content:"[I’m #B, my links aren’t green.]"; display:block; }
p { border:1px solid yellow; }
p:before { content:"[I’m a paragraph, the link inside me is not a child of #A.]"; display:block; }
<div id="A">
Link
<div id="B">
<span>
I am green after all
</span>
</div>
<p>
Link
</p>
</div>
The <span> around the link serves as a positive match for :not(#B), and the logic breaks.
Perhaps the closest you can get is by restricting matches the direct children plus nested children whose top most parent under A is not B:
#A > a, #A > :not(#B) a { color:green; }
<div id="A">
Link
<div id="B">
<span>
I am really not green
</span>
</div>
<p>
Link
</p>
</div>
But this would also break as soon as any element wraps B.
You’re on the right track with :not(#B) already.
You want to format the links that are direct children of #A, and those that are further down the tree, but not those in #B.
/* edited, was previously just #A > a, #A :not(#B) a, which won’t work for deeper nesting
inside #B, as Amit pointed out */
#A > a, #A > :not(#B) a { color:green; }
/* for illustration purposes only */
#B { border:1px solid red; }
#B:before { content:"[I’m #B, my links aren’t green.]"; display:block; }
p { border:1px solid yellow; }
p:before { content:"[I’m a paragraph, the link inside me is not a child of #A.]"; display:block; }
<div id="A">
Link
<div id="B">
Link
<span>Link inside span</span>
</div>
<p>
Link
</p>
</div>
Edit: As Amit pointed out, #A :not(#B) a would not work for links nested deeper into #B. So the :not(#B) part has to be a child of #A, #A > :not(#B) a. Example edited.
If you are actually trying to target <a> tags that appear under these elements and had markup that looked like the following :
<div id="A">
<a href='#'>Test A1</a>
<div id="B">
<a href='#'>Test B</a>
</div>
<a href='#'>Test A2</a>
</div>
You could take advantage of the direct descendant operator > in CSS to only target elements directly below #A and not within it's children :
#A > a {
/* This will only target <a> elements that are beneath #A and not in #B */
color: #FFF;
}
And example of this can be seen here and might look like :
Update
It looks like you don't want to just target <a> tags. If that is the case, you could probably generalize the previous statement by only targeting elements not in B under A :
#A > :not(#B) {
color: #FFF;
}
Updating the example markup :
<div id="A">
<a href='#'>Test A1</a>
<div id="B">
<a href='#'>Test B</a>
</div>
<div id="C">
I'm in C
</div>
<a href='#'>Test A2</a>
still will work as expected :
Related
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>
I have a lot of the same elements on a page that is not under my direct control (so i can't change the HTML). This might look like this:
<div class="item">This text should be black</div>
<div class="item" id="brand_one">This text should be red</div>
<div class="item" id="brand_two">This text should be red</div>
...
<div class="item">This text should be black</div>
I want to write a css rule that targets all elements with class item that have an id.
I can do
#brand_one, #brand_two, ... { color:red; }
But the id's go into the hundreds, so that's not an option.
What i'm looking for is a rule something like this:
.item[id] { color:red; } / .item# { color:red; }
I know this is possible in Javascript, but does this exist in CSS?
Yes, this is possible using CSS attribute selectors:
.item[id] {
/* any elements with a class .item and an ID attribute */
}
Yes, this exists. In you case you should use:
div[id*="brand"] { color: red; }
This selects all divs with an id that contains brand and colors it red.
Edit: You can also, to make sure it only targets ids with brand_ in the start of the id-name, use the following:
div[id^="brand_"] { color: red; }
This will avoid that other divs in the future that have an id that contains brand will also be targeted.
Edit 2: To make it even MORE specific, you can target only ids that are following the class="item":
div[id^="brand_"].item { color: red; }
This targets all divs with brand_ in the beginning of the id and have item as a class.
You can try using css attribute selector:
div.item {
color: black;
}
div.item[id^='brand_'] {
color: red;
}
div.code {
text-transform: uppercase;
}
div.code[id^='brand_'] {
color: blue;
}
<div class="item">This text should be black</div>
<div class="item" id="brand_one">This text should be red</div>
<div class="item" id="brand_two">This text should be red</div>
<div class="item">This text should be black</div>
<div class="code">This text should be in caps</div>
<div class="code" id="brand_three">This text should be in caps and blue color</div>
Here, [id^='brand_'] refers to id starting with brand_. There are also $(ends with) and *(contains) expressions.
We can use
.item[id^="brand"]{
color:red;
}
^= indicates "starts with". So we can search id which starts with "brand".
CSS [attribute^=value] Selector
The [attribute^=value] selector is used to select elements whose attribute value begins with a specified value.
So in your case ;
<style>
[id^="brand"] {
color:red;
}
<style>
Refer to:
w3schools
Try it yourself
Here's another way to do it.
<style type="text/css">
.item:not([id='']) {
color:red;
}
</style>
But it assumes you can set id='':
<div class="item" id="">This text should be black</div>
Not sure how this would work when id is unspecified as in your case.
I have a lot of the same elements on a page that is not under my direct control (so i can't change the HTML). This might look like this:
<div class="item">This text should be black</div>
<div class="item" id="brand_one">This text should be red</div>
<div class="item" id="brand_two">This text should be red</div>
...
<div class="item">This text should be black</div>
I want to write a css rule that targets all elements with class item that have an id.
I can do
#brand_one, #brand_two, ... { color:red; }
But the id's go into the hundreds, so that's not an option.
What i'm looking for is a rule something like this:
.item[id] { color:red; } / .item# { color:red; }
I know this is possible in Javascript, but does this exist in CSS?
Yes, this is possible using CSS attribute selectors:
.item[id] {
/* any elements with a class .item and an ID attribute */
}
Yes, this exists. In you case you should use:
div[id*="brand"] { color: red; }
This selects all divs with an id that contains brand and colors it red.
Edit: You can also, to make sure it only targets ids with brand_ in the start of the id-name, use the following:
div[id^="brand_"] { color: red; }
This will avoid that other divs in the future that have an id that contains brand will also be targeted.
Edit 2: To make it even MORE specific, you can target only ids that are following the class="item":
div[id^="brand_"].item { color: red; }
This targets all divs with brand_ in the beginning of the id and have item as a class.
You can try using css attribute selector:
div.item {
color: black;
}
div.item[id^='brand_'] {
color: red;
}
div.code {
text-transform: uppercase;
}
div.code[id^='brand_'] {
color: blue;
}
<div class="item">This text should be black</div>
<div class="item" id="brand_one">This text should be red</div>
<div class="item" id="brand_two">This text should be red</div>
<div class="item">This text should be black</div>
<div class="code">This text should be in caps</div>
<div class="code" id="brand_three">This text should be in caps and blue color</div>
Here, [id^='brand_'] refers to id starting with brand_. There are also $(ends with) and *(contains) expressions.
We can use
.item[id^="brand"]{
color:red;
}
^= indicates "starts with". So we can search id which starts with "brand".
CSS [attribute^=value] Selector
The [attribute^=value] selector is used to select elements whose attribute value begins with a specified value.
So in your case ;
<style>
[id^="brand"] {
color:red;
}
<style>
Refer to:
w3schools
Try it yourself
Here's another way to do it.
<style type="text/css">
.item:not([id='']) {
color:red;
}
</style>
But it assumes you can set id='':
<div class="item" id="">This text should be black</div>
Not sure how this would work when id is unspecified as in your case.
I have the following situation:
<div id="myMenu">
<div id="menu0">stuffs</div>
<div id="menu1">stuffs</div>
<div id="menu2">stuffs</div>
...... and so on
</div>
My requirement is to access all div having id $=menu inside myMenu except menu0, as my menu can have like 10 to 15 item so one way is to do:
#myMenu > menu1 {style}
#myMenu > menu2 {style}
so on... 15 times
but as I have to give same style to all of them , it seems unnecessary , I am looking for CSS selector which will fit correctly for my requirement also having compatible to IE8.
Any help is greatly appreciated.
If you always have the #menu0 element, you can use the general sibling selector that is IE8 compliant:
#menu0 ~ [id^="menu"] {
color: red;
}
<div id="myMenu">
<div id="menu0">stuffs</div>
<div id="menu1">stuffs</div>
<div id="menu2">stuffs</div>
</div>
or use classes (along with ids) that would fit better.
This css3 rule will get the list without #menu0:
div#myMenu > div:not(#menu0)
{
}
Alternately, you can use these two:
div#myMenu > div
{
/*new values*/
}
div#myMenu > div#menu0
{
/*reset with the original values*/
}
This code will hit all the children divs, then the second rule will override the prior one because it is later in the cascade and reset #menu0 to its original condition.
You can use class but also you can:
#myMenu div[id^="menu"]:not(#menu0) {
color: red;
}
<div id="myMenu">
<div id="menu0">stuffs</div>
<div id="menu1">stuffs</div>
<div id="menu2">stuffs</div>
<div id="menu3">stuffs</div>
<div id="menu4">stuffs</div>
<div id="menu5">stuffs</div>
</div>
This one selects all id which start with word 'menu' and is child of element with id #myMenu but exclude element with id #menu0
After comment for older browsers e.g. ie8 you can use:
#myMenu div[id^="menu"] {
color: red;
}
#myMenu #menu0 {
color: #000;
}
<div id="myMenu">
<div id="menu0">stuffs</div>
<div id="menu1">stuffs</div>
<div id="menu2">stuffs</div>
<div id="menu3">stuffs</div>
<div id="menu4">stuffs</div>
<div id="menu5">stuffs</div>
</div>
Because id is unique.
add another class:
<div id="myMenu">
<div id="menu0">stuffs</div>
<div id="menu1" class="sub">stuffs</div>
<div id="menu2" class="sub">stuffs</div>
...... and so on
</div>
and select:
#myMenu > .sub{ ... }
or simplicity
#myMenu .sub{ ... }
If, as implied from the comments to the question, it's always the first child that should not be selected:
/* selects all the <div>s with an id beginning with 'menu',
that follow a <div> with an id beginning with menu, that
are the direct-children of the element with an id of 'myMenu': */
#myMenu > div[id^=menu] + div[id^=menu] {
/* css here */
}
Or:
/* selects all <div> elements that are not the :first-child
that are direct children of <div id="myMenu">: */
#myMenu > div:not(:first-child)
/* css here */
}
Or:
/* selects all <div>s with an id beginning with menu that
have a previous sibling <div> with an id beginning with
'menu' that is the direct child of <div id="myMenu">: */
#myMenu > div[id^=menu] ~ div[id^=menu]
/* css here */
}
<div class="rightsidebox">
<div class="item-info-list">
<p>Model: AIDCU</p>
<div class="product-details">
<p></p>
<div class="price-box"> <span class="regular-price" id="product-price-1617-related">
<span class="price">$8.99</span></span>
</div>
<p></p>
</div>
</div>
I want to make a style for price and make the color green just in a case it is in the rightbox div and I want to use css , I cannot change the structure because it is a theme and it should not have conflict with other prices in other themes
I can use div.rightsidebox>div.item-info-list
but I cannot go further because of the paragraph in there
how can I solve it? I have weakness in using ">" and multiple classes in each other
This I believe is what you are looking for:
div.rightsidebox>div.item-info-list>div.product-details {
background:#ff0000;
}
JSFiddle: http://jsfiddle.net/RF5e7/
If you merely just want to select the price and make it green if it is contained by rightbox:
.rightsidebox .price {
color: green !important;
}
.rightsidebox .price { color: green !important; } // important to override other styles
EDIT: Usage of > - selectorr
The element>element selector is used to select elements with a specific parent. Note: Elements that are not directly a child of the specified parent, are not selected. More info
div.rightsidebox>div.item-info-list .price{
color: green;
}
JSFiddle example.
.rightsidebox .item-info-list p {
/* code */
}
This would go down to the paragraph element inside the classes defined there inside the stylesheet (above off course).
You don't need to be using div.rightsidebox that is required only if you're having class names for multiple elements. Otherwise only .rightsidebox is OK.
You can learn more about the CSS child selectors here: https://developer.mozilla.org/en-US/docs/Web/CSS/Child_selectors