41

The webpage I'm working on already has some base stylesheets, one of which contains this rule:

address:not(:last-child), 
fieldset:not(:last-child), 
li:not(:last-child), 
ol:not(:last-child), 
p:not(:last-child), 
table:not(:last-child), 
ul:not(:last-child) {margin-bottom: 12px}

This is applying the 12px margin-bottom on my <p class="mainCopy"> tags, which I'm not interested in. I want to be able to override it with .mainCopy {margin-bottom: 0}, but obviously the base rule is more specific than my rule. This forces me to make a rule that's more specific than I want or need, such as p.mainCopy. Moreover, I sometimes need to have <li class="mainCopy">, and this would force me to add a second rule, to cater for the <li> as well.

Is there any way I can simply reset this property, or revert the problematic CSS declaration?

Peter O.
  • 32,158
  • 14
  • 82
  • 96
Liran H
  • 9,143
  • 7
  • 39
  • 52
  • One thing you can do is to have a `margin-bottom: 0;` for the overriding class. – Praveen Kumar Purushothaman Nov 16 '16 at 11:04
  • 1
    Either you can make an override class *.margin-override{margin:0} which would be more specific, or do as you say in the question and just override the one specific element. Unfortunately there is no way to revert or reset a selector. – Kyle Nov 16 '16 at 11:06
  • Not really a good approach, but you could use `!important`. – Aer0 Nov 16 '16 at 11:08
  • @Aer0 was going to say this..even created fiddle but never mind. – Leo the lion Nov 16 '16 at 11:09
  • 3
    _Never_ use !important. Or inline styles. – Kyle Nov 16 '16 at 11:09
  • @Kyle yes so last option is use inline. That's it. – Leo the lion Nov 16 '16 at 11:09
  • @Kyle about !important i know but about inline style, why?? – Leo the lion Nov 16 '16 at 11:11
  • @Leothelion Inline styles have more priority than anything. And inline styles with important are a disaster... – Praveen Kumar Purushothaman Nov 16 '16 at 11:13
  • @PraveenKumar i am just talking about inline style. And if they are available then we should use in these case where we can't use anything. we can be careful with them. For ex, knife is use to cut vegetable but can be dangerous if we miss use so doesn't matter we are not going to use knife. – Leo the lion Nov 16 '16 at 11:15
  • 1
    @Leothelion, inline styles have the highest specificity: 1,000. I recommend the following article on the topic of specificity: https://css-tricks.com/specifics-on-css-specificity/ – Liran H Nov 16 '16 at 11:17
  • @Leothelion LoL. haha... I agree with you mate. But still, inline-styles are dangerous. Don't use it. It clutters the things too. – Praveen Kumar Purushothaman Nov 16 '16 at 11:24
  • 4
    As about your exact question... Reset to what? The C in CSS stands for *cascading* and you'll always have several layers of styles combining among themselves. There's no syntax for "Create a snapshot here". – Álvaro González Nov 16 '16 at 11:25
  • @ÁlvaroGonzález, I guess you're right. I don't think there's anything better that I can do in CSS than simply override it with the same specificity or greater. – Liran H Nov 16 '16 at 11:48
  • 3
    @kyle, what about helper classes? !important is useful to ensure a property always gets applied such as float-left/float-right helper classes. Saying NEVER to use them is bad advice, but the sentiment you are trying to convey is correct. 99.9% of the time you shouldn't be using it. – ESR Nov 16 '16 at 12:38
  • @EdmundReed Helper classes are a great thing, and can be used without !important if the rest of the CSS is implemented properly. So if you have a helper class .text-red, only this class should declare color: red; Any others that override it would be missing the point of helper classes entirely. – Kyle Nov 16 '16 at 12:40
  • NEVER reset CSS styles. This would not do what you think it does. – Joshua Nov 16 '16 at 17:26
  • @ÁlvaroGonzález, I suggest you write that as your answer to this thread rather than a comment, because at the moment this is the only one I can accept. – Liran H Nov 16 '16 at 20:55
  • @Kyle Even if you do a great implementation of CSS, you may be vulnerable to external javascript files you have no control of. This way you ensure that your helper class will still have higher specificity, even if some javascript attribute modification occurs. – Ricky Ruiz Nov 16 '16 at 23:42

6 Answers6

31

