CSS - if div is empty, display content - html

Is it possible to create a conditional div display depending on another div's content being present or not? I'm looking for a CSS only solution.
I've used something like this before:
.myClass:empty:before {
content: 'content added to empty div';
}
to add content to an empty div. But since there is no way to create hyperlinks in the created pseudo-content, I'm looking for another way.
So let's assume my div structure is as follows:
<div class="div1"></div>
<div class="div2">This should be displayed</div>
Is it possible to do a css trick to display div2 if div1 is empty; but hide it if div1 has content?
Feel free to restructure the div hierarchy, what I'm looking for does not depend on the current div structure.
Looking for ideas. Thank you.

I'd suggest:
/* hiding the div.div2 element (and its content)
if it's the next element-sibling of div.div1: */
div.div1 + div.div2 {
display: none;
}
/* selecting the div.div2 element which is the next
element-sibling of an empty (div.div1:empty)
div.div1 element: */
div.div1:empty + div.div2 {
display: block;
}
/* hiding the div.div2 element (and its content)
if it's the next element-sibling of div.div1: */
div.div1 + div.div2 {
display: none;
}
/* selecting the div.div2 element which is the next
element-sibling of an empty (div.div1:empty)
div.div1 element: */
div.div1:empty + div.div2 {
display: block;
}
div.div1 {
border: 1px solid #f00;
color: #f00;
}
div.div2 {
color: #0f0;
border: 1px solid #0f0;
margin-bottom: 1em;
}
<div class="div1"></div>
<div class="div2">This should be displayed</div>
<div class="div1">This is 'div.div1' (it has content)</div>
<div class="div2">This should not be displayed</div>

use css- next element selecor
.div1:empty + div{
content: 'content added to empty div';
}

Thank you for the quick answers. Based on Alexis Peters' answer, I've created this one which worked like a charm. Putting it down for future reference:
div2 {
display: none;
}
.div1:empty + .div2{
display: block;
}
An explanation is (for explorers like me) CSS above says "set div2 to not display. If any .div2 follows an empty .div1 then set display to block".
Cheers.

Related

Disabling pointer events only on a child element through CSS only

I'm working on a userscript for a page, so I don't have control over the original HTML. Also, because of the way the page loads and the script works, for various reasons I can only use CSS modifications here, and the modifications can only be on page-level CSS (not per-element style attributes).
So, the issue is, there is a large a element that has a hierarchy of divs in it. I would like to disable pointer events only on one of the child divs, while leaving everything functioning as normal everywhere else on the a. For example:
const disableBottomPointerEventsStyle =
'.bottom { pointer-events: none; cursor: default; }';
$('#test').click(function () {
$('<style/>')
.attr('type', 'text/css')
.text(disableBottomPointerEventsStyle)
.appendTo(document.head);
$(this).toggle();
});
.link { display: flex; width: 10ex; height: 20ex; margin-bottom: 1ex; }
.wrapper { display: flex; flex-direction: column; }
.top { border: 1px solid red; }
.bottom { border: 1px solid blue; }
div { flex-grow: 1; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- example of page structure: -->
<a class="link" href="about:blank">
<div class="wrapper">
<div class="top"></div>
<div class="bottom"></div>
</div>
</a>
<!-- ========================== -->
<button id="test">Test</button>
In that example there is an a with some divs in it, and the goal is to disable pointer events only on the blue div on the bottom while leaving everything else as-is.
To use the example press the Test button; this will insert a style rule in the document. My current best attempt is the value of disableBottomPointerEventsStyle:
.bottom { pointer-events: none; cursor: default; }
This has no effect.
So my question is, is it possible to do this only by modifying a page-wide CSS rule and, if so, how?
Note that this is fundamentally a CSS question, the JavaScript is pretty much incidental here.
The secret is to disable natural a behaviour, and enable it in the child.
I used hardcode a.link - to minimise a risk of side effects.
Supported https://caniuse.com/?search=pointer-events - should be good.
.link { display: flex; width: 10ex; height: 20ex; margin-bottom: 1ex; }
.wrapper { display: flex; flex-direction: column; }
.top { border: 1px solid red; }
.bottom { border: 1px solid blue; }
div { flex-grow: 1; }
a.link{ pointer-events: none}
div.top{ pointer-events: auto}
<a class="link" href="about:blank">
<div class="wrapper">
<div class="top"></div>
<div class="bottom"></div>
</div>
</a>

Is it possible to only target content between ::before and ::after when using CSS?

I do not have access to the JavaScript or HTML, only the CSS.
I am trying to change the text that is already there, to something else.
#element::before {
content: "This is the new text."
}
<div id="element">This is the original text.</div>
Is it possible to target the old text specifically with CSS, to then maybe apply text-indent: -9999px;?
It is not possible to specifically target the text node of an element; see Is there a CSS selector for text nodes? for more information.
You could achieve the effect you are after in a variety of ways, although as Paulie_D suggests, whether this is a good idea depends on what you are trying to achieve.
#element {
visibility: hidden;
}
#element:before {
content:"My new text using visibilty.";
visibility: visible;
}
#element2 {
font-size: 0;
}
#element2:before {
content:"My new text using font-size.";
font-size: 16px;
}
<div id="element">This is the original text.</div>
<div id="element2">This is the original text.</div>
The short answer is: no, you cannot use CSS to target the text within the element independently of the content of the pseudo elements.
However, you can create a work around by pasting the content of the pseudo element over the original
content and thus hide it.
Note: This approach uses absolute positioning so it may created issues if the pseudo-element
content is excessively long.
Better Approach: An alternative approach is to use the visibility property to hide the main content of the
element but make visible the content from the pseudo-elements (credit to Hidden-Hobbes).
#element::before {
content: "My new text.";
display: block;
color: black;
position: absolute;
background-color: yellow;
width: 100%;
}
#element {
color: red;
position: relative;
}
#element-alt::before {
content: "My new alt-text.";
border: 1px dotted blue;
visibility: visible;
display: block;
}
#element-alt {
border: 1px dotted gray;
margin-top: 30px;
visibility: hidden;
}
<div id="element">This is the original text.</div>
<div id="element-alt">This is the original text.</div>

