CSS classes and widgets: three questions - css

I wrote a pretty complicated widget that uses OnDemandList to create a widget that allows full editing (including adding) of a store.
Now... I am not exactly a CSS guru (quite the contrary), and would love some guidance, just to check that I am doings things in a semi-sane way.
When I create the editor in my widget, I do:
buildRendering: function(){
// ...
this.domNode = put( 'div' );
// ...
},
postCreate: function(){
// ...
// This is here, because if I set the class in buildRendering, it gets zapped by className (the widget's declaration)
put( this.domNode, '.editable-list' );
// ...
},
Then when an editor is added dynamically:
put( row.element, editingWidget.domNode );
put( editingWidget.domNode, '.editable-list-row-editor' );
I also need to make sure that each row has position:absolute so that the editor gets placed in the right spot:
domStyle.set( row.element, 'position', 'relative' );
In the CSS, I have:
.editable-list-row-editor {
position: absolute;
top: 0;
z-index: 20;
}
Questions:
1) Is it OK in terms of best practices to even add a style like I did with domStyle.set( row.element, 'position', 'relative' ); ...? Or shall I do that with CSS? I did it programmatically because it's really important that it's relative.
2) Is it OK in terms of CSS to leave things as non-specific as possible? The idea is that users might (and probably will) end up writing their own CSS, and overriding things by writing more specific rules... is that right? Or maybe I should have written:
.editable-list .editable-list-row-editor {
position: absolute;
top: 0;
z-index: 20;
}
Or better:
.editable-list .row-editor {
position: absolute;
top: 0;
z-index: 20;
}
...?
3) From what I am seeing, CSS classes for widgets should be set in postCreate rather than buildRendering, otherwise Dojo seems to use className to zap anything that was set there... is that what you'd normally do with a widget that creates its own domNode?

My personal opinion on the inline CSS vs CSS stylesheet is that I like to write everything in a seperate stylesheet. The reasoning behind this is that your code becomes cluttered with styling code, but when seperating concerns I think it would be better to write your CSS in a seperate file.
Of course, inline CSS is always the most specific one (the most important one), so if you really want to enforce something, you could add an !important to your CSS rule altought I would recommend use them not that much.
You should write your CSS as specific as possible, because you don't want to interfere with other widgets/HTML but you don't want the opposite as well (external CSS interfering with your widget). But of course, you can write things as:
.editable-list .row-editor {
position: absolute;
top: 0;
z-index: 20;
}
It mostly depends on what .row-editor actually means. If it's something "global", you could keep .row-editor, simply because it will allow you to define a global .row-editor which contains the CSS that is in common, while your .editable-list .row-editor will contain specific CSS rules for that widget.
For example, let's consider that you have another widget with a similar CSS:
.other-widget .row-editor {
position: absolute;
top: 0;
z-index: 25;
}
Then you could also write the following CSS:
.row-editor {
position: absolute;
top: 0;
}
.editable-list .row-editor {
z-index: 20;
}
.other-widget .row-editor {
z-index: 25;
}
But it actually depends on how you see the .row-editor class, if you think it's only specific to your editable list, then you might also consider prefixing it. It's similar to what Dojo already does, Dojo has global CSS classes like .dijitInline but also specific CSS classes like .dijitCalendarDateLabel.
If someone wants to change the style of the widget, he could add a parent class and so he will be able to make a more specific CSS selector. An example, let's say that the following is your CSS:
.editable-list .row-editor {
position: absolute;
top: 0;
z-index: 20;
}
Then someone who wants to change the CSS just adds a tag to a parent (for example the <body> tag):
<body class="myTheme">
<!-- Your HTML -->
</body>
And then specifies the following CSS:
.myTheme .editable-list .row-editor {
z-index: 30;
}
This will actually override your z-index. Dojo already uses this principle with their themes. When you want to use a specific theme, you add the theme CSS and add the name of the theme as a classname in your body, for example:
<body class="claro">
<!-- Your HTML -->
</body>
Of course you don't need to define it at body-level, as long as it's a parent node of your widget it will work.
About the issue about buildRendering vs postCreate, well, I suppose that you use the dijit/_TemplatedMixin mixin. If that's so, then if you look at the code and look for buildRendering you will see it's doing stuff. This means that if you write your own buildRendering you will actually replace their code with yours. If you want to make sure that Dojo executes its own logic first, you have to write something like:
buildRendering: function() {
this.inherited(arguments);
/** Your code */
}
That extra line of code will in fact call the same method of the inherited modules/mixins. You can do with that line what you want, if you don't want that the inherited modules are called, you leave it out (probably breaking it as well), if you want to execute it as the last step you just switch the this.inherited(arguments); to your last step in the buildRendering function (but then it might override your changes).
But in the end, this is all just an opinion and I'm sure that there are other opinions there that are also correct (for other or even similar use cases). But I can tell you that Dojo does things in a similar way for their own widgets, so maybe it's not a bad approach to follow it as well.
Sorry for the long answer, but I wrote it so that it might be useful for similar questions as well.

