Element visible only if there are no siblings through CSS - html

My current code looks something like this:
if list.isEmpty() {
output("<div>No items</div>")
} else {
for each item in list
optput("<div>" + item + "</div>")
}
However, the whole "No items" logic belongs to the view and should be separated from the logic. Ideally, I'd like to have just
for each item in list
optput("<div>" + item + "</div>")
And then have the HTML template look something like this:
<div id="container">
<div style="visible only if no siblings">No items</div>
<div>Item 1</div>
<div>Item 2</div>
<div>
The problem is that I can't figure out how to do the "visible only if no siblings" part. Is there a way to achieve this reliably (works across all standard browsers) using CSS?

Give the div you want to be visible only with no siblings a particular class:
<div id="container">
<div class="vis-only-no-siblings">No items</div>
<div>Item 1</div>
<div>Item 2</div>
<div>
As long as the divs have no other siblings, you'll be able to use the :only-child pseudoselector, like so:
#container div.vis-only-no-siblings{
display: none;
}
#container div.vis-only-no-siblings:only-child {
display: block;
}

Related

Can html element be skipped by css?

TL;DR:
Is it possible for css to ignore html element, but not its children?
Such element would be treated by css as if it wasn't there; but its children would be treated normally, i.e. as children of parent of the ignored element.
Details, Motivation:
Let's say we have a nice styled layout, e.g. with display: flex.
<div className="outer"><!-- this one has display: flex (just example) -->
<div className="inner">Foo</div>
<div className="inner">Bar</div>
<div className="inner">Baz</div>
<div className="inner">Foo 2</div>
<div className="inner">Bar 2</div>
<div className="inner">Baz 2</div>
</div>
But then, we need to wrap one group of our inner elements into form, or nav (for semantic or other reasons):
<div className="outer">
<div className="inner">Foo</div>
<div className="inner">Bar</div>
<div className="inner">Baz</div>
<form>
<div className="inner">Foo 2</div>
<div className="inner">Bar 2</div>
<div className="inner">Baz 2</div>
</form>
</div>
Well, of course this breaks our desired layout (e.g. flex), because <form> became the child of outer, and sibling of the first three inners.
Is it possible to make an element, in this case form, to be ignored by css - as if it wasn't there in the html element tree?
If it's not possible, has this feature ever been considered, worked on, rejected... ?
That's exactly what display:contents is designed to do. So:
form { display:contents }
.outer {
display: flex;
justify-content: space-evenly;
}
form {
display: contents;
}
<div class="outer">
<div class="inner">Foo</div>
<div class="inner">Bar</div>
<div class="inner">Baz</div>
<form>
<div class="inner">Foo 2</div>
<div class="inner">Bar 2</div>
<div class="inner">Baz 2</div>
</form>
</div>
just set the form to display: flex
now the form is a direct child... so you can for example set it to flex:1 or so.
and you will get a new "parent" for the form child elements.

Using CSS selectors first of type and not first child together

I'm trying to do some styling using purely CSS selectors, my markup looks like this:
<div class="StyledRow">
<div class="Row">Input 1</div>
<div class="Row">Input 2</div>
</div>
<div class="StyledRow">
<div class="Row">Input 1</div>
<div class="Row">Input 2</div>
</div>
<div class="StyledRow">
<div class="Row">Input 1</div>
<div class="Row">Input 2</div>
</div>
The rendered elements are inputs side by side (2) and then stacked on top of one another (so the user can add as many data sets as they wish)
The above is a simplified version but because of additional elements, I need to be a bit more specific with my styles. For example, the current style of StyledRow looks like this:
const StyledRow = styled.div`
display: flex;
align-items: center;
*:not(:first-child) > * {
margin-left: 0.2rem;
}
`;
I am trying to target the second Row in the first StyledRow so that the styles can be different from the rest which use a margin-left: 0.2rem. I had tried to use first-of-type and not-first-child together but with no joy.
Any suggestions would be really appreciated!
If you use
*:not(:first-child) > * {
margin-left: 0.2rem;
}
it will apply that to everything. So if you use
.StyledRow:not(:first-child) > * {
margin-left: 0.2rem;
}
the styling will be applied on every iteration of StyledRow apart from the first one.
If you use:
.StyledRow:nth-child(2) > * {
margin-left: 0.2rem;
}
then that will specifically target the second iteration of StyledRow.

