1

Problem description

I would like all my h2, h3, p and picture children of an article to have the following css rule:

margin-left: 16px;
margin-right: 16px;

What am I doing

So I'm using the > operator in CSS:

article > h2, article > h3, article > p, article > picture {
    margin-left: 16px;
    margin-right: 16px;
}

However this form requires a lot of repetition of the article keyword, and I really need these changes to only apply to children of an article. Is there any way to compress this rule using the word article only once?

My attempt fails

I tried to do this:

article > (h2, h3, p, picture) {
    margin-left: 16px;
    margin-right: 16px;
}

But it seems to me that it's not something acceptable for the CSS language.

Pierre Vieira
  • 2,252
  • 4
  • 21
  • 41
  • 2
    `article > * ` targets all the direct children of `article`. And I recommend reading this [article](https://code.tutsplus.com/tutorials/the-30-css-selectors-you-must-memorize--net-16048) (no pun intended) – stackingjasoncooper Jan 10 '22 at 00:16
  • 3
    You can use the pseudo selectors `:is()`or `:where()` depending on the weight you want to give to those selectors/rules . 101 example : https://jsfiddle.net/k0ef8uwp/ See: https://developer.mozilla.org/en-US/docs/Web/CSS/:is and https://developer.mozilla.org/en-US/docs/Web/CSS/:where – G-Cyrillus Jan 10 '22 at 00:19
  • to complete my comment : https://stackoverflow.com/questions/67433247/what-is-the-difference-between-where-and-is/67450559 (close to be a duplicate someway) – G-Cyrillus Jan 10 '22 at 00:25

3 Answers3

3

As G-Cyrillus suggested, you can use one of the pseudo-classes :is() or :where() to list multiple element types at the end of your article > … selector:

article > :is(h2, h3, p, picture) {
    margin-left: 16px;
    margin-right: 16px;
}
<article>Inside an article:
  <h1>h1 (shouldn’t be styled)</h1>
  <h2>h2</h2>
  <p>p</p>
  <picture>Inside a pic:
    <h2>h2 that is not a direct child of the article (shouldn’t be styled)</h2>
  </picture>
</article>

The difference between :is() and :where() is their specificity. :is() takes on the specificity of the most specific selector in its arguments, while :where() always has 0 specificity. For more details, see MDN: Comparing :where() and :is() or Stack Overflow: What is the difference between :where() and :is().

Browsers started implementing support for these selectors in 2020. Browser compatibility details: MDN: :where(), MDN: :is(), Can I use… :where(), Can I use… :is().

Rory O'Kane
  • 29,210
  • 11
  • 96
  • 131
1

If you have already set up a CSS build tool — a CSS pre-processor or post-processor such as PostCSS, Sass, or Less — you could use nested rules in combination with the & selector:

article {
    & > h2, & > h3, & > p, & > picture {
        margin-left: 16px;
        margin-right: 16px;
    }
}

If I pass the above to, for example, Sass as a SCSS input, it gets compiled to the CSS you want:

article > h2, article > h3, article > p, article > picture {
     margin-left: 16px;
     margin-right: 16px;
}

Tool-specific notes

Configuration

If you are using PostCSS, you will need a plugin to use nesting and &. I am aware of two plugins that support this:

Sass and Less require no additional configuration to use those features.

Documentation

Sass and Less call & the parent selector: Sass docs for &, Less docs for &. The CSS Nesting specification implemented by PostCSS Nesting calls & the nesting selector: CSS Nesting spec on &.

Rory O'Kane
  • 29,210
  • 11
  • 96
  • 131
0

If you know that in your HTML, all children of an article will be elements of the types you are trying to style, you can use *, the CSS universal selector, instead of listing h2, h3, p, picture explicitly:

article > * {
    margin-left: 16px;
    margin-right: 16px;
}

This will apply the given styles to all direct children of article. There’s no way to specify exceptions for the elements included in *.

Rory O'Kane
  • 29,210
  • 11
  • 96
  • 131