Practices for keeping JavaScript and CSS in sync? - javascript

I'm working on a large JavaScript-heavy app. Several pieces of JavaScript have some related CSS rules. Our current practice is for each JavaScript file to have an optional related CSS file, like so:
MyComponent.js // Adds CSS class "my-comp" to div
MyComponent.css // Defines .my-comp { color: green }
This way I know that all CSS related to MyComponent.js will be in MyComponent.css.
But the thing is, I all too often have very little CSS in those files. And all too often I feel that it's too much effort to create a whole file to just contain few lines of CSS - it would be easier to just hardcode the styles inside JavaScript. But this would be the path to the dark side...
Lately I've been thinking of embedding the CSS directly inside JavaScript - so it could still be extracted in the build process and merged into one large CSS file. This way I wouldn't have to create a new file for every little CSS-piece. Additionally when I move/rename/delete the JavaScript file I don't have to additionally move/rename/delete the CSS file.
But how to embed CSS inside JavaScript? In most other languages I would just use string, but JavaScript has some issues with multiline strings. The following looks IMHO quite ugly:
Page.addCSS("\
.my-comp > p {\
font-weight: bold;\
color: green;\
}\
");
What other practices have you for keeping your JavaScript and CSS in sync?

My perspective on CSS files is that they describe rules that define the theme of an application. Best practices generally state that content, presentation, and behavior should be kept separate so that it is relatively easy to change that theme. By having multiple CSS files, this becomes slightly more difficult, as a designer would have more files to deal with.
Additionally, CSS (Cascading StyleSheets) rules are affected by their position in the CSS document. By having multiple CSS files with different rules in each, it may become more difficult to prioritize which rules take precedence.
Finally, if you want to find out what CSS selector in your JS file matches what CSS file, try using a cool search tool, like grep, if you're on linux. If you're using a good IDE, you can also use it to quickly search for the rules, then you can just jump to the line number. I really see no advantage in keeping the CSS rules in different files; it will only complicate matters.
Additionally, I would advise against the idea of putting the CSS inline. By doing this, you will inevitably make it more difficult for your web designer to quickly and easily swap out the styles. The whole point of external CSS is so your web designer can change the theme or provide multiple themes for different users. If you embed the CSS in the JavaScript or HTML, you've then tightly coupled the content, behavior, and presentation.
Best practices generally suggest keeping content, behavior, and presentation separate for this very purpose.

Having one CSS file per JS file seems a good thing for me. It's clean, and easy to understand and to maintain. The only problem would be to have dozens of CSS files on every page, but I suppose you combine those files to one big file, so this problem does not exist in your case.
How to embed CSS in JavaScript? It depends on the environment you have, and how the build process is done. The easiest thing is to have a large comment at the beginning of every JavaScript file, something like this:
// <...>Your copyright notice here</...>
// <css>
/*
body{color:red;}
div{border:solid 10px lime;}
// ... other ugly styles.
*/
// </css>
Then during the build, you have to search for <css>...</css> blocks and extract the CSS by trimming the /* and */.
Of course, it creates a problem: if you are using an IDE with auto-completion, embedding CSS into a JavaScript file will make it impossible to use auto-completion in this case.

My preferred method is to keep all the CSS files separate and then have a build process that compiles them into a larger CSS file on deployment.
I would avoid merging your JS with your CSS. It may sound like a cleaner solution from the file-level, I think it'll get messy fast. That, and you'll lose the highlighting and syntax assistance your editor gives you.

Check out Csster. I wrote it to solve just this problem.
You embed your CSS rules directly in your Javascript, using Javascript object literal syntax. It's no uglier than raw CSS.
Csster.style({
h1: {
fontSize: 18,
color: 'red'
}
});
The rules are inserted into the DOM on the client side. This architecture simplifies your build process and reduces client requests.
You can use it like you describe, but Csster also provides a couple other niceties:
nesting to DRY up stylesheets
color functions like darken and saturate
built-in macros for common CSS idioms like clearfix, rounded corners, drop shadows.
extension points for custom behavior or cross-browser support
It's well tested and I've used it on quite a few projects. It is independent of jQuery, but plays well with it.
I'd love to have more people use it and provide feedback.

Related

When dynamically creating HTML elements with Javascript is it better to have the CSS predefined in a file, or dynamically assigned?

Is it better from performance standpoint / a more efficient use of memory to have the CSS be created with the dynamically generated HTML elements, or to have the classes predefined in a CSS file waiting to be used?
I could imagine that having CSS sitting waiting to be used could make the CSS file unnecessarily big, whereas using JS to create the CSS could be a less efficient use of memory and processing power.
Would love to hear others' thoughts on it.
I vote for using css classes in separate file :
To separate the display from the processing or the traitement
To be able to manage any changes in the future
Having the possibility to make your CSS dynamic with CSS Custom Properties
Possibility to use css Modules
Take all css advantage
Personally, I prefer having things separate, since it's easier to find/read/update later one. Having a bunch of CSS styles mixed in with JS could make it hard to read and maintain in the long run.
I also wouldn't worry about optimization until you feel that your code is taking a while to load.
Defined in a css file, is a good practice.
If you need to update the css after generating html, Then it will be a good to define in css classes.

