I'm re-evaluating the effectiveness of my CSS design choices after reading about SMACSS.
One of the conflicts I've examined is:
<button class="cool-text button"></button>
Semantics aside, the object in question has two classes which do not extend each other in anyway. Now, if the CSS were:
.cool-text {
background-color: black; // want this
color: green; // don't want this
font-size: 16px;
text-shadow: 0 1px 0 yellow;
}
.button {
background-color: white; // don't want this
border: 1px solid;
border-radius: 4px;
color: #eee; // want this
}
Once again, this is not an ideal example. I was wondering, what if I wanted the background-color from .cool-text and the color from .button. In a programming language, an object can have two classes, and you can specify how to resolve conflicts in method names. I guess similarly, I could specify .cool-text.button, but I would have to re-write the properties, which seems very bad.
.cool-text.button {
background-color: black;
color: #eee;
}
Are there any workarounds using SCSS?
Also, is it a bad idea to rely on the positions of the classes within the class attribute (in vanilla CSS). Classes that are specified first have higher priority, for instance:
<button class="green-button button"></button>
In this example, .green-button has higher precedence.
This seems to add CSS specificity to HTML. What if there were lots of classes, you would have to spend time figuring out which ones should go first and that seems very counter-intuitive.
Per Quentin, it's determined by the order within CSS.
It all depends on the rule specificity and order.
Your solution makes perfect sense to me, because your original idea is not ideal (taking x from class1 and y from class2, yet the classes are parallel). However, if you end up writing too many of those exception rules, like:
.cool-text.button {
background-color: black;
color: #eee;
}
it means something's not quite right with your design. Why simply not design a cool-button class then? If your .button is meant to be one of the base classes, put it on the top of the CSS file, let the other (more specific) classes override it easily.
Also, please refrain from using !important unless absolutely necessary.
See this nice specificity calculator: http://specificity.keegan.st/
Related
One of the things I find hard to work with in CSS is how rules mix layout (ie: position, sizing) and look and feel (color, shadows, fonts, etc.).
We're working in a 'reskin' project, where we want to keep the layout of our solution, but change the look and feel. To this end I'm thinking of splitting the current styles in two: one stylesheet for layout and the other for skin, and then replace the latter with the new, reskinned one.
Just to illustrate my point. A current CSS rule could look like this:
Styles.css:
.my-class {
/* layout rules */
width: 100px;
height: 50px;
float: left;
/* look and feel rules */
border: 1px solid red;
font-weight: bold;
}
My idea would be to split this into 2 individual rules, in 2 files:
Layout.css:
.my-class {
width: 100px;
height: 50px;
float: left;
}
Skin.css: (could be replaced with a different 'skin' file)
.my-class {
border: 1px solid red;
font-weight: bold;
}
Is there any reason why this would not work? Does this have any drawbacks (other than the increased page load time?)
If you have a clear way of separating the CSS you can do it this way. In our company it is separated the same way, you just have to pay attention when adding new CSS so you don't mix it up.
There is no increase in page load time, when you use PHP to merge the files together and minimize it when the user visits your website.
Check out this link, there is an explanation on how to combine and minify CSS with PHP.
Consider the following CSS stylesheet:
#start_experiment_button
{
display: inline-block;
color: black;
border: 3px outset gray;
background-color: #CCCCCC;
padding: 8px;
text-decoration: none;
font-family: Arial, Helvetica;
font-weight: bold;
}
#start_experiment_button:hover
{
border: 3px inset gray;
}
#start_experiment_button:active
{
border: 3px inset gray;
}
#start_experiment_button
{
display: none;
}
Notice that the display property of #start_experiment_button is defined twice. Does this serve a purpose? Does the second definition simply over-ride the first, such that the first need not have been written at all? Or do the intervening definitions for hover and active somehow influence when the two display values take effect?
The last rule
#start_experiment_button {
display: none;
}
overrides the first one. Hence the element is not shown at all. Because the element is invisible both :hover and :active are not applied.
Note that as more specific the selector as higher priority the rule has. So if the element was visible the rules defined by the selectors #start_experiment_button:hover and #start_experiment_button:active would have higher priority then the rule defined by #start_experiment_button.
Does the second definition simply over-ride the first, such that the first need not have been written at all?
Yes, and only for the display property. The other properties are unaffected.
Or do the intervening definitions for hover and active somehow influence when the two display values take effect?
No, they don't, because neither of those rules have their own display declarations, and even if they did, those states would be impossible to reach because the element is never rendered.
It's not clear why that last rule exists and why it appears in that spot unguarded by either a media query or a more qualified selector, because with its display: none declaration, it makes all the other three rules redundant by preventing the element from ever being rendered.
Yes it will override..
#start_experiment_button
{
display: none;
}
This code will override your first code, as the code reads from first line to the last while its executed.. hope you got your answer..
i am kinda new to LESS, but already can see it's huge power of building huge design frameworks / systems.
I'll try to reduce my question as simple as i can, and hopefully i will got lucky with some help!
So, let's say i have build Framework (something like Bootstrap 3), that have a lot of own components, which have their own rules, variables to base etc. And than i have theme which of course can overwrite those variables to change style.
But what if i need to add some specific rules, which haven't been presented before?
// FRAMEWORK
#btn-font-size: 12px;
#btn-line-height: 1;
#btn-border: 3px;
.some-component .menu > .btn {
font-size: #btn-font-size;
line-height: #btn-line-height;
border: #btn-border solid transparent;
}
// HERE STARTS MY THEME
#btn-font-size: 16px;
#btn-border: 6px;
.some-component .menu > .btn {
margin-bottom: 12px;
letter-spacing: 0.3px;
background: #FFFFFF;
}
And you would ask, so what's the problem here? You should just get what you want with this approach.
But problem lays in my intention to build optimized code, which would be lot less in size, more readable, logical and won't ruin some of dependencies (so for some complex components i won't have to do some additional edits, just to add few things).
In plain simple words, i want it to compile like that:
// FRAMEWORK
.some-component .menu > .btn {
font-size: 16px;
line-height: 1;
border: 6px solid transparent;
margin-bottom: 12px;
letter-spacing: 0.3px;
background: #FFFFFF;
}
So the idea is to extend framework, not to overwrite classes.
To do so i was trying all kinds of mixins, extends, variables with rulsets etc, which ain't seem to help or to be enough specific.
Any ideas would be greatly appreciated, because there seem to be no native LESS solution, but maybe some tricks?)
Also see: How to keep duplicate properties in compiled CSS file when use LESS?
Since Less v2 you should use the Less Clean CSS plugin to compress the css output from Less using clean-css.
Clean-css will merge your properties automatically.
Compiling your code with lessc --clean-css code.less outputs:
.some-component .menu>.btn{font-size:16px;line-height:1;border:6px solid transparent;margin-bottom:12px;letter-spacing:.3px;background:FFFFFF}
A basic CSS example. Every browser I have come across will render the item with the margin & padding and a red border
.test{
margin: 4px;
border: 1px solid black;
padding: 4px;
}
.test{
border: 1px solid red;
}
Naturally if I was writing this CSS by hand I would replace the black with red and only have one rule.
But If the first rule comes from a parent CSS file (or in my case a LESS file) that I can't edit because it is used elsewhere, or is from a 3rd party library that I don't want to hack then I see no alternative but to add an extra rule.
Now since I am using server side LESS -> CSS compilation with minification, it seems perfectly reasonable to me that the compressor/minifier should reduce the rules down to just
.test{
margin: 4px;
border: 1px solid red;
padding: 4px;
}
But everything I have tried, keeps both rules; some of the compressor/minifiers go as far as removing newlines
.test{margin:4px;border:1px solid black;padding:4px}.test{border:1px solid red}
It strips out a single newline character but left an entirely unnecessary rule declaration in. This seems bizarre to me.
Is there any system than can do this? (preferably an add on for node.js) If not, do we know why not? Seems like quite a big file size saving with no downside to me.
disclaimer I have tried searching for combining selectors, merging selectors and few variations, apologies if I have missed the common term for this procedure, seems likely since the gains just seem so obvious I have to be missing something!
Why It Cannot and Should Not Be Done
You state:
Every browser I have come across will render the
item with the margin & padding and a red border.
That is because, of course, the cascading nature of CSS. It is designed to work like that for the express purpose of overriding. Which is exactly the point of why (and how) you "add an extra rule" in your CSS to override.
There is a Reason
Now, I can see your point in a preprocessor perhaps "merging" code with the same selector for minimization purposes. However, (1) there would be a rare (if ever) case where the two classes would actually follow one right after the other in the CSS code, as your example shows (and in such a case, minimization would be okay). Usually there is going to be intervening CSS that can affect how the cascade might play out in rendering. Which leads to (2), it would require more logic than is initially obvious (or even possible) to implement. Consider this example:
HTML
<div class="test1 test2"></div>
CSS (Framework File)
.test1 {
margin: 4px;
border: 1px solid black;
padding: 4px;
}
.test2 {
border: 1px solid blue;
}
CSS (Developer File)
.test1 {
border: 1px solid red;
}
The above code if output as normal should render a red border by the cascade, just as the developer wants. Now suppose LESS or another preprocessor does minify it as you desire. It could end up like this:
Theoretical Minimization
.test1 {
margin: 4px;
border: 1px solid red;
padding: 4px;
}
.test2 {
border: 1px solid blue;
}
And would in fact render as blue not as red! This is because the two .test1 merged, now making the .test2 last in the cascade order rather than the second instance of .test1 being last. So a preprocessor would have to be "smart" enough to figure out a theoretically infinite number of possible cascade combinations, and that without knowing what the html coding is that ultimately influences the decision (like here, where the html double classes in conjunction with the cascade order is what is determining the final rendering).
Had the preprocessor merged into the second instance, that does not solve the problem, as what if developer had put a second instance of .test2 after the second instance of .test1, but did not define a different border color? The .test2 border color would still have overridden by merging with the following .test2.
This illustration should show why such a minimization cannot and should not be done--the interactive logic between possible html form and CSS cascade is impossible to predict what or how to merge except in a case were two exact selector strings in the CSS immediately followed one another. Any other case could make a wrong decision.
Question: Is the second OOCSS principle really valid?
According to the OOCSS second principle you're not supposed to have location dependent styles:
Quote from https://github.com/stubbornella/oocss/wiki
Essentially, this means “rarely use location-dependent styles”. An object should look the same no matter where you put it. So instead of styling a specific h2 with .myObject h2 {...}, create and apply a class that describes the h2 in question, like h2 class="category".
Lets take a practical example of this. Say I have a standard 2.0 setup with a normal body (white background) and a huge footer (black background). In the body we have black links and in the footer of course we need white. Isn't the simplest and most intuitive way to achieve this simply to:
a{ color: #000; }
.footer a{ color: #FFF; }
If I where to follow OOCSS principles I'd have to first create a class:
.inverted{ color: #FFF; }
Then proceed to add that class to every link I want inverted. That seems like a hassle.
Isn't the purpose of the whole language that styles are made to Cascade?
Am I misunderstanding something here?
I think you are right in the sense that yes, in your specific example.. perhaps doing it your way would be easier. But then again, if you look at the first sentence in the OOCSS page:
How do you scale CSS for thousands of pages?
In that context.. the second principle makes perfect sense.. so using your same example (ie let's assume we implemented your solution).. let's say that a year down the road your company decides to create light grey buttons in the black footer having black text:
<!-- inside footer -->
<a class="button lightGrey">link</a>
in this case.. all the a tags will be white because they're covered by your cascading. So then we will have to go create another sytle just to undo what your solution did:
.footer a.button.lightGrey {
color: #000; /* huh? but i thought we did this before with a {color: #000;} ?*/
}
where as if we simply made a decision that all a tags by default are black (see last note):
a{ color: #000; }
then in the footer we will create a special type of link that are supposed to be white:
.footerLinks { color: #FFF }
then a year later some of the links are still white.. others within the greyLight button will be black:
<a class="button lightGrey">link</a>
then here we don't have to worry about undoing anything.. a tags have a default color.. and that's it. if 2 years later someone decides that the links inside the lightGrey buttons (anywhere on the site, not only withen the footer.. which is the whole point of OOCSS) should be red.. then this would be the OOCSS approach:
.redLink {
color: red;
}
and the html will be
<a class="button lightGrey redLink">link</a>
in this case it won't matter if we take out the .lightGrey class, or we can have this code within or not within a footer .. it's all the same.. it results in more predictable and re-usable code.. which is OOCSS (I'm very glad that they're finally formalising this.. thanks a lot for the post btw).
One last note: To be pure OOCSS, one shouldn't change the default color of a ie a {color: #000;} is wrong!, it should be left to it's default color (which is blue).. whenever anyone wants to change that color.. then they must specify it ie
<a class="redLink">..</a>
so in this case it's more like the default a is the parent class.. and everything else subclasses it and overrides its default behaviour..
update - response to comments:
reputable site argument:
such initiatives are almost always driven by the community then adopted by reputable companies.. and even when they are adopted by larger companies it usually happens from the bottom up through enthusiastic developers who advocate for such change.. I for one was such an advocate when I was working in Amazon. And even when it's adopted.. it's usually at a small scale and not across all units in the org. it wouldn't even be a good idea for the Googles and the Amazons and the facebooks etc to enforce such a rule b/c there will always be a difference of opinion.. not to mention that such micromanagement would constrain the engineer's creativity.. there could be a guideline in a wiki for a team (ie we had one for the Amazon Kindle Touch app store) but to enforce that rule across 10,000 engineers working across the company wouldn't be practical nor desirable.
So in short if you see value in OOCSS, and start implementing on your site, and advocating it to your fellow web devs, and then it becomes a trend, that's when it eventually becomes an industry wide best practice and that's when you can expect to see it on facebook etc.
example:
take a look at this:
simple: http://jsfiddle.net/64sBg/
a bit more detailed: http://jsfiddle.net/64sBg/2/
without going too much detail (I'm sure you will see the pattern) you can see that the granularity in css descriptions allows for subtle changes without any redundancy in style definition. So notice the left arrow vs right arrow.. also the .red and .blue styles can be subsequently applied to tables etc..
also notice that there isn't a single cascading in my css.. so my styles can be completely independently applied (ie implementing the rule An object should look the same no matter where you put it)
lastly.. there is still use for cascading.. you can definitely use it in your jQuery selectors for example.. also cascading happens by default (ie without you having to explicitly set it in your css styles).. so if you take look at the css below.. you will notice that the font properties of body has cascaded down to all the buttons.
<a class="button blue dark">
<div class=" arrowDownWhite rightArrow">Analytics</div>
</a>
<a class="button red dark">
<div class=" arrowDownWhite leftArrow">Actions</div>
</a>
<a class="button grey light">
<div class=" arrowDownRed leftArrow">options</div>
</a>
and css:
body
{
font-family: Trebuchet MS,Liberation Sans,DejaVu Sans,sans-serif;
font-size: 15pt;
}
.button
{
padding: .5em 1em;
display: inline-block;
text-decoration: none;
}
.dark {
color: white;
}
.light{
color: #E40E62;
}
.blue
{
background-color: #51C8E8;
}
.red
{
background-color: #E40E62;
}
.grey
{
background-color: #E0E0E0 ;
}
.arrowDownWhite
{
background-image:url(http://s2.postimage.org/ywam7ec4l/small_Arrow_Down_White.png);
background-repeat:no-repeat;
}
.arrowDownRed
{
background-image:url(http://s2.postimage.org/je5743t2d/small_Arrow_Down_Red.png);
background-repeat:no-repeat;
}
.leftArrow
{
padding-left: 1em;
background-position: left center;
}
.rightArrow
{
padding-right: 1em;
background-position: right center;
}
It is worth the hassle of separating your skin from the container.
Lets look beyond colors. I wish Nicole Sullivan provided better examples than she does. I have 23 web sites that an contain
Menus
Tabs
Toolbars
Horizontal and Vertical Lists of Links
All of them are Skins of the Nav abstraction
I started off created an abstraction class to handle the common code between all of them. I added a few modifiers to change the orientation from horizontal to vertical, and also the floated position of it. I kept all colors out of the abstraction as well as css rules that can change based on the skin I apply to it.
/* Object */
.nav
{
margin-bottom: 1.5em; margin-left: 0; padding-left: 0; list-style: none;
}
/* Modifier */
.nav--stack .nav__item
{
display: block;
}
.nav--right
{
float: right;
}
/* Elements */
.nav__item
{
float:left
}
.nav__item__link
{
display:none;
}
Menu Skin
I needed a skin that made the .nav abstraction look like a sidebar menu. In case you are wondering, I did not put the padding for .nav_item_link above is because it can change based on the skin. The tabs skin has it set for 2px.
/* Object */
.menu
{
}
/* Elements */
.menu .nav__item--current.nav__item__link
{
color: #fff; background: blue;
}
.menu .nav__item__link
{
padding: 4px; border-radius: 4px;
}
.menu .nav__item__link:hover
{
background: #eee
}
Notice to keep things location-independent - I have 0 tag names. I don't style li and a children on .nav like bootstrap does. This code could be used on dls or even divs and has better performance based on how selector engines read rules.
To me the benefit of just having to skin the objects I have for all 23 sites I have is worth any hassle.