Related

Add logic to CSS

I would like to use logic in my CSS. Styles need to be applied only if a product ID is higher than a specific number, e.g:
if (data-product-id > 25) {
padding: 50px;
}
Is this possible with CSS?
No, it isn't. Attribute selectors are based on simple string matching. There is no provision for less than / greater than numerical comparisons.
The closest you could get with CSS itself would be something like:
[data-product-id="25"],
[data-product-id="26"],
[data-product-id="27"],
/* etc */
This sort of thing is better handled with JS or server-side code which adds classes to elements.
You can apply some limited logic of the like you were asking about in CSS, but I advise against it. Nevertheless, the answer below is an answer, it's better to implement your logic in Javascript.
Assuming that you have a class called data-product for all your data products, you can create this rule:
.data-product {
padding: 50px;
}
.data-product[data-product-id="1"],
.data-product[data-product-id="2"],
.data-product[data-product-id="3"],
.data-product[data-product-id="4"],
.data-product[data-product-id="5"],
.data-product[data-product-id="6"],
.data-product[data-product-id="7"],
.data-product[data-product-id="8"],
.data-product[data-product-id="9"],
.data-product[data-product-id="10"],
.data-product[data-product-id="11"],
.data-product[data-product-id="12"],
.data-product[data-product-id="13"],
.data-product[data-product-id="14"],
.data-product[data-product-id="15"],
.data-product[data-product-id="16"],
.data-product[data-product-id="17"],
.data-product[data-product-id="18"],
.data-product[data-product-id="19"],
.data-product[data-product-id="20"],
.data-product[data-product-id="21"],
.data-product[data-product-id="22"],
.data-product[data-product-id="23"],
.data-product[data-product-id="24"],
.data-product[data-product-id="25"] {
padding: 25px;
}

How to think about styling AngularJS components?

I'm working on an AngularJS project with the aim of slowly getting things in order for Angular 6, or whatever version is out when we start on the upgrade. One of the big pieces of that work is converting existing directives into components.
The thing I'm struggling the most with, is that every instance of a component introduces an extra element into the DOM that wraps my actual component HTML and breaks the hierarchy, making it very hard to write CSS that does what it needs to.
To illustrate my dilemma, imagine a simple component called alert that provides styling for various types of messages you want a user to pay attention to. It accepts two bindings, a message and a type. Depending on the type we will add some special styling, and maybe display a different icon. All of the display logic should be encapsulated within the component, so the person using it just has to make sure they are passing the data correctly and it will work.
<alert message="someCtrl.someVal" type="someCtrl.someVal"></alert>
Option A: put styling on a <div> inside the extra element
Component template
<div
class="alert"
ng-class="{'alert--success': alert.type === 'success', 'alert--error': alert.type === 'error'}">
<div class="alert__message">{{alert.message}}</div>
<a class="alert__close" ng-click="alert.close()">
</div>
Sass
.alert {
& + & {
margin-top: 1rem; // this will be ignored
}
&--success {
background-color: green; // this will work
}
&--error {
background-color: red; // this will work
}
}
This works fine as long as the component is completely ignorant of everything around it, but the second you want to put it inside a flex-parent, or use a selector like "+", it breaks.
Option B: try to style the extra element directly
Component template
<div class="alert__message">{{alert.message}}</div>
<a class="alert__close" ng-click="alert.close()">
Sass
alert {
& + & {
margin-top: 1rem; // this will work now
}
.alert--success {
background-color: green; // nowhere to put this
}
.alert--error {
background-color: red; // nowhere to put this
}
}
Now I have the opposite problem, because I have nowhere to attach my modifier classes for the success and error states.
Am I missing something here? What's the best way to handle the presence of this additional element which sits above the scope of the component itself?
I personally do option A. This allows you to easily identify and create specific styles for your components without fear that they will overwrite site-wide styles. For instance, I'll use nested styles to accomplish this:
#componentContainer {
input[type=text] {
background-color: red;
}
}
This will allow you to make generic styles for your component that won't spill out into the rest of your solution.

Selector alignment in CSS source code

