2

I have been long battling this, and I would like to know if any others have feedback. I am about to make a customized library for building web apps quickly, and I want to make sure I use the right approach. I WANT to use this method:

$.fn.someSlider = function(){
var coreStyle = '.slider ul { white-space: nowrap; } .slider ul li {display: inline-block}', coreStyleTemplate = '<style><\/style>';
} 

But I feel like hard coding the base CSS into the widget is always frowned upon - instead I see SO users recommending the use of CSS style rules instead of this option. I really really really want that 'it just works' feel, and having to force my users to use a separate style sheet just to get my plugins working... well is annoying!

Just to clarify: I would like to include all base style rules needed for the widgets proper/base functionality to be included inside the script. The user would easily modify the base look of the widget by writing a style rule in their own style sheet.

Example:

Instead of having to look through all the base styles trying to find the font color like this... .slider {display: inline-block; color: #000; someotherconfusingrule : blahblah; }

The user simply starts a new rule with the classes name/selector being used - and then just write the changes to make to the default script styles

They would just write

.slider {color: #000};

Thanks for the help in advance SO!

2 Answers2

1

Nice question! Although I'm not sure what the preferred solution to this would be, I was thinking of the following approach:

  • Use a IIFE to define your jQuery plugin and enable you to define some private, global variables and functions.

    $.fn.pluginName = (function() {
        return function() {
           ...your regular plugins code...
        };
    }();
    
  • Define your plugins CSS as a list of style rules in your plugins code

    var rules = [
        '.box {' +
        '  width: 100px;' +
        '  background-color: #f99;' +
        '  margin: 10px;' +
        '  padding: 10px;' +
        '  font-family: Helvetica, Arial;' +
        '  text-align: center;' + 
        '}'
    ];
    
  • Create a private variable that remembers if your stylesheet has already been added to the document

    var styleSheetExists = false;
    
  • Create a private function that creates a stylesheet using the style rules above and that adds it as the first <style> element in the <head> allowing the user to override styles in their own CSS. See http://davidwalsh.name/add-rules-stylesheets for a good tutorial on how to do this properly

    var createStyleSheet = function() {
        var style = document.createElement("style");
        style.appendChild(document.createTextNode(""));
    
        $('head').prepend(style);
    
        for (var i = 0; i < rules.length; i++) {
            style.sheet.insertRule(rules[i], i);
        }
    };
    
  • The first time your plugin is applied to an element check if the stylesheet has already been created and if not create the stylesheet.

    var $elements = $(this);
    
    if (!styleSheetExists) {
        createStyleSheet();
        styleSheetExists = true;
    }
    
    $elements.each(function() {
        $(this).addClass('box');
    });
    
    return $elements;
    

See http://codepen.io/ckuijjer/pen/FkgsJ for this example. It creates a jQuery plugin called box which simply adds the class box to an element. The class box has a default pink background color defined in its stylesheet which gets overridden by a user defined blue background color.

But please do make this configurable in your jQuery plugin. You want to enable developers to bundle all their css, including your plugins, to optimize resource delivery to the client. Plus injecting stylesheets might be a small performance hit.

Community
  • 1
  • 1
ckuijjer
  • 13,293
  • 3
  • 40
  • 45
  • Thanks for the great response. I am using a similar technique now on a form validation plugin which has styles that will absolutely never need to be edited, and in my opinion should be included in the base script itself. If anyone thinks this is just plain wrong.. then they should read up on how web components or the polymer library work, I feel it has many similarities. Also this method has some built in dependency injection in the way that base styles are loaded only when the script is loaded. – NicholasAbrams Oct 21 '14 at 02:57
  • I like to leave the .class_names detached from the injected style var because it allows me to pass a custom selector into the mix so the user can set their own conventions. – NicholasAbrams Oct 21 '14 at 03:06
  • @user2626009 Detaching the class names from the style variable to have them user definable is indeed a good idea – ckuijjer Oct 21 '14 at 05:53
1

It may seem annoying but separating the model, view, and controller is the correct way. You're using jQuery so why not consider how jQuery would approach the situation: a jQuery UI widget like the Accordion comes with several stylesheets, the most important being the base stylesheet and a separate 'theme' stylesheet that (if done correctly) is nondestructive and can be modified without risking the integrity of the widget. You may also want to consider how your favorite plugins are authored and what makes them appeal to you. It's my personal opinion CSS should never be present in JavaScript files however if you've made up your mind, the solution @ckuijjer provided is sound. Hope this helps!

robbymarston
  • 344
  • 3
  • 16