Search code examples
htmlcssview

Preventing CSS from affecting child views


In the context of .NET MVC (but that could also apply to other similar technologies), let :

  1. A tree of views, e.g the page view FileUploadPage and its child partial view FileDropZone that would have a class identifying their view "type" on their root node :

FileUploadPage.cshtml :

<div class="view-fileuploadpage">
    <h2>File upload page view</h2>
    @Html.Partial("FileDropZone")
</div>

FileDropZone.cshtml :

<div class="view-filedropzone">
    File drop zone partial view
</div>
  1. Some CSS rules which I would like to apply only to the view's own elements instead of globally :

Like this :

.view-fileuploadpage h2 {
    /* Spécific to the view FileUploadPage */
}

But NOT like this :

h2 {
    /* Global, not what I want */
}

I like this way of doing things, because it prevents interferences from other pages in the CSS due to needlessly global selectors.

However there is a problem with that : the view-specific CSS rules apply to the view's own elements, but also to any other view that is being included as a child view. In the example above, the view FileDropZone inherits the rules that are supposed to be specific to the view FileUploadPage, which is an undesired consequence.

So my question is : how can I make the CSS rules that are supposed to be specific to my views own elements NOT apply to the child views as well ?

I could use the "direct child" opeartor in my selectors to specify the full "path" to the elements I want to style, like so :

.view-fileuploadpage > h2 {
    /* Applies to the h2 of the view FileUploadPage */
    /* DOes NOT apply to any h2 that would exist in a child view of FileUploadPage */
}

But this would make the code hard to maintain, because the selectors would have to be updated every time a piece of markup gets moved or modified within a view.

I'm having the exact same problem with JavaScript and query selectors, but I guess finding a solution for CSS would also solve the JavaScript problem.


Solution

  • You can use the :not() pseudo-class to deselect grandchildren within a particular child.

    .view-fileuploadpage h2:not(.file-drop-zone *):not(.more-children *){
      color: #f00;
      } 
    

    This assigns the color to all h2 elements excluding those in the stated classes within the :not() selector.

    The CSS file will need to be updated with the classes of new children if any.

    The best solution will be to wrap all the contents of the view-fileuploadpage or parent div that should not get the styling and use the class of this wrapper as a single selector. This way, the file will not need constant updating all future children and grandchildren are added within the wrapper.

    Hence, instead of having:

        <div class='view-fileuploadpage-one'>
          <h2>Container</h2>
          <p>...</p>
         
          <div class='file-drop-zone'>
            <h2>file drop zone</h2>
            ...
          </div>
        
          <div class='more-children'>
            <h2>More children</h2>
            ...
          </div>
       </div>
    

    You can opt for:

     <div class='view-fileuploadpage-two'>
        <h2>Container</h2>
        <p>...</p>
        <div class='content-wrapper'>
        <!--   this wrapper will contain everything else -->
          <div class='file-drop-zone'>
            ...
          </div>
    
          <div class='more-children'>
            ...
          </div>
        </div>
       </div>
      </div>
    

    Which will be more or less:

    <div class='view-fileuploadpage-two'>
        ...
      <div class='content-wrapper'>
        ...
      </div>
    </div>
    

    Kindly see my idea on this pen.