I'm looking to see if anyone has ever had any experience with this CSS syntax debate we are currently having on our team. Our dev team has been using the vim plugin Tabular to align text in our code. For example in PHP or Javascript we will align variable declarations using the plugin like this:
$count = 0;
$var_1 = array();
$var_2_long_name = array();
$stdout = fopen( 'php://stdout', 'w' );
$some_data = json_decode( $some_json_data, true );
Helps the code look clean and easy to read.
We have considered using alignment in our CSS (we are using LESS but this question could be applied to SASS or just straight CSS). For example we would change this block:
.btn-section {
position: relative;
top: -65px;
display: block;
z-index: 100;
.content-box;
background-color: #grayButton;
color: #gray;
padding: 10px 0;
.border-radius(5px);
}
To this:
.btn-section {
position : relative;
top : -65px;
display : block;
z-index : 100;
background-color : #grayButton;
color : #gray;
padding : 10px 0;
.content-box;
.border-radius(5px);
}
One of the devs experimenting with this tactic moved the mixins from their original spots to the bottom of the declaration in order to make the code "look right" since mixins don't conform the the normal selector: value; format of regular css. In this case, the .content-box mixin had a background-color declaration that was being overridden by the backgroud-color line beneath it. Moving the mixin to the bottom broke the override and gave the element the wrong background color.
Errors like this coupled with the extra steps it takes to format every single block of CSS make me think this might not be such a good idea. Has anyone ever tried this type of alignment before? Any opinions on whether this is a good or bad idea? Thanks.
I think your alignment tactic is a good idea, I'd just recommend turning it upside down:
.btn-section {
.content-box;
.border-radius(5px);
position : relative;
top : -65px;
display : block;
z-index : 100;
background-color : #grayButton;
color : #gray;
padding : 10px 0;
}
That way the more general mixin styles would be applied first, after which they may be overridden by selection specific adjustments instead of the other way around.
By doing it like this, you eliminate this risk of accidently overriding specific styles with inherited ones and still keep everything neat and easy to read.

LESS mixins vs classes

I'm looking into LESS because I definitely see some of their benefits. For instance colour declaration.
One thing I don't understand tho, and maybe I'm not getting the flow right is - why use the following LESS snippet
.radius {
-webkit-border-radius:5px;
-moz-border-radius:5px;
border-radius:5px;
}
.btn-red{
background-color:red;
.radius;
}
.btn-green{
background-color:green;
.radius;
}
...
When we can use the .radius class in the html file right away. I'm left with the impression that LESS will add a ton of duplicate code once it gets compiled.
I'm using the following, which makes more sense. Same with font-size, margins, etc... Aren't classes used in such cases?
<div class="btn-red radius">Cancel</div>
<div class="btn-green radius">Go</div>
The snippet above does not benefit from SASS/LESS capabilities that much. Lets have a closer look and check this SCSS snippet.
// Abstract placeholder.
%radius {
border-radius: 5px;
}
// Put your global styling here.
// I'm assuming that you can alter the markup and have button.btn.btn-green
.btn {
// Color modifier.
&-red {
#extend %radius;
background-color: red;
}
&-green {
#extend %radius;
background-color: green;
}
}
The CSS output will be:
.btn-red, .btn-green {
border-radius: 5px;
}
.btn-red {
background-color: red;
}
.btn-green {
background-color: green;
}
And then you have to pick up Autoprefixer and vendor-prefixes issue is solved once and for all.
Because now, you can just specify the class btn_red or btn_green and all the buttons will automatically have a radius.
Your HTML should contain only the semantics, and styling or classes referring to styling should not be part of it.
That applies to the other classes as well. If for instance, you would rename btn_red to btn_cancel, you have a meaningful classname that you can apply to any kind of cancel button. And in the CSS you can specify that a cancel button is red and a 'Go' button is green, and both have a radius, without needing to modify the HTML at all.
So, the ultimate goal is to have the HTML describe the structure and the CSS describe how that structure should look. And a CSS preprocessor is only their to make a bulky spaghetti-like CSS file more structured.
There are several benefits.
You can use more semantic class names. Rather than encoding style information directly in your class names, (btn-red, radius) you could use a single class that conveys the usage of the style, rather than its contents.
You can avoid repeating yourself.
#radius-size: 5px;
-webkit-border-radius:#radius-size;
-moz-border-radius:#radius-size;
border-radius:#radius-size;
You can parameterize it so that you'd be able to use different radiuses (radii?) in different contexts.
.radius(#radius-size) { ... }
Because there are cases that developer has-no-access or don't-want to change the markup. and the only solution is to include all props from a predefined class.
for example:
you have bootstrap loaded (then you already have .has-success and .has-error classes) and if you want to use HTML5's native form validation using input's :valid and :invalid states, you have to use JavaScript to add/remove success/error classes based on input's states. but with this feature of LESS you can include all props of success/error class inside input's states. the code for this example could be something like this:
#myinput {
&:valid { .has-success; }
&:invalid { .has-error; }
}

CSS :after, content: having two values?

I've got CSS on my links depending what type of link it is. In this case it's password protected, and external link.
So I've got CSS like this:
a.external-link:after { padding-left: 2px; content: url(../images/icon-external-link.gif); }
a.restricted-link:after { padding-left: 2px; content: url(../images/icon-lock.png);}
However when I try something like this:
<a class="external-link restricted-link" href="some link">Some Link</a>
It only displays the last icon, in this case the icon-lock.png. Which makes sense, since the content value can only be set once not combined, so the last class declaration is overwriting it. Is there anyway to combine these two so I can mix and match these link classes easily (I've got 4 total). I don't want to make separate classes/images for each combo.
Hate to break it to you, but you're going to have to make separate classes/images for each combo. Especially as there would be no way of knowing which content should go first.
a.external-link.restricted-link:after
{
content: url(ext) url(res);
}
vs
a.external-link.restricted-link:after
{
content: url(res) url(ext);
}

Resources