Apply CSS to object, unless followed by paragraph - css

I was wondering how I could apply CSS to an h2, except when it's directly followed by a paragraph. In that case, apply the CSS to the paragraph.
I've got a few sections, each with it's own title. However, sometimes it's followed by a subtitle. I'm applying a bottom margin to each title, but if there is a subtitle, there shouldn't be a margin between. In that case that bottom margin should be applied to the paragraph beneath the h2.
But.. how do I fix that?
I could give each h2 with a subtitle a class with "gotSubtitle" so I can keep them apart, but that's not the 'smooth' way to do this.

Just did it.
article h2:not(.gotsubtitle){
color: red;
}
<article>
<h2 class='gotsubtitle'>Oi</h2>
<p>Test</p>
</article>
<article>
<h2>Oi</h2>
</article>
Added the class and the :not selector. ;)
Not too smooth, but... Is what we can do with pure CSS.
Another possibility:
With jQuery...
$('article').has('p').addClass('title');
article.title h2{
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<article>
<h2>Oi</h2>
<p>Test</p>
</article>
<article>
<h2>Oi</h2>
</article>

Try this it will work:
h2.gotSubTitle{
/*apply CSS to an h2*/
}
p + h2.gotSubtitle{
/*apply CSS to an h2 which is directly followed by a paragraph*/
}

Adding class="..." to each element would sure work, but I think the easiest (and still clean) solution would be to pack both the h2 and the paragraph into a div and apply the bottom margin to the div. No condition checking and it should work just as well.
And as asked many times, there is an adjacent sibling selector, but you can't select preceding elements with it, only following ones. However, it is possible to apply the bottom margin to every h2 and then apply the same bottom margin and a negative top margin to the following paragraph element.
While to me that is everything but clean, it requires no modification of your html code.
Here's an example.

var headerTag = document.querySelectorAll("h2");
for(var i = 0; i < headerTag.length; i++){
var nextELement = headerTag[i].nextSibling.nextSibling;
if( (/P/).test(nextELement.tagName)) {
headerTag[i].classList.add("no")}
}
h2{
background:red
}
h2.no{
background: none
}
<section>
<h2>header is following</h2>
<h2>paragraph is following</h2>
<p>i am a paragraph :-)</p>
</section>

Related

Can I hide a :before or :after element if the original div has no content?

I have a div that says "Tags: Example 1, Example 2"
The css looks like this:
.tag {
color: #bbb9b9;
font-size: 8pt;
font-weight: 300;
font-family: 'Roboto', sans-serif;
}
.tag:before {
content: 'Tags: ';
}
.tag:empty {
display:none;
}
Now, if no tags show up at the Wordpress post, I also want to hide the text "Tags", but it is in a :before tag.
Is there a way to hide the :before element somehow? Since the :before element is never actually empty, I'm finding it hard to fix.
The :empty pseudo selector will select elements that contain either nothing or only an HTML comment.
It will only work if the div is completely empty or has comments.
<div></div>
<div><!-- Comment --></div>
If the div has space or tabulations, you will have to use the pseudo element :blank
<div> </div>
<!-- Notice that inside this div there is a blank space -->
<div>
<!-- Comment-->
</div>
I think maybe this is what might happen. Although there is no content, the div may have some space or tabulation. If this doesn't help, it would be nice to have an example of the html code when it's theoretically empty.

Remove styling from an element if a certain element exists in the DOM higher up

I have a fairly specific scenario where I'd like to remove a top-margin from an element named 'footer' if and only if I can determine the presence of another element in the DOM.
The other element happens to be a DIV with a colored background, in which case the margin applied to the footer creates an unwanted empty white space.
The other element is not a sibling of the footer, but is rather a fairly deep descendent of a a preceeding element in the DOM.
An example would be :
<main>
<section>
<wrapper>
<div id="if-exists-remove-footer-styling">
<div>
</wrapper>
</section>
</main>
Here's a non-jQuery solution:
if (document.getElementById('if-exists-remove-footer-styling')) {
document.getElementById('footer').style.marginTop = 0;
}
All this assumes is that your footer element has an id.
Here's the jQuery solution:
if($('#if-exists-remove-footer-styling').length >0) {
$("#footer").removeClass('top-margin')
}
CSS:
.top-margin {
margin-top:60px;
}
#footer {
margin-top:0;
}
HTML:
<div id="footer" class="top-margin">footer content</div>
Working JSFiddle

:first-child not being applied

