30

In my HTML structure, I have it set up like this:

<body>
   <main>
      <section>
      ...
      </section>

      <aside>
      ...
      </aside>
   </main>
</body>

The problem is, not all pages have <aside>

I need to select <section> and give it a max-width: 500px; ONLY when <aside> is present. The default is section { max-width: 1000px; } (when <aside> is absent)

Unlike in Selector for one tag directly followed by another tag; the user [asking the question] wants to style "B" ALL the time. Also, in this question, the user wants to select "B" (not "A")


  • I need to style <section> ONLY if <aside> is present.
  • I can't change the order of the HTML >_<
  • Can it be done with CSS only?
  • What selector do I need or how to set it up?
  • If it can't be done with CSS (I rather it be CSS-only), how can I accomplish this?
Community
  • 1
  • 1
Omar
  • 11,077
  • 21
  • 81
  • 107
  • Can it be done with CSS only? --- unfortunately not – Karl Adler Apr 15 '15 at 22:34
  • possible duplicate of [Selector for one tag directly followed by another tag](http://stackoverflow.com/questions/1132366/selector-for-one-tag-directly-followed-by-another-tag) – bpeterson76 Apr 15 '15 at 22:36
  • 1
    You are essentially asking for a previous sibling selector in css which don't exist. Possible duplicate of: http://stackoverflow.com/questions/1817792/is-there-a-previous-sibling-selector and http://stackoverflow.com/questions/7126531/css-selector-if-exist-adjacent-sibling – HJ05 Apr 15 '15 at 22:41
  • There is no need to re-edit your title to include a prefix that is already given in the tags. – BoltClock Apr 17 '15 at 05:22
  • @boltclock ditto! I'd appreciate if you don't edit the tile of my question. No need to change it to whatever you want it to be – Omar Apr 17 '15 at 23:32
  • 1
    Believe it or not, "whatever I want it to be" used to be the same as you - including the prefix in the title. But the [community has collectively agreed that that sort of thing doesn't belong](http://meta.stackexchange.com/questions/19190/should-questions-include-tags-in-their-titles) - so 1) there *is* a need to remove it 2) and it's not what *I* want it to be, it's what community policy wants. I won't edit your question again, but I can't guarantee that anybody else who comes along won't re-edit it either. – BoltClock Apr 18 '15 at 04:21

9 Answers9

41

A neat little trick

You can achieve what you want by using a trick to check if the <section> element is the only element in <main>. This will not work, if there are any other elements there. In your case it should work like this (http://jsfiddle.net/Ljm323qb/2/):

section {
     max-width: 500px;
}
/* The STAR of the show */
section:only-child {
     max-width: 1000px;
}

As illustrated in this codepen: http://codepen.io/omarjuvera/pen/ByXGyK?editors=110


General stuff on Sibling Selectors

There's the + selector which would select a sibling that comes right after the element (https://developer.mozilla.org/en-US/docs/Web/CSS/Adjacent_sibling_selectors)

And there's the ~ selector which selects all following siblings (https://developer.mozilla.org/en-US/docs/Web/CSS/General_sibling_selectors)

You could achieve it by putting the <aside> element before the <section> element and using a sibling selector.

Here's an example: http://jsfiddle.net/Ljm323qb/1/

A quick look in the future
Soon this will be possible, with a new :has pseudo class (http://dev.w3.org/csswg/selectors-4/#relational)
You'll be able to call something like main:has(> aside) > section { ... } but we'll have to wait for that, unfortunately :(

Omar
  • 11,077
  • 21
  • 81
  • 107
wawa
  • 4,248
  • 3
  • 27
  • 49
  • I can't change the order >_ – Omar Apr 15 '15 at 22:45
  • 1
    Hmm how about this: http://dev.w3.org/csswg/selectors-4/#only-child-pseudo will work starting at IE9... https://css-tricks.com/almanac/selectors/o/only-child/ – wawa Apr 15 '15 at 23:02
  • It relays on the fact, that the `
    ` element is the only element in the `
    `
    – wawa Apr 15 '15 at 23:07
  • @wsws it works. Edit your answer as a solution, with a jsFiddle =) – Omar Apr 15 '15 at 23:11
  • @Omar Done. I still let the general explanation for siblings there and added a method, that will work some time in the future, but is not implemented yet. – wawa Apr 15 '15 at 23:19
  • `:only-child` is not new to Selectors 4, so it's not exactly surprising that it works in IE9 - http://www.w3.org/TR/css3-selectors/#only-child-pseudo – BoltClock Apr 16 '15 at 03:40
  • Also a shorter way to write the selector using `:has()` is `section:has(+ aside)`. – BoltClock Apr 16 '15 at 03:44
  • A little bit more general hack would be :nth-last-child(1). It allows section to have previous siblings ( not limited to being the only child). But has less support – vals Apr 16 '15 at 06:55
  • @vals: Other than one or two versions of Chrome that have bugs, support for :only-child and :nth-last-child() is identical. And neither of these are hacks - unless you consider using structural pseudo-classes a hack. – BoltClock Apr 16 '15 at 07:12
  • @BoltClock I said hack meaning that we are not checking if aside is present or not, but we are checking another condition that is more or less related to it. – vals Apr 16 '15 at 08:57
  • The `:has` pseudo class unfortunately is still not implemented like 2 years later (http://caniuse.com/#feat=css-has). Microsoft has a poll open for it at https://wpdev.uservoice.com/forums/257854-microsoft-edge-developer/suggestions/8977591--has I'd suggest to vote on it. – wawa May 17 '17 at 10:46
  • 1
    Man, this idea of checking :only-child is great! saved my day! Thank you sir – extraxt Jan 29 '21 at 20:04
3

WITHOUT JAVASCRIPT

If you can change the order of your html elements to:

<body>
   <main>
      <aside>
      ...
      </aside>

      <section>
      ...
      </section>
   </main>
</body>

You can do it like this by using a sibling selector:

aside ~ section {
    max-width: 500px;
}
deowk
  • 4,230
  • 1
  • 24
  • 34
  • Correct and very good support up to IE7. Also good approach to use ~ and not + because this way the elements don't need to be next to each others. +1 – Alessandro Incarnati Apr 15 '15 at 22:47
  • 1
    This solution would work, if he could change the DOM. Unfortunately he wrote: `I can't change the order of the HTML >_ – wawa Apr 15 '15 at 23:21
  • 1
    You say "CSS ONLY", but then you go on to say "change the order of your html elements". That makes no sense. – BoltClock Apr 16 '15 at 03:42
  • I meant that this solution does not require javascript, I can understand that the heading is not 100% correct but I was speaking to the fact that the OP really did not want to use Javascript and needed a CSS only solution. – deowk Apr 16 '15 at 08:56
3

You can toggle a class .haveSidebar to the body tag using jQuery and make your CSS for the section tag depends whether this class exists on the body tag or not:

HTML

<main>
    <section>
    </section>

    <aside>
    </aside>
</main>

CSS

main {
    width:100%;
}
main aside {
    width:300px;
    background:red;
    min-height:300px;
    float:left;
}
main section {
    width:100%;
    background:green;
    min-height:300px;
    float:left;
}
body.haveSidebar main section {
    width: calc(100% - 300px);
}

JS

var sideBar = $('body > main > aside');
if (sideBar.length > 0) {
    $('body').addClass('haveSidebar');
} else {
    $('body').removeClass('haveSidebar');
}

Fiddle with aside tag

Fiddle without aside tag

Update

Solution without calc(), by using margin-left property

main aside {
    width:300px;
    background:red;
    min-height:300px;
    position:relative;
}
main section {
    width:100%;
    background:green;
    min-height:300px;
    float:left;
}
.haveSidebar main section {
    margin-left:301px;
}

Fiddle without calc()

Fares M.
  • 1,538
  • 1
  • 17
  • 18
  • Is it save to use `calc()`? I love it, but since it's only a Candidate Recommendation, I wonder if we should use it yet... (https://developer.mozilla.org/en-US/docs/Web/CSS/calc#Specifications) – wawa Apr 15 '15 at 22:49
  • There's some people using it, but there is no guarantees of compatibility and it still buggy in some browsers. – Fares M. Apr 15 '15 at 23:03
1

Even though it's not the neatest way of doing things, you can run on document ready javascript function, to check if aside tag exists, and inject an in-line css to the section tag accordingly.

Matju
  • 53
  • 6
1

It would be fairly straightforward to accomplish this with JavaScript.

For example this will work:

<script>
    window.onload = function() {
        if (document.getElementsByTagName('aside')[0]) {
           document.getElementsByTagName('section')[0].style.max-width = '500px';
        } else {
            document.getElementsByTagName('section')[0].style.max-width = '1000px';
        }
    }
</script>
Sam Redway
  • 7,014
  • 2
  • 25
  • 36
1

Try this, i believe it can only be done with some javascript.

if ($('main').find('aside').length>0)
{
    $('main').find('section').addClass('specificSection');
}
COLD TOLD
  • 13,299
  • 3
  • 33
  • 51
0

In CSS there is Adjacent sibling selectors: http://www.w3.org/TR/CSS21/selector.html#adjacent-selectors

section + aside { ... }

This is supported by all modern browsers, including IE8+ And be careful: selector matches if section and aside share the same parent in the document tree and section immediately precedes aside

If this doesn't work for you, you may try JavaScript with jQuery:

if($('aside').length)) $('section').addClass('specificSection');

And then add all your styles to class '.specificSeciton'.

alexeiTruhin
  • 425
  • 3
  • 9
  • 1
    This would select the – Stephen P Apr 15 '15 at 22:45
0

If you have the possibility to put your aside element before the section one, you can use the adjacent sibling selectors:

aside + section{ max-width: 500px }
Gaël Barbin
  • 3,611
  • 3
  • 22
  • 52
0

Using jQuery, you could try something like:

if($('aside')) $('section').css('max-width','500px');

Using CSS only, you could have a different style for the type of page that has the aside included and somehow only include that style on those pages. You could put that style into a little stylesheet of its own and include it where needed, which is probably a cleaner way of doing it than rendering the page and then changing it using JavaScript.

Eamonn Gormley
  • 2,348
  • 4
  • 19
  • 19