Since address:not(:last-child) and similars has 11 points of specificity, you can duplicate the classname to make it stronger. For example, the following declaration is totally valid and it has 20 points of specificity:

.mainCopy.mainCopy {
     margin-bottom: 0;
}

And you must add only one mainCopy in your html:

<ul class="mainCopy">

Edit

Take care on the "points" of specificity, because there aren't decimal points. Them are number positions by the specificity. For example:

 address:not(:last-child) /* is 0-0-1-1 specificity (1 tagname, 1 pseudoclass) */
 .mainCopy.mainCopy /* is 0-0-2-0 specificity (2 classnames) */
Marcos Pérez Gude
  • 21,869
  • 4
  • 38
  • 69
  • I'm not sure I fully understand why but [it works](http://jsbin.com/jonoroweru/1/edit?html,css,output)... – Álvaro González Nov 16 '16 at 11:20
  • Thanks Marcos. Do you mean that I should wrap the elements that have `class="mainCopy"` with another element with the same class, and then in the CSS use `.mainCopy .mainCopy`? Or did you just mean that I should select the same class twice? – Liran H Nov 16 '16 at 11:21
  • @LiranH Please check my demo. There's no space in the middle of `.mainCopy.mainCopy`—simply, it matches the same elements as `.mainCopy` but assigns a higher priority. – Álvaro González Nov 16 '16 at 11:26
  • I understand what it does, but not sure how, in this instance, it's better than simply repeating the same selector as the base stylesheet's, and setting the margin-bottom to 0. – Liran H Nov 16 '16 at 11:29
  • 2
    @marcos, I've found the reason why this works. It's apparently specifically mentioned in the CSS3 spec, and as far as I understand should work in CSS2 as well. See this thread: http://stackoverflow.com/questions/11572081/css-class-repetition-to-increase-specificity – Liran H Nov 16 '16 at 12:03
  • 1
    While this works for the sample given, it's overly specific and following this practice will lead to specificity wars. Your selector should be chosen to meet the requirement needed and no more. In this case, either @Marileen's approach or an override of `.mainCopy, p.mainCopy { ... }` is probably the most appropriate, but it depends on the OP's precise requirements. – Alohci Nov 16 '16 at 12:49
  • 1
    This solution is not wrong nor a trick. Is perfect for give a high priority to a single classname. You can repeat x3 and more and it's still ok. The solution `p.mainCopy` is less performance and you can't reuse it on another tag than `p`, so you are mandatory to write one per tag. It's because I'm thinking that my solution is better. – Marcos Pérez Gude Nov 16 '16 at 14:02
  • Could you link to where a specificity-scoring algorithm is specified? I am familiar with selector specificity, but I was not aware they were scored numerically. I'd be interested in reading it. – apsillers Nov 16 '16 at 16:39
  • 1
    @apsillers there are tons along internet, you can choose what you like. Two examples: https://www.smashingmagazine.com/2007/07/css-specificity-things-you-should-know/ || https://css-tricks.com/specifics-on-css-specificity/ || And a Calculator: https://specificity.keegan.st/ – Marcos Pérez Gude Nov 16 '16 at 16:45
  • 2
    Thanks! From the links you supplied, I found the W3 specification: https://www.w3.org/TR/selectors/#specificity. – apsillers Nov 16 '16 at 16:48
  • This will have same specificity `.mustHaveMargin .mainCopy` in which case the winner is determined by source order. – Salman A Nov 16 '16 at 18:21
15

There exists the following property:

all: unset;

Which I believe can be used like so:

.mainCopy {
    all: unset;
    margin-bottom: 0
}

https://developer.mozilla.org/en/docs/Web/CSS/unset

EDIT: Actually I believe due to the specificity of your specific problem this may not work.

ESR
  • 1,669
  • 1
  • 18
  • 22
13

To answer your question (rather than solving your problem)...

Can I reset a CSS property rather than overriding it?

Reset to what?

The C in CSS stands for cascading and you'll always have several layers of styles combining among themselves with precisely defined though not always immediately clear rules. Apart from the styles set by the site author in different places (external CSS files, <style> blocks, style="" attributes...), in the base line we'll find the builtin browser styles and as far as I know browser vendors are free to assign whatever default styles they choose—and often users can add their own styles to the soup, either with builtin settings or with add-ons. Even the so called CSS resets don't actually reset anything. They merely add yet another layer of styles on top of the rest.