CSS: Simply apply a style to the first generation of children

I am trying to apply a css style to the first children of an element. So say I have a div, with two divs, which are the children, and within each child is their own child, which are the grandchildren.
This JSFiddle, I hope is what I've done: http://jsfiddle.net/o8xhba9u/
#parent {
border: 1px solid;
padding: 10px;
}
#child-one {
text-indent: 5px;
padding: 10px;
}
#child-two {
text-indent: 5px;
padding: 10px;
}
#parent * {
border-top: 1px solid red;
}
My goal is to only have the children (child-one and child-two) to only be the ones with the red border-top. The paragraph elements (grandchildren) shouldn't have the red outline. I am trying to accomplish this dynamically, as if I were to have different elements, and add new ones later and have the effect applied without having to edit the css. How can I accomplish that?
You are looking for the direct child combinator, >.
Example Here
#parent > * {
border-top: 1px solid red;
}

Display another container on input:focus using only css

I want to have some css properties on input:focus so how can I do that?
My scenario is; when input get focus I want to show another div so how can I do that using only css?
On hover I can do that using ">" but on focus is not working and I don;t understand why :(.
so this is my code:
<div class="containerTooltipXxx">
<p class="paragraphClass">
Some text...<br /><input type="radio" /><br />More text...
</p><div class="blocks">
<label>Field</label> <input></input></div>
</div>
.containerTooltipXxx{
padding: 20px;
position: relative;
float: left;
display: inline-block;
border: 2px solid lime;
margin: 50px;
}
.paragraphClass{display: none;}
.containerTooltipXxx:hover > .paragraphClass, .containerTooltipXxx:focus > .paragraphClass{
display: block;
position: absolute;
top:-5px;
left: 50px;
background: red;
opacity:.9;
}
very important, the html hierarchy cannot be changed.
Thank you.
fiddle
using CSS you can only point to the next sibling elements. Here since the p tag is out of the parent div it is not possible using css.
I know that you don't want to change the HTML order but still I am showing it for example.
Moving p tag inside the div.blocks can do this with only CSS
.blocks input[type="text"]:focus ~ .paragraphClass {
display: block;
position: absolute;
top:-50px;
left: 50px;
background: #ccc;
opacity:.7;
}
DEMO
.containerTooltipXxx:hover > replace this by
.containerTooltipXxx:focus ~ .paragraphClass
{
display: block;
position: absolute;
top:-5px;
left: 50px;
background: red;
opacity:.9;
}
Your first hover selector is fine, but the second is wrong.
What you are doing with .containerTooltipXxx:focus > .paragraphClass, is selecting the immediate child .paragraphClass from a focused .containerTooltipXxx. Focus can only be used on things with input, and your container is just a div.
What you would need is a parent selector, but these are currently not available. They will be most likely in CSS4. http://www.w3.org/TR/selectors4/#subject
Currently, your best bet would be using javascript. Make an event listener for focus on the input box, and then programmatically apply a visible class to what you want to show.

Vertical layout with CSS without using breaking elements?

Is it possible to implement vertical layout with CSS only, and not with HTML elements?
I have a list of divs inside one div. By default the next element is right to the last, when there's no place on right, it is placed below.
I'd like to achieve the same with CSS style settings. Is it possible?
By CSS-only I mean, we have div and its children, and do not add anything special such as:
line-breaking elements ( <br/>, <div style="clear:both;"/> )
UL tags
tables (yes, still used, f.g. JSF almost exclusively based on them)
So:
<div id="menu">
Page 1
Page 2
Page 3
</div>
And CSS implementing vertical layout:
#menu { ??? }
#menu a { ??? }
Is there a ??? that I could use to achieve what I want?
Display anchor tags as block elements.
#menu a {
display: block;
}
Do you mean something like this?
http://jsfiddle.net/7Y9jS/
#menu {
width: 300px;
}
#menu a {
display: block;
background: #ccc;
color: #000;
padding: 10px 0;
text-align: center;
margin-bottom: 2px;
}
<div id="menu">
Page 1
Page 2
Page 3
</div>
set display block to a
#menu a {
display: block;
}
use float left
#menu a {
float:left;
}
and then add the class group to your #menu
.group:before,
.group:after {
content: "";
display: table;
}
.group:after {
clear: both;
}
.group {
zoom: 1; /* For IE 6/7 (trigger hasLayout) */
}