Is it bad practice to append style tag with multiple styles via javascript?

I have a question regarding style tags and Javascript. Many plugins or scripts come with a separate CSS file for styling. So, is it bad practice to avoid this, and use a style tag and append it to the head of the page, to then use those styles for your plugin?
For example, this code:
var style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = '.hg-grid-item-4{ width: calc(24.25% - '+Options.padding * 2+'px); padding: '+Options.padding+'px; float: left; margin-bottom: 1%}';
document.getElementsByTagName('head')[0].appendChild(style);
would add some styling to the website without needing an external CSS stylesheet. Would this cause problems in older browsers?
Also, as you can see in my example, I used a variable for the padding and the width. Is there a way of doing this if you dedice to use an external CSS? Thanks in advance!
In most of the cases you do not need calc() in CSS - this will always slow things down a bit and in general is an over complication that can almost always be done in a more simple way
Doing things the way you did doesn't consider a non-js version. So not the best practice especially when you style something like .hg-grid-item-4 so I assume some some grid that you use. Will this not break badly with JS disabled ?
It makes the code less maintainable - not sure what would be the reason to mix logic with styling ? In general it is a better idea to use Sass for example and define your Options.padding there if this is not something that really really needs to be calculated with JS. Does it ?
Adding the style tag to the DOM with JavaScript is totally legal for JavaScript to do, however, this is not considered "best practice."
When writing code, it best to separate the view from your application logic. The easiest way to do this is to put all of your styles in a CSS file. Also, it has the added benefit of making your code easier for other developers to understand.
For more information:
Separation of concerns
MVC
In regards to your variable padding question, in vanilla CSS, this is not possible, in order to use variables in CSS, you would need to use a CSS Preprocessor, like SASS or LESS. However, I think this would be overkill for your problem, you can make flexible styles using Flexbox or using percents instead of fixed margins or padding.

Are there compilers for HTML/CSS?

Many people today use Google Closure Compiler to actually "compile" their JavaScript code. The advanced mode enables it to rewrite JS to better, faster and smaller JS-code that functions the same way as the original input.
Are there any good compilers out there for HTML/CSS? It could for example compress the CSS classes like a JS-compresser does. It could remove any divs (display: none;) that no JavaScript actually displays (display: block;). It could remove whitespaces. It could combine small images into sprites. It could combine files that are included on all pages into one file.
The list just goes on and on. Do you know about any good tools for this job? (Even if it only can compress CSS classes etc.)
Concatenate your css files and you made most of the work : the cost is mostly related to the number of requests.
But for removing useless rules, there is no point in using a tool : needing one would mean you don't really understand which ones are needed and why. In other words your code is a mess you must fix because at this point it may only grow explosively.
That's the same for sprites and other optimizations : only by knowing the use flow of the application, if people come back and have some images cached, or only the ones of the main page, etc. can you know what strategy to use, even if it's almost always useful to merge all your small images of one page in a big one.
No actual compilers as such that I know of, but there are tools to help you create clean html and css.
For css there is, for example, less which is a good tool for generating nice clean cross-browser markup but you have to use it from the get-go. Similarly for html, there are a few markup frameworks that can simplify generation of clean html. markdown is one such that is quite popular.

Jquery/Java Script: Customise an Image/Avatar by chainging options (e.g. Shape, Colour)

