Apply CSS styles to an element depending on its child elements [duplicate] - html

This question already has answers here:
Is there a CSS parent selector?
(33 answers)
Closed 2 years ago.
The community reviewed whether to reopen this question 5 months ago and left it closed:
Original close reason(s) were not resolved
Is it possible to define a CSS style for an element, that is only applied if the matching element contains a specific element (as the direct child item)?
I think this is best explained using an example.
Note: I'm trying to style the parent element, depending on what child elements it contains.
<style>
/* note this is invalid syntax. I'm using the non-existing
":containing" pseudo-class to show what I want to achieve. */
div:containing div.a { border: solid 3px red; }
div:containing div.b { border: solid 3px blue; }
</style>
<!-- the following div should have a red border because
if contains a div with class="a" -->
<div>
<div class="a"></div>
</div>
<!-- the following div should have a blue border -->
<div>
<div class="b"></div>
</div>
Note 2: I know I can achieve this using javascript, but I just wondered whether this is possible using some unknown (to me) CSS features.

The syntax for that is:
div:has(div.a) { border: solid 3px red; }
div:has(div.b) { border: solid 3px blue; }
As far as I'm aware, styling a parent element based on the child element is not an available feature of CSS. You'll likely need scripting for this.
It'd be wonderful if you could do something like div[div.a] or div:containing[div.a] as you said, but this isn't possible.
You may want to consider looking at jQuery. Its selectors work very well with 'containing' types. You can select the div, based on its child contents and then apply a CSS class to the parent all in one line.
If you use jQuery, something along the lines of this would may work (untested but the theory is there):
$('div:has(div.a)').css('border', '1px solid red');
or
$('div:has(div.a)').addClass('redBorder');
combined with a CSS class:
.redBorder
{
border: 1px solid red;
}
Here's the documentation for the jQuery "has" selector.

Basically, no. The following would be what you were after in theory:
div.a < div { border: solid 3px red; }
Unfortunately it doesn't exist.
There are a few write-ups along the lines of "why the hell not". A well fleshed out one by Shaun Inman is pretty good:
http://www.shauninman.com/archive/2008/05/05/css_qualified_selectors
Update. Many years later, :has has arrived, browser support is increasing.
https://developer.mozilla.org/en-US/docs/Web/CSS/:has
12 years is a long time.

On top of #kp's answer:
I'm dealing with this and in my case, I have to show a child element and correct the height of the parent object accordingly (auto-sizing is not working in a bootstrap header for some reason I don't have time to debug).
But instead of using javascript to modify the parent, I think I'll dynamically add a CSS class to the parent and CSS-selectively show the children accordingly. This will maintain the decisions in the logic and not based on a CSS state.
tl;dr; apply the a and b styles to the parent <div>, not the child (of course, not everyone will be able to do this. i.e. Angular components making decisions of their own).
<style>
.parent { height: 50px; }
.parent div { display: none; }
.with-children { height: 100px; }
.with-children div { display: block; }
</style>
<div class="parent">
<div>child</div>
</div>
<script>
// to show the children
$('.parent').addClass('with-children');
</script>

In my case, I had to change the cell padding of an element that contained an input checkbox for a table that's being dynamically rendered with DataTables:
<td class="dt-center">
<input class="a" name="constCheck" type="checkbox" checked="">
</td>
After implementing the following line code within the initComplete function I was able to produce the correct padding, which fixed the rows from being displayed with an abnormally large height
$('tbody td:has(input.a)').css('padding', '0px');
Now, you can see that the correct styles are being applied to the parent element:
<td class=" dt-center" style="padding: 0px;">
<input class="a" name="constCheck" type="checkbox" checked="">
</td>
Essentially, this answer is an extension of #KP's answer, but the more collaboration of implementing this the better. In summation, I hope this helps someone else because it works! Lastly, thank you so much #KP for leading me in the right direction!

Related

Html5 RNG border

