rstacruz / rscss

Reasonable System for CSS Stylesheet Structure
https://ricostacruz.com/rscss
3.91k stars 176 forks source link

How can I style deeply nested HTML elements using RSCSS? #69

Closed joeljuca closed 7 years ago

joeljuca commented 7 years ago

Heya!

I'm not sure how to organize my components and/or elements when I have deeply nested components and I'm not really allowed to use the > CSS selector component.

For ex., I have the following markup:

<div class="question-box">
  <h1 class="title">My Question App</h1>
  <form>
    <div class="avatar">
      <img (...)>
    </div>
    <div class="question">
      <h2>Who's the one on the photo?</h2>
      <ul>
        <li class="answer">
          <input type="radio" id="option-1">
          <label for="option-1">Option #1</label>
        </li>
        <li class="answer">
          <input type="radio" id="option-2">
          <label for="option-2">Option #2</label>
        </li>
        <li class="answer">
          <input type="radio" id="option-3">
          <label for="option-3">Option #3</label>
        </li>
      </ul>
      <button class="submit" type="submit"></button>
    </div>
  </form>
</div>

In this case, I have a .question-box component, which holds the entire markup, and I have elements that are nested with multiple levels. For example, I need to keep a <form> element for HTML validation purposes, but then I'm unable to use the > CSS selector.

So, I would like to know how you have been tackling scenarios like this one :-)

operkot commented 7 years ago

You can break your major component into smaller pices. For example, add class .question-form to your form element form.question-form > .avatar etc. Sorry for my bad english!

joeljuca commented 7 years ago

Hey @operkot, thanks for replying!

So, you're suggesting me to break down .question-box component, which is quite big, into smaller ones, like .question-form, etc.? Why would I do it if my .question-box component is self-contained and I'll never use the .question-form outside this scope?

Also, if you do it, how do you structure your Sass files? I'm used to keep one Sass file per component - something like:

// path/to/my/stylesheets/components/_question-box.sass

.question-box
  font-size: 1.4em

  &.-small
    font-size: 1em

Are you doing something similar? If yes, how do you organize components with nested components that are not being used in other scenarios like this one?

ricotheque commented 7 years ago

You can consider form.question-form its own self-contained component, even if you'll only use it once. And yes, RSCSS recommends one file per component.

In any case however, you can use tag selectors. The only issue RSCSS with a selector like .question-box > form > ... is that it's not as descriptive as .question-box > .question-form.

joeljuca commented 7 years ago

Keeping a separated .question-form component seems to be a bad idea. Doesn't make sense to me, even when RSCSS recommends it. What I'll be doing is to avoid child selectors to keep the ability to style those elements. Something like:

.question-box
  // (...)

  & .title
    // (...)

  & .avatar
    // (...)

  & .question
    // (...)

  & .answer
    // (...)

I makes sense to me, for one important reason: there are no scenarios where I'll have other components inside .question-box, so avoiding the direct child selector > does not create cascading issues.

This is a tricky scenario where I found that RSCSS doesn't work well due to it being to restricted about nesting components. We could try to adapt it to scenarios like this one, which are really common in real world web applications.

ricotheque commented 7 years ago

Having used RSCSS to build WordPress themes, I totally understand where you're coming from.

I tried experimenting with not using > and it seemed to work fine at first. But then I encountered the scenario described in the Pitfalls page of the documentation. Using child selectors ensure that your component's styles only apply to that component's elements.

The biggest issue I have with RSCSS is that sometimes you're forced to use really long selectors, like > form > .title. But I agree with my namesake that child selectors are a must, even for complicated markup. That's why for each component file I settled on a system like this:

.question-box {
    // ...
}

.question-box > form {
    > .title {
        // ... 
    }
    > .avatar {
        // ...
    }
    > .question {
        // ...
    }
    > .answer {
        // ...
    }
}

.question-box.-question-variant > form {
    > .title {
        // ... 
    }
}

.question-box > .another-nested-component {
    > .element {
        // ...
    }
}
joeljuca commented 7 years ago

Got it!