There's no syntax for "Create a snapshot here" (which would be the only solution I can think of without a thorough analysis) so the answer is basically no.

Álvaro González
  • 142,137
  • 41
  • 261
  • 360
6

You can add another :not rule to all selectors where you want to exclude .mainCopy to have the margin

address:not(:last-child):not(.mainCopy), 
fieldset:not(:last-child):not(.mainCopy), 
li:not(:last-child):not(.mainCopy), 
ol:not(:last-child):not(.mainCopy), 
p:not(:last-child):not(.mainCopy), 
table:not(:last-child):not(.mainCopy), 
ul:not(:last-child):not(.mainCopy) {
  margin-bottom: 12px
}
Marileen
  • 179
  • 1
  • 6
  • 1
    Thanks, but I believe this wouldn't help, as it would not override the base rule, but rather just be additional to it. – Liran H Nov 16 '16 at 11:36
  • 1
    @LiranH The idea is that you *replace* your base rule with this, thereby making sure your base rule already doesn't apply to `.mainCopy`. If the base rule isn't applied, the problem of resetting the base rule is solved: there's nothing that needs to be reset. –  Nov 16 '16 at 23:01
  • @hvd Sorry, I might have forgotten to mention: I do not own the base stylesheet, and so cannot make any changes to it. This would otherwise be a good solution - thank you, Marileen. – Liran H Nov 17 '16 at 22:04
2

Use the universal selector * preceded by body tag.

body *.[<'className'>] {}

Or simply precede your class with the body tag.

body .[<'className'>] {}

Both are actually the same, use the one that you see fit and/or easier to spot for maintenance.


address:not(:last-child),
fieldset:not(:last-child),
li:not(:last-child),
ol:not(:last-child),
p:not(:last-child),
table:not(:last-child),
ul:not(:last-child) {
  margin-bottom: 12px;
  color: red;
}
body *.mainCopy {
  margin-bottom: 0;
  color: green;
}
<main>
  <p class="mainCopy">p</p>
  <p>p</p>
  <ul>
    <li class="mainCopy">
      li
    </li>
    <li>
      li
    </li>
  </ul>
  <code>body *.mainCopy {}</code>
</main>

If you're paranoid, you can even use:

html .[<'className'>] {}

address:not(:last-child),
fieldset:not(:last-child),
li:not(:last-child),
ol:not(:last-child),
p:not(:last-child),
table:not(:last-child),
ul:not(:last-child) {
  margin-bottom: 12px;
  color: red;
}
html .mainCopy {
  margin-bottom: 0;
  color: green;
}
<main>
  <p class="mainCopy">p</p>
  <p>p</p>
  <ul>
    <li class="mainCopy">
      li
    </li>
    <li>
      li
    </li>
  </ul>
  <code>html .mainCopy {}</code>
</main>
Ricky Ruiz
  • 25,455
  • 6
  • 44
  • 53
  • 2
    Thanks Ricky. I am familiar with this solution (just forgot to mention it), but was looking for a solution that would prevent me from having to be more specific than ".mainCopy" in my selectors. – Liran H Nov 17 '16 at 21:57
1

I tend to go with initial as a property value.

address:not(:last-child), 
fieldset:not(:last-child), 
li:not(:last-child), 
ol:not(:last-child), 
p:not(:last-child), 
table:not(:last-child), 
ul:not(:last-child) {margin-bottom: initial}
AGDM
  • 104
  • 1
  • 6
  • I was just annoy to post this answer! Note that, IIRC, this is non-standard and only available on WebKit- and Blink-based browsers – Ky - Nov 23 '16 at 11:40
  • @Supuhstar this is true. I found out IE doesn't like `initial`. Fun. But then again, I really don't care for IE. – AGDM Mar 14 '18 at 18:59
  • IE could definitely be better. Must be a business reason why they are so unique. – AGDM Nov 17 '19 at 15:56
  • 1
    Also worth adding that, in the time since this question was asked, [`initial` is now standard](https://developer.mozilla.org/en-US/docs/Web/CSS/initial) – Ky - Nov 17 '19 at 19:15
  • I wish I were as blessed as you to not know why IE is so different. https://en.m.wikipedia.org/wiki/Embrace%2C_extend%2C_and_extinguish?wprov=sfla1 – Ky - Nov 17 '19 at 19:15
  • Great article share. That pretty much sums M$ up. – AGDM Nov 22 '19 at 01:23