I started learning how to write code within the last few weeks and I have been trying to improve and expand as well as put in to practice some of what I have learned by creating a text-based, web browser game.
The problem I am having is when I create a RNG and try to add a confined border it expands to fill a horizontal section of the webpage.
I have tried using some border measurement instructions but nothing seems to affect it. I have tried searching various web pages for a solution as well but nothing.
I have posted what I have written so far:
<style>
.bordered {
width 50px;
height 50px;
padding 25px;
border: 3px solid black;
}
</style>
<section>
<div class="bordered">
<p id="one"; width 50px;></p>
<button onclick="random()">Random</button>
<script>
function random(){
document.getElementById("one").innerHTML = Math.floor(Math.random() * 100);
}
</script>
Any suggestions?
The problem is that you have invalid HTML / CSS:
Your line of code <p id="one"; width 50px;></p> has a few errors; attributes should not have semicolons after them, and you width needs an equals sign. Ideally it would have quotation marks as well, as <p id="one" width="50px"></p>. Also note that setting inline rules like this is generally considered bad practise, and they carry the second-highest level of specificity. CSS should be used in most cases instead.
Your CSS rules need to have colons separating the properties from their values. For example, width 50px should be width: 50px.
Both the inline style and the CSS styles are invalid, and subsequently neither attempt to set width to 50px is getting applied. Because the element is block-level, it expands to the maximum width by default.
Fixing up the above two issues will confine your border's width, though as an additional nitpick you should avoid using the inline event handler onclick. Instead, you should separate the markup form the logic by making use of JavaScript's addEventListener() method.
This can all be seen in the following:
document.getElementsByTagName('button')[0].addEventListener("click", function() {
document.getElementById("one").innerHTML = Math.floor(Math.random() * 100);
});
.bordered {
width: 50px;
height: 50px;
padding: 25px;
border: 3px solid black;
}
<section>
<div class="bordered">
<p id="one"></p>
<button>Random</button>
</div>
</section>
Hope this helps!

Inner and outer wrapper colors

That seems to be a dumb question, but I'm really surprised, after a few websites worked with. Why does the foo div is red, not green?
https://jsfiddle.net/de8he92v/
<div class="wrapper-2">
<div class="wrapper-1">
<div>foo</div>
</div>
</div>
<style>
.wrapper-1 { background-color: red; }
.wrapper-2 { background-color: green; }
</style>
Edit
Ok, I read ThisClark answer, but still don't understand.
Here is updated fiddle:
https://jsfiddle.net/de8he92v/3/
Now the foo is yellow, but why it is not green?
The foo is inside red wrapper. Then, the red wrapper is inside green wrapper. So why we don't see green? What the madness?
In other words, if the puppy is inside the kennel, then we would see the kennel. But here we see only the puppy.
<div>foo</div> has the default user agent styles applied to it which is typically a transparent background and display: block.
Since it's inside .wrapper-1 and has a transparent background, you will see red.
To make this really stand out, add this to your fiddle and run it again:
div {
margin: 5px;
padding: 5px;
border: solid black 5px;
}
That additional style will apply to all the divs on the page and give you a better visual idea of where they are and what styles they have.
With the additional style applied, it ends up looking like this:
Additionally, div.wrapper-1 is said to be a child of div.wrapper-2 and even though 1 comes before 2 in numerical order, the div.wrapper-1 styles appear on top of their parent element, div.wrapper-2. The same parent-child relationship applies between div.wrapper-1 and <div>foo</div>.
EDIT
Your updated code in 3D view with margin, padding, and border:
Your update without additional style:

CSS - efficiently using classes

