7

I am building a widget that will be displayed on a client's site. We cannot use an iFrame so I am forced to use an exhaustive CSS reset (https://github.com/premasagar/cleanslate) to avoid interference with their styles. To use that solution, I need to add !important to all of my styles and because there are a lot of them and I want to keep this code easy to maintain, I'm looking for a more dynamic solution.

I am able to add !important to the stylesheet via javascript but that's not ideal for a production environment. I am using CodeKit and LESS and wondering if either of these are able to help me easily add !important to all styles when the CSS file is generated.

Mixin? CodeKit config?

Ryan
  • 2,747
  • 2
  • 22
  • 16
  • For overriding styles I would recommend adding a class to the tag and then use that class to override styles as needed. – khollenbeck Jan 07 '13 at 17:43
  • I'm already wrapping my widget with a class and using that for styling but that doesn't stop the clients CSS from interfering with mine if they set something I'm not accounting for. – Ryan Jan 07 '13 at 19:45
  • Maybe I am not following what you are saying. But I don't see how their styles could override yours if you are using the highest level css selector. Unless they have a selector set on the tag as well. You should be able to make your own stylesheet and override all of their pre-existing styles with your own selector. – khollenbeck Jan 07 '13 at 20:13
  • What you're saying is correct. However, it's overriding the unknowns that is the trouble. While their CSS can not change any styles I have explicitly set, they could add styles that I'm not accounting for. (e.g. if they set a border on

    and I don't set a border to reset that, my

    's will all have borders)

    – Ryan Jan 07 '13 at 20:26
  • @KrisHollenbeck: Your logic is not wholly correct. [Specificity](http://stackoverflow.com/questions/3311629/why-is-the-selector-of-lesser-specificity-than-anything/3311930#3311930) has little to do with whether a class is on the `body` or not. `.bodyClass div` will not override `.someLowerWrapperClass div` unless the `.bodyClass div` occurs _after_ the other selector (and thus overrides by the cascade order). – ScottS Jan 07 '13 at 20:40
  • Ryan, Okay I see what you are saying.I haven't used LESS but I have used SASS which is similar to LESS. I am sure you could create a @mixin that adds !important to certain selectors. However the problem would be determining which css property to add them to. That part would be tricky. – khollenbeck Jan 07 '13 at 20:51

2 Answers2

11

Update: Yes, LESS Can Help

I hate using !important except in the most extreme circumstances. Most people use it like a chainsaw when they should be using a scalpal to do the job. Nevertheless, I understand the issues facing widget developers like yourself, and your choice to use https://github.com/premasagar/cleanslate leaves you with no option.

Marc's answer noted a good feature of LESS, but he failed to demonstrate how that can help in this matter.

If you wrap your entire LESS code in a namespaced mixin, then this feature does exactly what is needed. So assume your widget code looked like this (you mentioned you are already using some type of class for your widget):

.yourWidgetClass div > p {
  prop: something;
  &:hover {
    prop: some-hover-style;
  }
}

.yourWidgetClass .someClass {
  prop: something;
}

Then you can do this (wrapping all your widget code in #makeImportant() then calling that mixin with the !important feature noted in Marc's answer):

#makeImportant() {
    .yourWidgetClass div > p {
      prop: something;
      &:hover {
        prop: some-hover-style;
      }
    }

    .yourWidgetClass .someClass {
      prop: something;
    }
}

& {
    #makeImportant() !important;
}

This produces the following CSS Output:

.yourWidgetClass div > p {
  prop: something !important;
}
.yourWidgetClass div > p:hover {
  prop: some-hover-style !important;
}
.yourWidgetClass .someClass {
  prop: something !important;
}

For my original (accepted) answer that was way more manually intensive, see the edit history.

Community
  • 1
  • 1
ScottS
  • 71,703
  • 13
  • 126
  • 146
  • Thanks for the details answer. I decided that I needed to approach this differently... and we ended up going with an iFrame to eliminate these hassles (plus jQuery namespacing, etc). – Ryan Jan 08 '13 at 22:49
2

I found that LESS can mark all properties set by a mixin at once as !important when specify !important after the mix-in call.

  .someMixin() {
    background-color: #fff;
    cursor: pointer;
  }

  .someUsages {
    .someMixin() !important;
  }

Results in:

  .someUsages {
    background-color: #fff !important;
    cursor: pointer !important;
  }

For more information on this topic see the LESS doc about "The !important keyword".

Marc
  • 4,715
  • 3
  • 27
  • 34