How to check if multiple elements exists

Given this html:
<div id="wrapper">
<div id="header-holder">
<div class="header">header 1</div>
<div class="header">header 2</div>
</div>
<div id="project">project data</div>
</div>
I want to apply a style to element in .header only if #project exists. I'd like to do this with css. Is this possible?
The trouble with cascading style sheets is they cascade. They go down layer by layer and don't come back up. If your structure were set where your <div id="project"> was above your <div id="header-holder"> you could use:
div#wrapper #project + #header-holder .header { ... }
However, if you are unable to restructure your HTML, then you'll need to use javascript. If you have access to jQuery you could try the following:
$('#wrapper:has(#project) .header').addClass("has_project");
Then in CSS:
.header.has_project{ ... }

Coloring alternating divs of certain class

My code is as follows:
HTML
<div class="divs">
<div class="row">row 0</div>
<div class="not-row"></div>
<div class="row">row 1</div>
<div class="not-row"></div>
<div class="row">row 2</div>
<div class="not-row"></div>
<div class="row">row 3</div>
<div class="not-row"></div>
</div>
CSS
.row:nth-child(even) {
background: #fff;
}
.row:nth-child(odd) {
background: #eee;
}
This is supposed to paint the background of two of the rows gray and two of the rows white. Unfortunately it paints all of their backgrounds gray. What am I doing wrong?
I tried using nth-of-type instead of nth-child but that didn't change anything.
jsFiddle example
For even just use (as a default)
.row {}
Then override the odd ones with:
.row:nth-child(4n+1) {}
.row {
background: #fff;
}
.row:nth-child(4n+1) {
background: #eee;
}
http://jsfiddle.net/b8ma1hon/3/
More on how nth-child works can be found here:
https://css-tricks.com/how-nth-child-works/
You cannot simply use even/odd in this instance as that is in relation to all child elements, not just the ones with the class row.
Your inclusion of .row in the selector is purely an extra criteria and has no impact on the nth-child selector.
Likewise I could state:
.row:nth-child(1):hover {}
This would restrict selection to an element with a class of row, which is the 2nd child, which is currently in a hovered state.
It wouldn't make sense if this was the 2nd element out of all the hovered elements as you can only hover over one at a time.
I hope that makes sense!
It's also worth noting that your selector is now dependant on the not-row existing, or at least some kind of element existing between the row elements.
If this was to change then your selector would also have to change.
Alternatively you could change your element type for the not-row elements to something else so that you can make use of the nth-of-type selector:
<div class="divs">
<div class="row">row 0</div>
<span class="not-row"></span>
<div class="row">row 1</div>
<span class="not-row"></span>
<div class="row">row 2</div>
<span class="not-row"></span>
<div class="row">row 3</div>
<span class="not-row"></span>
</div>
.row {
background: #fff;
}
.row:nth-of-type(odd) {
background: #eee;
}
http://jsfiddle.net/b8ma1hon/5/

Problem with selecting a nested last element

I have this HTML code with applied CSS.
I need all div with cnt-list-box in red but ONLY the LAST div cnt-list-box with different color.
Any ideas?
<div class="cnt-box-1">
<div class="cnt-list-box">content 1</div>
<div class="cnt-list-box">content 2</div>
<div class="cnt-list-box">content 3</div>
<div class="cnt-list-box">content 4</div>
<div class="cnt-list-box">content 5</div>
</div>
.cnt-list-box
{
background-color:Red;
}
your example does work in FF and Webkit:
http://jsfiddle.net/meo/hwFYT/
As commented by usoban you should check:
Changing CSS for last <li>
PS: your incode comment is not a valid CSS comment. It produces a parsing error this is why it seams to work, but its no a good practice.
Fortunately I found by myself a reasonable solution to my problem.
.cnt-box-1 > .cnt-list-box:last-child
{
background-color: Blue;
}