On this page, I want to hide the incorrect HTML displayed above the logo. It is generated by an old plugin we are replacing soon.
To start with, I tried the CSS:
.vine-home-block-grapes:first-child {display: none;}
but this does not remove the highlighted block below:
Can you help me determine why please?
Use css :first-of-type selector
.vine-home-block-grapes:first-of-type{
display:none;
}
That selector won't work as the element you are attempting to select is not the :first-child of its parent.
One way to do what you want is select all elements with that class name, set their styles as you wish and then, using a new rule with the sibling selector, override those styles for any element of that class appearing later in the parent.
.vine-home-block-grapes{
display:none;
}
.vine-home-block-grapes~.vine-home-block-grapes{
display:block;
}
Add this script. It would work fine without any problem:
<script>
var fourthChild = document.body.getElementsByTagName("div")[0];
document.body.removeChild(fourthChild);
</script>
Thanks to #FelixKling
Try wrapping the child elements in a <div> so the element can BE the first child of its wrapping element. Right now, your element is not the first child of <body> See the experiment here to show how :first-child doesn't work as expected, because really it's not the first child of its parent.
p:first-child {
background-color: aqua;
}
.vino:first-child {
background-color: lightgreen;
}
WORKS
<p>First</p>
<p>Second</p>
<p>Third</p>
DOESN'T WORK (because none of these are the first child of its parent, in this case, <body>
<p class="vino">First</p>
<p class="vino">Second</p>
<p class="vino">Third</p>
Adding a wrapping div works.
<div>
<p class="vino">First</p>
<p class="vino">Second</p>
<p class="vino">Third</p>
</div>

Structuring paragraphs like novels using CSS

This is the CSS:
p + p {
text-indent: 1.1em;
margin-top: 0;
}
p {
font-family: 'Crimson Text', serif;
margin: 0;
}
HTML:
<p>...<p>
<p>...</p> (new paragraph)
<p><br><p>
<p></p> (new scene)
(This is WordPress' default text editor)
I'm not sure how it works (I took it form a site that I can't remember).
It produces this:
There is only one problem. The third paragraph is a new scene and it shouldn't be indented. I wonder if there is a way of fixing this with CSS? (CSS3 is OK)
EDIT:
I guess jQuery is the only way? Any suggestions of doing it with jQuery?
I would say to structure it out into scenes.
Markup:
<div class="scene">
<p>...</p>
<p>...</p>
<p>...</p>
</div>
<div class="scene">
<p>...</p>
<p>...</p>
<p>...</p>
</div>
And some CSS:
.scene p { text-indent: 1.1em; }
.scene p:first-child { text-indent: 0; }
That cleans up your markup, and enables consistency across the board. (This is also ie7/8-friendly)
It's because you have all adjacent paragraph tags. If you change your HTML to this:
<p>...<p>
<p>...</p> (new paragraph)
<br>
<p></p> (new scene)
It should work - if you want extra spacing, maybe you should wrap your break inside another div?
You should mark a change of scene using a method other than <p><br></p>, which is a paragraph containing a line break only. The following is artificial too but causes an empty line even when CSS is off:
<p>...</p>
<p>...</p>
<div> </div>
<p>...</p>
Here the third p is not preceded by a p element but a div element, so the selector p + p does not apply to it.
Agree with #Jukka K. Korpela, you should probably be using something better. I have never used word press, but if you can't change the markup, then you might want to change.
If you just need it to work for now, you can run this script and it will fix the css values.
$('br').parent('p').next('p').css('text-indent', '0em');​
You just need to make sure you have the <br/> tag before your first scene.
<p><br/></p>
http://jsfiddle.net/bnMzQ/25/

css selector: first paragraph's first letter inside a div

<div>
<p>
Once upon a time..
</p>
<p>
A beautiful princess..
</p>
</div>
How can I select (in my css) the first letter of the first paragraph inside this div??
Thanks
Luca
div p:first-of-type:first-letter { font-weight: bold; }
In some cases you may have a header or some other elements types before the <p> For example:
<div>
<h1>My Great Title</h1>
<p>
In my younger years I was a great man, but all that changed when I saw...
</p>
<p>
I struck him for shaming my name, my family, my life. It was a shameful...
</p>
</div>
So in this case, p:first-child won't work for some reason, at least not in Chrome or Safari.
So instead you'll want to use this:
div p:first-of-type:first-letter{
/* add your awesome code here */
}
Thank you for your time.
first-of-type
You can use the CSS :first-letter pseudo-element to apply style to the first letter of a block-level element.
Well, I would add at least a class to the element you want the first-letter styling to be applied to. I'm sure you can do a css rule for the first paragraph of the first div; but if you happen to have another div with a paragraph at the beginning, then it is going to be applied to all of them. In other words, without using a class/id in your selector, it will be applied to the first letter of the first paragraph of EVERY DIV (which might not be the behavior you're looking for). So I would recommend this:
<div>
<p class="FirstLetter">
Once upon a time..
</p>
<p>
A beautiful princess..
</p>
</div>
And then in your css:
.FirstLetter:first-letter {
// styling rules here
}
But if my intuition is incorrect and you know for sure that this is what you're looking for, then #Demian Brecht's answer should do fine.
Yes, it's actually really simple:
div p:first-letter
CSS :first-letter Selector
div p:first-letter{
color:blue;
}
Working example HERE
Note: The following properties can be used with :first-letter
font properties,
color properties,
background properties,
margin properties,
padding properties,
border properties,
text-decoration,
vertical-align (only if float is 'none'),
text-transform,
line-height,
float,
clear
You can directly target the first letter of the entire div:
div:first-letter {
color: red;
}
demo: https://codepen.io/anon/pen/gRoypa

Resources