Lots of websites let you customize an image by changing options.
For example, this Barbie website lets you create your own Barbie doll. You can click on various hairstyles and clothes and the main image updates while you click.
Other clothes websites do similar things.
Are there any tutorials that show you how to do this with Java Script or Jquery?
Ideally, I am looking for something templates that lets you re-use the code for different situations.
I have found a couple of tutorials but they all use PHP:
Bokehman - This website says it uses Javascript, but it actually uses PHP
Code Canyon - This script is templated to easily swap out elements, but again uses PHP.
I know that Javascript really doesn't support writing files so you would have to use a PHP solution to save the image.
However, I am just looking for something to create the image. At this stage, I'm not bothered about the saving.
This is how I did it in the end.
1) Create a separate CSS classes for each asset.
Concatenate classes for assets that are made up of multiple variables.
Create a .input parent class to display image assets for the selection form.
Create a .preview child class to display image assets on the finished avatar
e.g.
.skin-brown .preview .preview-body {
background-image(<<image-asset>>);
}
.input .input-skin-brown {
background-image(<<image-asset>>);
}
.input .input-hair-style-1 {
background-image(<<image-asset>>);
}
.hair-style-1.hair-colour-black .preview .preview-hair {
background-image(<<image-asset>>);
}
2) Create HTML. Assign default asset options to the wrapper element.
e.g.
<div id="wrapper" class="hair-style-1 hair-colour-black skin-brown">
<div class="inputs">
Put your input FORM here. Use a HTML form element.
</div>
<div class="preview">
The finished avatar goes here.
<div class="preview-hair"></div>
<div class="preview-eyes"></div>
<div class="preview-body"></div>
</div>
</div>
3) Use Jquery to manipulate the classes on the wrapper when the options in the input form have been clicked.
e.g if user clicks on hair-style-2, the hair-style-1 class in the wrapper will be changed to hair-style-2
I have a separate question about this:
jQuery: Swap Classes based on Class position
That's essentially all there is to it. Once you have the css classes written and the Jquery code to switch the classes working, it is actually very straightforward.
Because you a storing all the inputs as a form, you can send the values to another process when the user clicks submit.
Tips:
1) Use SASS/SCSS to write the css.
You can create an array and loop through it in sass which makes it easy to maintain the css. I have a question about this here:
Sass: Using two #each lists in SCSS
CSS - SASS: Using #each based mixins to generate multiple backgrounds
2) Avoid using a CSS sprite.
Although sprites help greatly with load times, I think you will go crazy trying to maintain it (depending on the assets that are involved). There are tools to maintain it for you, but because this is an edge case, I don't think the tools work that well.
3) Load Speeds are an issue
When the user clicks on an avatar element, there is a short delay while the CSS loads. This is a problem, as the user thinks their click hasn't registered.
To get around this, create a hidden div, which uses display:none. Then use the CSS3 multiple background property to attach every asset to this DIV (as a background).
This way, all your assets will load at the start, so there won't be a delay when the user clicks. Again, use SASS loops and arrays for this, as the array will automatically add all your assets to the hidden DIV.
4) Think very carefully about class and asset names.
I originally went for friendly names (e.g. haircolourblack, hairstylebob) as I thought it would be easier to make sense of the code. However, in hindsight, I wish I had gone for numbered names (haircolour1, hairstyle1) as things can get tricky if your assets change (Plus using numbers make it easy to maintain code against multiple avatars). Again, use SASS arrays to cut down on the maintenance of this.
5) Use Class prefixes
(e.g. .preview .preview-eye instead of .preview .eye or .preview .preview-hair-style instead of .preview .hair ). The reason for this is that a lot of the names are very generic and will probably be used in multiple places on the page (e.g. for both .preview and .input sections). If you use prefixes, it is easier to target specific classes. Plus you can use [class*="preview-"] or [class*="input-"] to target all members of a prefix, without having to litter your code with lots of shared classes (e.g. [class*="-hair-"] will get all hair elements without needing a separate hair class applied to each hair element.
6) Consider SVG
If you use SVG for your image assets, you can keep the files small and they will scale up to any size. Be sure to note SVG browser compatibility (http://caniuse.com/svg)
7) Consider CSS background size
You can also use background-size: contain to scale image assets, which can make it easy to reuse the same image for both .preview and .input instances. However, it also has compatibility issues.
It does seem like a daunting project, mainly because there aren't any resources on how to build it. But if you break it down, it's actually quite easy. It's mainly the code maintenance that is an issue, so be sure to plan!

Downsides with applying all css within javascript(jquery)?

I'm making this search component that I can just load using javascript and have it work wherever I load it. The idea is that it does an AJAX-search, so I don't want to code that up every time I put one on the page.
So maybe on pages that I want to put it on that would look like this:
var searchBox = new Search(inputBox);
Ideally, I wouldn't really want to have to link a style sheet everytime I do this. I'm just wondering if performance takes a big hit if I just create tags and add attributes like this:
$('<div></div>').css({
'background-color': #002323, etc.
});
I feel like its only slightly more verbose, but it will be much easier to manage and use.
Or do you know a better way of doing this?
Maybe this question is brushing the surface of a bigger problem, which is about making CSS object-oriented. I don't want it messing up other things on the page if there are css attributes with the same name. Everything else I do is object-oriented. Are there any CSS solutions or methodologies for this?
Two things come into mind:
If you ever want to change the style, you will have to do it in javascript, possibly at several places.
Obviously, applying styles one by one instead of just adding a class is slower.
CSS was designed to make your life easier and honestly I think it wouldn't be very wise to not to use it, unless you have some javascript style framework that does a better job.
It seems to me that it rather depends on how much CSS you need to apply to this search component, and whether you need to be able to skin it for different sites. Assuming your javascript is all held in one external file, is it a big problem to create a basic CSS file to go with it, and use the script to dynamically insert a <link> to the CSS file above other <link> elements in the document?
That way you can reuse and skin it very easily, overriding the styles set in the default CSS for any particular site just by adding the appropriate selectors to that site's stylesheet. If you set them all with jQuery, it'll be much harder to change the skin.
The main problems of your search component are obstrusive JS and probably non-accessible tool (except if you took the ARIA road).
The one you're talking about is secondary.
You should use carefully named classes, I wonder what can be easier to manage than a class="warning" (background-color: #FE0114; ? no way)

Categories