Thank you very much for sharing your experiences. The direct child selector > approach seems the best to follow given the organization of RSCSS being so simplified. However, it creates a very strict HTML structure, enforcing you to stick with it because any change on HTML will result in changes on CSS.

I don't like this limitation. I like to think about block and inline elements being correctly stacked inside each other, and I like to create classes of elements that behave the same wherever I place it. RSCSS helps me on this objective by stripping positional CSS rules from the component's source code, but being so strict with the HTML layout creates more issues than solutions for me.

Perhaps it's just that RSCSS is not the tool for the current job.

Joel Wallis Jucá joelwallis.com

On May 2, 2017 12:24 AM, "ricotheque" notifications@github.com wrote:

Having used RSCSS to build WordPress themes, I totally understand where you're coming from.

I tried experimenting with not using > and it seemed to work fine at first. But then I encountered the scenario described in the Pitfalls page of the documentation http://rscss.io/pitfalls.html. Using child selectors ensure that your component's styles only apply to that component's elements.

The biggest issue I have with RSCSS is that sometimes you're forced to use really long selectors, like > form > .title. But I agree with my namesake that child selectors are a must, even for complicated markup. That's why for each component file I settled on a system like this:

.question-box { // ... } .question-box > form {

.title { // ... } .avatar { // ... } .question { // ... } .answer { // ... } } .question-box.-question-variant > form { .title { // ... } } .question-box > .another-nested-component { .element { // ... } }

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/rstacruz/rscss/issues/69#issuecomment-298488441, or mute the thread https://github.com/notifications/unsubscribe-auth/AApIXAVj8amwuc0eE2ccvfEFQ8amER3Rks5r1qHkgaJpZM4NMq4U .

rstacruz commented 7 years ago

However, it creates a very strict HTML structure, enforcing you to stick with it because any change on HTML will result in changes on CSS.

I don't like this limitation.

I'd consider this to be a feature, not a bug™—in my experience, having the nesting be intrinsically linked to the CSS structure has some benefits of its own, like being able to simplify your CSS, or being able to deduce markup from your CSS, and (most especially) making sure other developers don't deviate from the intended structure.

If you'd still prefer to have your CSS agnostic of your markup nesting levels, it does seem like RSCSS isn't for you. Other CSS organization methodologies like BEM and SUIT don't have this limitation, I encourage you to look into those. Good luck!

joeljuca commented 7 years ago

Yeah, I came up to the same conclusion, @rstacruz. But sometimes having a small freedom on HTML structure can lead to a good flexibility. For ex., in the example below I have a traditional Bootstrap-backed form:

<div class="col-md-9">

  <div class="form-contact-new">

    <div class="grpname form-group">
      <label for="field-name">Your name:</label>
      <input type="text" id="field-name" class="form-control">
    </div><!-- /.form-group -->

    <button type="submit" class="btnsubmit btn btn-default">Save</button>

  </div><!-- /.form-contact-new -->

</div><!-- /.col-md-9 -->

Here, consider .form-contact-new as my RSCSS component, and both .grpname and .btnsubmit as elements of that component. The structure works really well, but as you may know, HTML forms need to be wrapped into a <form> tag to work properly. So:

<div class="col-md-9">

  <div class="form-contact-new">
    <!-- wrapping HTML elements of .form-contact-new into a <form> tag -->
    <form method="post">

      <div class="grpname form-group">
        <label for="field-name">Your name:</label>
        <input type="text" id="field-name" class="form-control">
      </div><!-- /.form-group -->

      <button type="submit" class="btnsubmit btn btn-default">Save</button>

    </form>
  </div><!-- /.form-contact-new -->

</div><!-- /.col-md-9 -->

As you can see, I'm using a <form> because that's how HTML works, but it does not affect how I my elements should be rendered. The wrapping component .form-contact-new and the <form> element are both block elements, so the result is exactly the same (I'm assuming they don't have any CSS rule that might change it, like width, height, padding, margin, border, etc.). So, in this case, I would just need to have the freedom to say that I want to style the .grpname and .btnsubmit elements without having them as children of .form-contact-new.

Btw, the example above is just to illustrate why I think it's a bad idea. I'm already looking into SUIT CSS and it seemed the best solution for my case. Thank you very much for your time!