I've been educating myself. Reading this:
The engine evaluates each rule from right to left, starting from the rightmost selector (called the "key") and moving through each selector until it finds a match or discards the rule. (The "selector" is the document element to which the rule should apply.)
For example:
ul li a {...}
#footer h3 {...}
* html #atticPromo ul li a {...]
Now, some example code SASS outputs for me:
#content #blog {
/* ... */
}
/* line 85, ../sass/screen.scss */
#content #flickr {
/* ... */
}
#content #flickr div p {
/* ... */
}
This seems a bit awkward.. am I doing something wrong? Is this a communication problem between me and Sass? Are we losing it?
Edit:
Some SCSS code:
#flickr {
#include columns(5,8);
background: url('../img/ipadbg.png') no-repeat;
#ipod-gloss {
z-index: 999;
position: relative;
}
div {
margin-top: -80px;
margin-right: 20px;
h2 {
color: $white;
font-size: 24px;
}
p {
margin-top: 40px;
}
}
}
Side Bonus!: The article says browsers (or at least Firefox) search the selectors from right to left. I couldn't understand why this is a more efficient why. Any clues?
You have to find your compromise between maintainability (nesting makes it easier to find your way around in the stylesheet) and rendering performance.
A rule of thumb says you should try to restrict yourself to a three-level nesting and you should avoid to nest IDs if it's not necessary.
However, I think nesting too much is not the biggest issue. As soon as I became aware of the power of mixins, I used them a lot.
For example, this is my often used button mixin:
#mixin small-button($active-color: $active-color, $hover-color: $button-hover-color, $shadow: true)
display: inline-block
padding: 4px 10px
margin:
right: 10px
bottom: 10px
border: none
background-color: $button-color
color: $font-color-inv
+sans-serif-font(9px, 700)
text-align: center
text-transform: uppercase
cursor: pointer
#if $shadow
+light-shadow
&:hover
text-decoration: none
background-color: $hover-color
&:last-child
margin-right: 0
a
color: $font-color-inv
&, &:hover
text-decoration: none
&.disabled
+opacity(0.75)
&:hover
background-color: $button-color
&.active
background-color: $active-color
&.disabled:hover
background-color: $active-color
You see, quite a bit code. Applying such mixins to many elements on your page will result in a big CSS file which takes longer to be interpreted.
In the old fashioned CSS-way you would give each button element e.g. the class .small-button. But this method pollutes your markup with unsemantic classes.
Sass provides a solution though: selector inheritance via the #extend directive.
If you set defaults for your parameter of the mixin, you can also provide a simple class, which uses the mixins with your default:
// Use this mixin via #extend if you are fine with the parameter defaults
.small-button
+small-button
And then you can just inherit from this class in various contexts:
#admin-interface
input[type=submit]
#extend .small-button
The resulting CSS statement aggregates all usages of .small button into one rule with comma-separated selectors:
.small-button, #admin-interface input[type=submit] {
display: inline-block;
...
}
Concluding, a naive usage of Sass can effect your CSS performance. Used wisely, however, it is maintainable thanks to well-structured and DRY code, it leads to proper separation of markup and styling (semantic classes only) and allows for smart and performant CSS code.
SASS is only a language that compiles down to CSS. If you're concerned with SASS' performance in terms of how it runs in the browser, then SASS doesn't enter the equation -- it'll be compiled and served to the browser as regular CSS.
From what I can see of your usage of SASS, there's a couple of things I could suggest:
You don't have to nest everything.
The ability to nest rules inside each-other in SASS is a language feature, but you don't have to do it if it doesn't make sense to do so.
In terms of your general CSS usage:
If the nesting gets too severe/unwieldly, consider using classes where it makes sense.
When it's necessary to use the hierarchy of DOM elements, consider using the [child combinator]: .foo > .bar.
IDs are meant to be unique, thus should always only reference a single element. Most of the time, they can be CSS rules unto themselves -- #content #flickr would become just #flickr, for instance -- and browsers will optimise the lookup for a single ID. The only time you would need something like #id1 #id2 is if #id2 needs to appear in different contexts on different pages.
If your selector contains things like #id div p, that div is either superfluous or serving a specific purpose.
If it's superfluous, change the rule to #id p, which selects any <p> that occurs as a descendant of #id.
If it serves a specific purpose, consider classing the <div> with a class name that describes its purpose -- perhaps <div class="photos-list">. Then your CSS could become .photos-list p, which is far more maintainable and reusable.
Related
Whats the best way of dealing with small variations in CSS?
For instance say if I have two buttons:
.btn-red .btn-blue
And I want each of the buttons next to one another but I want .btn-blue to have margin-left of 10 pixels.
I have a number of options that I could implement:
I could add an inline style to the .btn-blue element (but then you have issues of maintainability and readability if your conforming to a naming convention like BEM).
I could create a utility class that adds 10 pixels of margin (but then I'm falling into the trap of potentially having many one off utility classes, how about if I want an additional 20 pixels of margin on another item?)
I could extend .btn-blue and apply a different class (but that creates near enough the same problems as having a one-off utility class)
I could add 10 pixels directly to the .btn-green class but that conflicts with the Single Responsibility Principle.
I could target a wrapper class and using a descendent selector target .btn-blue but then I negate the usefulness of using something like BEM and fall into the world of specificity.
I realise the questions rather pedantic but this is one of the key issues as my CSS files grow that typically spirals out of control.
Say if I had the following...
SASS:
.btn {
padding: 10px 30px;
font-size: 16px;
border-radius: 3px;
border: none;
}
.btn-red,
.btn-blue {
#extend .btn;
color: white;
}
.btn-red {
background: red;
}
.btn-blue {
background: blue;
}
HTML:
<div class="btn-wrap">
<button class="btn-red">
Mr Red
</button>
<button class="btn-blue">
Mr Blue
</button>
</div>
I am honestly not quite certain about what you're trying to achieve, but could something like this help?
.btn-red + .btn-blue { /* Or [class*="btn-"] + [class*="btn-"], maybe */
margin-left: 10px;
}
I have a button that is displayed in a lot of pages of my website (With an automated javascript Widget).
I want this CSS :
.app.programEditor .col-2 .actions .widget.bt-flat.programs > .bt-flat-icon {
}
to be applied, and not this one :
.app.programEditor .actions .widget.bt-flat > .bt-flat-icon {
left: 145px !important;
top: 19px !important;
But instead, what happens, is the two css are applied, and as a result I get the second element that overwrites what I want to do with the first CSS ( A blank css with no rules )
Please I really need your help
The root cause of your problem is the poorly written rule that uses !important. This is an excellent example of why not to use !important. If at all possible, try to understand why !important was thought to be needed there, and see if you can remove it.
But if you are left fighting against an important rule, your only choice is to fight fire with fire, and toss back an !important of your own, in a rule designed to take precedence either because it is more specific (in this case, your override rule has seven classes, to the original rules's six, so it is more specific), putting it later in the file if it has the same specificity, or if you have no other choice use the various tricks available to jack up the specificity.
Having said that, overall this CSS seems to be poorly structured, verbose, and inefficient.
.app.programEditor .actions .widget.bt-flat > .bt-flat-icon {
First, if .app is a class applied to your entire application, it is probably not necessary. If .actions only occurs within .app.programEditor, then the latter is not necessary at all. If .bt-flat can only apply to widgets, then instead of widget.bt-flat you can just write .bt-flat. If .bt-flat-icon can only occur within .bt-flat, as seems likely, then .widget.bt-flat may not be necessary. And so on. In general, instead of writing down every single class in the HTML hierarchy in your CSS rules, try to limit selectors to those necessary to unique select the element you want. In this case, for example, it is possible your rule could be written as simply as (just an example):
.programEditor .actions .widget > .bt-flat-icon {
Second, the magic numbers 145 and 19 are a massive code smell. They are probably connected to other magic widths and heights elsewhere in the CSS, and would have to be changed if those change. What do the 145 and 19 mean? Perhaps they are actually a percentage of some underlying dimension. In other words, maybe some element is 160 pixels wide, and we want to place the icon to the upper right. In that case, instead of hard-wiring the 145, you can either use a percentage, or specify a right property, or use the transform property perhaps, so no matter how the width changes--such as with the introduction of .col2--the icon remains in the right place with the original rule.
You can simply change it to position:static this is just a demo. Otherwise, if you understand concept of Specificity very well, then there was no need for this question.
$('#change').click(function() {
$('.one').css("position", "static");
$('.one').text("Position changed to Static")
});
.container {
width: 90%;
margin: 50px auto;
position: relative;
border: 1px solid #000;
display: block;
height: 200px;
overflow: hidden;
}
.one {
width: 150px;
height: 150px;
background: tomato;
position: absolute;
left: 118px!important;
top: 30px!important;
display: block;
color:white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div class="container">
<div class="one">
Positioned using absolute or relative</div>
</div>
<button id="change">Change CSS</button>
If many rules exist, the first one takes precedence, but if the last one is more specific, it will override the first one. BUT if the first one is less specific AND has !important that one will take precedence. :) To make matters more complicated, if both rules has !important the most specific rule will take precedence.
So the easy solution here, if you cannot change the already existing rule, just add !important to the code you can edit. If that doesn't work, try to get your code processed earlier in the code than the other one.
.app.programEditor .col-2 .actions .widget.bt-flat.programs > .bt-flat-icon {
left: 40px !important;
top: 40px !important;
}
I'm learning CSS and I have the result I want but only if I use the ! important; specification. I don't understand why I can't override a property inheriting one class and overriding a property.
form button.minor-action,
#profile-left a.action,
.minor-action {
display: inline-block;
background: #lightBlue;
color: white;
padding: 0 1.2em;
border-radius: 4px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
-ms-border-radius: 4px;
text-decoration: none;
text-align: center;
font-weight: bold;
border: none;
height: 25px;
margin-top:1.0em;
line-height:25px;
white-space: nowrap;
&:visited {
color: white;
}
&:hover, &:active, &:focus {
background-color: darken(#lightBlue, 10%);
text-decoration: none;
}
&.call-to-action {
background-color: #pink;
&:hover, &:active, &:focus {
background-color: darken(#pink, 10%);
text-decoration: none;
}
}
}
.extra-questions {
margin-top: 0em !important;
}
I thought that if I use the above style for a button:
<button id="add_question" class="extra-questions minor-action">{% trans "Lägg till ny" %}</button>
then I wouldn't have to use the ! important; statement and the override would work without it, but it doesn't. What am I missing? can you please help me understand why it doesn't work without the ! important statement, or show me a way do to it without ! important; ?
Its is not entirely correct that it isnt overridden because its set in the class above, in this instance it isnt due to the order of your LESS - it isnt being overridden because you have listed your classes in the wrong order- instead of
extra-questions minor-action
You need to do
minor-action extra-questions
When denoting classes, if they share values for the same property settings- those values for the last class applied will take precedence.
Alternatively, you can add more specificity to your classes, in your LESS, nest extra-questions within minor-action and prefix with &. This will mean the order of classes in your HTML does not matter, the combination does. The output CSS will be:
.minor-action.extra-questions
Also, as I am sure you are aware, using !important should be avoided
Your example works without !important - http://jsfiddle.net/sgguap7v/
It does not work !important without that case -
1. The rule is to follow the class - .extra-questions {} .minor-action {}
2. The rule has a higher weight - button.minor-action {} It has a greater weight than .minor-action {}
The css rule are applied depending on the order you call them, and the more specific they are.
if you have 2 rules defining the margin-top The browser then have to decide which one to apply. To do that it read your css file from top to bottom and calculate the priority of each rules based on the following.
Priority 1: #id (Id are unique selector so very important)
Priority 2: .class (Then the class they are less important than ID but still )
Priority 3: element (Finally generic style that is overridden most of the time, this is your default style)
Each time you add a nested selector it add to the priority as well so:
body.class is more important than .class and body #id is more important than body.class etc...
Finally if the rules ends up with the same priority, the last one is apply.
setting the !important flag in your code is a way to artificially boost the priority to a particular rule. But if you end up having the same rule with !important then the priority rules above will apply.
Override Will Work if You Do
.minor-action{
margin-top: 0em;
}
You didn't apply any styles to .extra-questions but to .minor-action. its true you apply to a same element. but cascade just work like that.
This will help: How to override the properties of a CSS class using another CSS class
And This: http://www.w3.org/TR/CSS2/cascade.html#cascade
Because its already set in the class above .minor-action, if it's set it doesn't override unless you use !important
Your first selector is more specific, it applies to elements that are children of a form, and it just overrides the most general (the second one) which applies to any of your .yourclass regardless of its position in the document hierarchy. you can get rid of the important by selecting form .yourclass instead.
Consider this:
h1 { color: red; color: blue }
Or, a more complex example (taken from a SVG file, stroke is twice):
style="fill:none;stroke:#ffffff;stroke-width:20;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke:#555555"
It seems that the answer is “it’s legal, the last assignment wins”, but I’d really like to know: Is there something written in the CSS specification about this topic?
It is valid to have multiple declarations that assign a value to a property so that the assignments apply to the same element, e.g.
h1 { color: red; }
h1 { color: blue }
Combining the declarations in the same rule does not change this.
There is no explicit statement about this in CSS specifications, so it is allowed simply because there is no rule that forbids it. Multiple declarations are very common, though mostly so that they are in different rules, often even in distinct style sheets. But they can also be used within a rule. A common technique is
p { max-width: 25em; max-width: 60ch }
which means that older browsers that do not recognize the ch unit will use the setting max-width: 25em, whereas in newer browsers, the latter declaration takes effect.
A general rule in CSS is that all other things being equal, latter declaration wins; this is part of the cascade rules. In the case of h1 { color: red; color: blue }, all other things are equal. But in h1 { color: red !important; color: blue }, the first declaration would win.
It is COMPLETELY VALID, h1 { color: red; color: blue } here color will simply be overridden by the next property value i.e blue
Even I use that while my website is in development mode, I often use border: 1px solid #f00; to create a blueprint of the page.
I'm trying to override a particular widget's style using UiBinder. What am I overlooking?
<ui:style>
/*************
* Note #1
*************/
.btnVote {
display: inline-block;
width: 50px;
height: 50px;
background: #fff;
margin: 5px;
text-align: center;
outline: none;
cursor: pointer;
}
/*************
* Note #2
*************/
.btnVote-up-hovering, .btnVote-down-hovering {
background: #ddd;
}
.btnVote-up-disabled, .btnVote-down-disabled {
border-shadow: inset 0 1px 3px #aaa;
}
.lblName {
line-height: 50px;
font-size: 40px;
padding: 5px 10px;
}
.clear {
clear: both;
overflow: auto;
}
.floatLeft {
float: left;
}
</ui:style>
<g:HTMLPanel styleName="{style.clear}">
<g:FlowPanel styleName="{style.floatLeft}">
/*************
* Note #3
*************/
<g:PushButton ui:field="btnVoteUp" stylePrimaryName="{style.btnVote}">
(+)
</g:PushButton>
<g:PushButton ui:field="btnVoteDown" stylePrimaryName="{style.btnVote}">
(-)
</g:PushButton>
</g:FlowPanel>
<g:FlowPanel styleName="{style.floatLeft}">
<g:Label ui:field="lblName" stylePrimaryName="{style.lblName}"/>
</g:FlowPanel>
</g:HTMLPanel>
Note 1: This rule is being applied and works fine
Note 2: This other rules seem to be getting ignored (they don't take effect)
Note 3: The default naming for the widget is being reset, hence Note 1 works fine. The base class is set to GOGXR1SCFI instead of gwt-PushButton
Why aren't they other rules working? When I hover the widget, the class GOGXR1SCFI-up-hovering is indeed set to the widget, but no accompanying CSS.
Thanks for your help.
Update
Something I ran into that gave me a hard time for a while: when you use the #external keyword, you must place a semi-column at the end of the #external statement, as in:
<ui:style>
#external .btnVote;
.btnVote {
...
}
</ui:style>
<g:FlowPanel styleName="{style.btnVote}"/>
One thing you could do is to create your CSS using ClientBundle, define all the different states there, then handle the various states manually. This way you don't need to define classes as #external, and GWT will optimize the CSS for you (shorten the names, only ship what gets used, etc.). This is especially beneficial for custom widgets and such.
The easiest way to deal with this is to write #external .btnVote, .btnVote-up-hovering, .btnVote-down-hovering, .btnVote-up-disabled, .btnVote-down-disabled at the top of your <style> section.
The original GWT widgets do not work well with CSS resources (like the one you have in your UiBinder). They depend on a primary style name that they append things like "up-hovering" to. This is terrible for CSS resources and UiBinders because when you type "up-hovering" it becomes things like SDLFJKS.
The button styles do NOT get obfuscated (so you can read "up-hovering"). Your UiBinder styles DO get obfuscated. You can never make them match as long as obfuscation is going on.
So, the #external keyword tells UiBinder and CssResource not to obfuscate certain styles. Now, when you use {style.btnVote-up-hovering}, that will actually come through to the final HTML, which is where these old-fashioned GWT styles will be applied.
I suspect you have CSS stylenames being obfuscated by GWT in your UIBinder. Reference - garbled css name when styling within UiBinder
Chose the approach you find easier to integrate in your proces. Cheers :)