CSS: Adjacent sibling inside a class - css

Trying to add a top-margin to an adjacent sibling.
<div class="container">
<h2>Header 1</h2>
<p>Some text and sentences...</p>
<h2>Header 2</h2>
<p>Some more text and sentences..</p>
</div>
Normally I would accomplish top-margin on "Header 2" by using css on the adjacent siblings.
p + h2{
margin-top: 12px;
}
However, h2 has margin defined via
.container h2{
margin: 24px 0px;
}
How can I make the adjacent siblings css work while overriding the .container h2 css?

Try the following:
.container > p + h2{
margin: 12px;
}
That is:
Select h2 elements...
...which immediately follow a p element...
...which is a child of an element with class container.
Since .container > p + h2 contains 1 class and 2 elements, it will override .container h2, which only has 1 class and 1 element.

This should work
.container p + h2 {
margin-top: 12px;
}

.container h2 is more specific than p + h2 so it is taken into consideration. You need a more specific selector to override the margin.
This should be "more specific" and override:
.container p + h2 {
margin-top: 12px;
}

Related

Better CSS for Run-in Headings

Edit 3/18/22: I recently checked several Terms of Use and similar documents and found run-in headings are frequent in this type of document but always incorrectly formatted as <strong> rather than as headings, so this issue appears to be much broader than academia style guides.
I have been wrestling with the format of run-in headings for years. This is not a minor problem, because one of the top styles in academia and scholarly work, APA, requires (APA is strict, not flexible like some style guides) run-in headings for both level 4 and 5 headings (https://apastyle.apa.org/style-grammar-guidelines/paper-format/headings)
Many other academic styles also have run-in headings — for example, Chicago's five heading levels; and Harvard Extension's "C" level headings.
I used to just format run-in headings as bold, but that does not correctly interpret the document structure for assistive technologies. So I now use the CSS below, since display: run-in is not currently a CSS option. The results are glitchy.
For instance, a break appears after the heading when the heading wraps on the browser page. Any suggestions for better code?
H4.enpara {
text-indent: 2em;
display: inline-block;
break-before: column;
margin-bottom: -1em;
}
H4.enpara + P {
display: inline;
margin: 0 0 .7em 0;
}
Original Answer
Note: the concept was correct, but it had flaws, see the h2 heading "Edit, it was more complicated than I thought"
Original answer:
Could we not just use inline on both and apply a left-margin to the heading?
Then for spacing we just add a 0.15em margin to the left of the run-in paragraph.
The only down side is that you can end up with a double space as an extra character is automatically added for an inline paragraph and heading in Chrome.
The only solution I have for that would be to add a spacer class to headings that take up more than one line manually (the margin-left).
It is minor though as with a bit of fine-tuning you can see it is barely noticeable. It is still more accessible than using bold as you pointed out and I don't think the spacing difference is large enough to cause any problems to people with dyslexia etc.
h4, h5 {
margin-left: 2em;
display: inline;
}
h4 + p, h5 + p {
display: inline;
margin-left: 0.15em;
}
<h4>a long heading that will wrap onto two lines to ensure that browser wrapping does not break our run-in system</h4><p>a paragraph</p>
<p>another paragraph that does not have a run-in</p>
<h4>Another heading</h4>
<p>another paragraph with a run-in.</p>
<p>a longer paragraph to ensure there isn't an issue with the run-in happening for the heading itself on a paragraph
<h5>a heading level 5 to test it works for that also</h5>
<p>a further paragraph that should have a run-in also</p>
Edit, it was more complicated than I thought
The above kind of works, but you can get run-in where it is not intended if you happen to only have a single paragraph after a h4 or h5 and then use another h4 or h5.
I may have made a mistake and this is not extensively tested, but this appears to be the correct formatting requirements for all heading levels.
I had to use a couple of tricks to account for run-in on a h4 followed by a h5 with only a single paragraph and to counter a spacing issue that introducing the ::after pseudo element caused.
I think the below behaves correctly, but you would need to test it extensively as I said.
The only thing it doesn't cover is correcting Title Case as that isn't possible without JS as far as I am aware.
Finally I have set all spacing in REM, then if someone increases their browser size it will scale appropriately. The only thing that you may have to look at there is whether a 2rem margin on the left works or whether that should be a fixed amount (if you quadrupled the font size for example the left margin would be too large probably).
The fix would be to set the left margin in a fixed unit such as px, I will leave that up to you to investigate / decide.
h1, h2, h3, h4, h5{
font-size: 1rem;
font-weight: bold;
}
h1{
text-align: center;
}
h3, h5{
font-style: italic;
}
h4, h5 {
margin-left: 2rem;
display: inline;
}
h4 + p::after, h5 + p::after{
content: "";
height: 1rem;
display: block;
clear: both;
}
h4 + p, h5 + p {
display: inline;
margin-left: 0.15rem;
}
h4 + p + p,
h4 + p + h1,
h4 + p + h2,
h4 + p + h3,
h4 + p + h4,
h4 + p + h5,
h5 + p + p,
h5 + p + h1,
h5 + p + h2,
h5 + p + h3,
h5 + p + h4,
h5 + p + h5{
margin-top: 0rem;
}
<h1>H1 - Centered, Bold, Title Case Heading</h1>
<p>Text begins as a new paragraph.</p>
<h2>H2 - Flush Left, Bold, Title Case Heading</h2>
<p>Text begins as a new paragraph.</p>
<h3>H3 - Flush Left, Bold Italic, Title Case Heading</h3>
<p>Text begins as a new paragraph.</p>
<h4>H4 - Indented, Bold, Title Case Heading, Ending With a Period.</h4>
<p>Text begins on the same line and continues as a regular paragraph.</p>
<h5>H5 - Indented, Bold Italic, Title Case Heading, Ending With a Period.</h5>
<p>Text begins on the same line and continues as a regular paragraph.</p>
<h2>H2 - Flush Left, Bold, Title Case Heading</h2>
#Graham Ritchie's answer seems to work well, but not a fan of the h4 + p + p, h4 + p + h1.... Hopefully this works well for you:
h1, h2, h3, h4, h5 {
font-size: 1rem;
font-weight: bold;
}
p {
text-indent: 2rem;
}
h1 {
text-align: center;
}
h3, h5 {
font-style: italic;
}
h4, h5 {
display: inline;
margin-inline-start: 2rem;
}
h4 + p, h5 + p {
display: inline;
margin-inline-start: 0.5rem;
}
h4 + p::after, h5 + p::after {
content: "";
display: block;
margin: 1rem;
}
<h1>H1 heading</h1>
<p>Text following h1</p>
<h2>H2 heading</h2>
<p>Text following h2</p>
<h3>H3 heading</h3>
<p>Text following h3</p>
<h4>H4 heading</h4>
<p>Text following h4</p>
<p>Text following h4 + p</p>
<h4>H5 heading</h4>
<p>Text following h5</p>
<h5>H5 heading following h5 + p</h5>
<p>Text following h5</p>
<h2>H2 heading following h5 + p</h2>
<p>Text following h2</p>

Avoid CSS styling between certain adjacent elements and classes

I would like to add padding-top: 20px; between h3 and body but not if h3 is preceded by another element (e.g., h2). Is this possible?
Adding padding-top to all headings gives the desired padding when a heading is preceded by body text but an undesired padding between headlines:
Note that this document is Rmarkdown created using knitr, so I don't have full control over all the html. A pure CSS-solution would be preferred.
UPDATE:
To anyone also using knitr for Rmarkdown, the solution turned out to be a rather complex targeting:
/* First h2 following h1 */
.level1 > .level2:nth-child(3) > h2 {
padding-top: 0px;
}
/* First h3 following h2 */
.level2 > .level3:nth-child(3) > h3 {
padding-top: 0px;
}
Looking at the generated HTML, I learned that the first h2 after a h1 was in the third element in level1 and that that element was called level2. Similarly for the first h3. This is what is targeted above. The structure is probably different in other documents so take a look yourself.
How about
body > h3:first-child {
padding-top: 20px;
}
That will affect only immediate child of body with a header3, with nothing in between.
Thanks to #Oram, for pointing out missing :first-child
You can use the > selector plus :first-child to target only a direct h3 child.
* {
margin: 0;
padding: 0;
}
.test {
background-color: #cccccc;
margin: 10px;
padding: 10px;
}
.test > h3:first-child { color: red; }
<div class="test">
<h3>Targeted h3</h3>
<p>Paragraph</p>
<h3>h3 not targeted</h3>
</div>
<div class="test">
<p>Paragraph</p>
<h3>h3 not targeted because of the p tag</h3>
<h3>h3 not targeted</h3>
</div>
Try this:
body > h3:first-child {
padding-top: 20px;
}
It will only apply the CSS to the first direct child of the body which is a h3.

CSS - successive indenting of siblings after headings

I am needing to indent all elements after headings to give a visual structured layout.
I have seen that this is possible in the this question :
Indent all tags following h2 until next h2 is hit using CSS
However, I am unable to "reset" when going back a level.
To be more clear, I need to have progressive indents which cancel when moving back.
So
H1
H2
.....
H2
.....
H3
....
H2
.....
H1
....
If possible, I would prefer to not use enclosing DIV's but rather pure CSS.
Is this possible ?
Here is a code snippet for indenting. I hope I understand what you want correctly.
* {
margin: 0;
}
h1 ~ *:not(h1) {
margin-left: 1em;
}
h2 ~ *:not(h1):not(h2) {
margin-left: 2em;
}
h3 ~ *:not(h1):not(h2):not(.h2):not(h3) {
margin-left: 3em;
}
h4 ~ *:not(h1):not(h2):not(.h2):not(h3):not(.h3):not(h4) {
margin-left: 4em;
}
<h1>H1</h1>
<h2>H2</h2>
<h2>H2</h2>
<p class="h2">test</p>
<h3>H3</h3>
<p class="h3">test</p>
<h4>H4</h4>
<p class="h4">test</p>
<h2>H2</h2>
<p class="h2">test</p>
<h1>H1</h1>
<h2>H2</h2>
<h2>H2</h2>
<h1>H1</h1>
UPD:
Oh, I see about other elements - sorry didn't get it. Maybe somehow like this?
You can use the CSS text-indent property.
h2, h2 + * {
text-indent: 50px;
}
h3, h3 + * {
text-indent: 100px;
}
Ok, here is the solution which works for me :
h1 + *:not(h1)
{
margin-left: 0em;
}
h2 + *:not(h2), h2
{
margin-left: 20px;
}
h3 + *:not(h3), h3
{
margin-left: 40px;
}
The key is to use the plus sign (+) as opposed to the tilde sign (~).
Hope this helps others also.
Edit : Ok, spoke too soon. This will successfully indent and outdent, but only for the first sibling element. If there are multiple sibling elements, it will fail.
Any ideas ?

Changing width of h1 when img is hovered over

I'm trying to expand the width of my h1 tag when you hover over the img, however I cannot seem to get it to work.
http://jsfiddle.net/xJ4dc/
Thanks.
Try this:
img:hover + h1 {
width:100%;
}​
jsFiddle example.
This rule says that whenever you hover over an image, change the width of all adjacent sibling <h1> elements to 100%.
The Selector has to select the element for it to apply the rule.
In your fiddle img:hover has no desendant h1 therefore nothing happens.
In this case, since h1 is the next sibling of img:hover you can use the + selector
img:hover + h1
fiddle
you need to understand what img:hover h1 says:
upon all tags named img on :hover all child elements tags named h1
you would need to use the plus sign img:hover + h1 to work.
But I would suggest do is http://jsfiddle.net/xJ4dc/5/
<ul>
<li>
<img src="http://www.real-whitby.co.uk/wp-content/uploads/donkey.jpg" />
<h1>This is a heading</h1>
</li>
</ul>
​
and then:
li img {
width: 100px;
}
li h1 {
display: none;
}
li img:hover + h1 {
display: block;
}
​
Note that I would use display:none; and then display:block to hide and show the heading.
The selector img:hover h1 means "any h1 element that is a descendant of an img being hovered over". The problem is your h1 element isn't a descendant of your img tag, it's a sibling. You can change to using the adjacent sibling selector to get the desired effect:
img:hover + h1 {
width:300px;
}
​

CSS: "AND" and + operator?

I want to put a space after all the headers using CSS. Like this:
if h1 = add a space after
else if h1 + h2 = add a space after also but no space in between
This is my HTML code
<article>
<h1>Title 1</h1>
...
</article>
<article>
<h1>Title 1</h1>
<h2>Title 2</h2>
...
</article>
For the CSS
h1, h2 { padding-bottom: 20px; }
The problem is, there is a space also between h1 and h2. I tried this code below but only those articles with h1 and h2 have a space after.
h1 + h2 { padding-bottom: 20px;}
Is there a way to do this? Or I should just use the h1 + h2 in CSS and add < br > for h1 only?
There's a few ways to do this, none pretty.
/* #1 */
h1 + *:not(h2),
h2 + *:not(h3) { /* etc */
padding-top: 20px;
}
/* #2 */
h1, h2 {
padding-bottom: 20px;
}
h1 + h2 {
margin-top: -20px;
}
(and variations of these.)
The problem is there is currently no way to select "backward," i.e. apply styles to an element based on what appears after it. There is only the ability to select "forward," using the + or ~ sibling combinators. So you can't override the style on an <h1> based on the existence of a subsequent <h2>.
In the CSS4 selectors draft, there is a method of specifying the subject of the selector, using the $ sign. In that case the code would look like:
h1, h2 {
padding-bottom: 20px;
}
$h1 + h2 {
padding-bottom: 0;
}
/* or even */
h1:not($h1 + h2), h2 {
padding-bottom: 20px;
}
This isn't currently available in any browsers, however.
Is there no way to know when generating the HTML if the h2 is following the h1? That seems like the best way to handle this. Then you can make a simple css rule for h2.follows_h1 { margin-top: -5px } or whatever fits exactly what you need.

Resources