I have written a class for a textfield with a certain style. The field appears at 2 very different place within the website, with different parent elements. The second need another margin-top. What is an efficient way to change the original margin-top, since I cannot use pseudo-classes?
js fiddle
HTML
<div class="some_parent">
<div class="my_styled_field"></div>
</div>
.....
<div class="some_other_parent">
<div class="my_styled_field"></div>
</div>
CSS
.my_styled_field{
margin-top: 2rem;
}
.some_other_parent .my_styled_field{
margin-top:3em; //what ever you want
}
this is the way to apply some other styles to the same class, having different parents .
Pretty sure the most efficient way - most of the time - as in best performance, would be to add another class to your second styled_field.
If you add another class to your second styled_field, you would need only 1 reflow to reach it:
.newclass{margin-top:5px;}
Whereas using the descendant selector which others are selecting is surely worse performance, this means the browsers has to check a lot of elements recursively:
.parent .styled_field
If you don't want to add a class for some reason, better performance than the descendant selector would be the child selector:
.parent > .styled_field
When thinking about css performance, remember that even though we read left-to-right, browsers read right-to-left.
Where we would check all .container elements for an image-tag, browsers find all image-tags - then checks if they are in a .container
Using CSS class hierarchy:
.some_other_parent .my_styled_field {
margin-top: 2em;
}
Youc can do this:
FIDDLE EXAMPLE
.some_parent .my_styled_field{
width: 3rem;
height: 3rem;
margin-top: 2rem;
background-color: red;
}
.some_other_parent .my_styled_field{
width: 4rem;
height: 4rem;
margin-top: 4rem;
background-color: green;
}
This way, you aply style to .my_styled_field depending on his parent element.

Is there a css pseudo selector for overflow?

I'm trying to alter the style of something based on wether or not its parent div is being overflown.
.pDiv { display: block; width: 300px; height: 100px; border: 1px solid rgb(0,0,0); }
.cDiv { display: block; padding 4px; border-bottom: 1px solid rgb(0,0,0);
.pDiv:overflow .cDiv { border-bottom: none; }
<div class="pDiv"><div class="cDiv">child 1</div><div class="cDiv">child 2</div><div class="cDiv">child 3</div><div class="cDiv">child 4</div><div class="cDiv">child 5</div></div>
is it possible to do something like this? I would use the last-child pseudo-selector, but the number of children can vary, so I want it to remove the border-bottom of the last-child ONLY IF the parent div is being overflown. I want a pure CSS solution too please, no JS!
CSS cannot select based on used or computed styles of any kind, so you're out of luck.
It seems a handy solution for this is being cooked up: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries
According to css-tricks, the feature "#container brings us the ability to style elements based on the size of their parent container."
You should already be able to use it, but beware that not every browser supports this yet.
This way, you might (read the note) be able to get out with something like:
.parent-div {
max-height: 10rem;
overflow-y: auto;
container: size;
}
#container (min-height: 10rem) {
.parent-div:last-child {
border-bottom: none;
}
}
The main idea here being that if the element reached it's maximum height, then it's all but always overflowing — so we just apply the style so long as it's at it's maximum height.
Unfortunately, my own browser does not support this yet, so I can't guarantee you it would work the exact way as it is written above. But if you refer to the 2 pieces of documentation I provided, you should be able to come out on top 🤓
Note:
The css-tricks page also mentions that "Currently, you cannot use height-based container queries, using only the block axis". I'm hoping this simply means using the full size axis is necessary in this case, but I'm not able to test this.
If someone could verify whether this solution works and then leave a comment here, that would be very much appreciated. I'd edit this answer and credit the person.

Change specificity by child

I'd like to integrate a theme tag to my elements so they appear in diffrent colours. But since the css selectors have the same css specificity the latest overrides the earlier defined rule.
this is an example that shows my problem:
<div class="red">
<div class="box">This should be red</div>
<div class="yellow">
...
<div class="box">This should be yellow (nested in x levels under the div.yellow)</div>
...
</div>
and here my css
.box { width: 100px; height: 100px; }
.yellow { background-color: yellow; }
.red { background-color: red; }
the box should be listed somewhere, but as soon as it is a sub child of another color definition it should been overwritten.
thanks for any help!
You shouldn't really be doing things this way -- if your theme changes, then suddenly things with class yellow may actually be blue, for example. I would suggest finding a common way of naming things (even if it's just colour1, colour2, colour-highlight...) and then specifying those styles. You can then look into the way your pages are designed and make the rules more specific as necessary (either by using !important or by making the rule more specific, e.g. .colour1 becoming .box .colour1 or div.colour1).
Try:
.box { background-color: inherit; }
See:
http://jsbin.com/imube/edit
I don’t quite see the problem. Here’s what I get with that code:
alt text http://www.pauldwaite.co.uk/images/so/1905834.png
You probably need to use CSS's !important keyword eg:
.yellow { background-color: yellow !important;}