Registering CSS preprocessors

CSS preprocessors allow you to:

  • Integrate dynamic stylesheet languages, such as LESS, Sass or Stylus (you can then write CSS code that is shorter and easier to maintain)
  • Perform custom processing of CSS code (for example validation, or other automatic adjustments)

You can use the API to register any number of CSS preprocessors, and choose a language (preprocessor) for individual CSS stylesheets. The system then stores two versions of the code for each stylesheet. You work with the unprocessed code in the editing interface, but browsers always recieve the plain CSS version when rendering pages.

Kentico provides a LESS Preprocessor, which you can download from the Marketplace.

Registering server-side CSS processors

You need to register your CSS preprocessors at the beginning of the application’s life cycle. Choose one of the following options:

  • During the initialization process of the application itself — use the CMSModuleLoader partial class in the App_Code folder.
  • When initializing custom modules — override the OnInit method of the module class.

Use the CssStylesheetInfoProvider.RegisterCssPreprocessor method to add preprocessors into the system. For server-side CSS processing, call the method with the following parameters:

  • Name (string) - a unique identifier of the preprocessor.
  • Extension (string) - the file extension of the stylesheets that use the given preprocessor (language). Used when deploying stylesheets as physical files.
  • Display name (string) - a name that appears when selecting the language for stylesheets in the administration interface.
  • Callback method that handles the processing of the CSS code.

When writing the callback method, either use the API of an external CSS preprocessor library, or implement your own custom logic. The callback must return a string containing plain CSS code.

The callback method provides a CSSEventArgs parameter with the following string properties:

  • Code - the stylesheet’s original code, which the preprocessor needs to convert into plain CSS.
  • ErrorMessage - allows you to set a message that the system displays in the stylesheet editing interface if an error occurs while processing the CSS.

Example

The following example registers a sample processor that converts the final CSS code of stylesheets into upper case. The example uses a custom registration class in the App_Code folder.

  1. Open your project in Visual Studio.
  2. Create a class in the App_Code folder (or CMSApp_AppCode -> Old_App_Code on web application projects).
  3. Extend the CMSModuleLoader partial class.
  4. Create a new class inside CMSModuleLoader that inherits from CMSLoaderAttribute.
  5. Add the attribute defined by the internal class before the definition of the CMSModuleLoader partial class.
  6. Override the Init method inside the attribute class and call the RegisterCssPreprocessor method.
  7. Implement the callback method that handles the server-side CSS processing (ParseCss in the example).
  8. Save the class file (Build the CMSApp project on web application installations).



using CMS.Base;
using CMS.PortalEngine;

[CustomCSSProcessor]
public partial class CMSModuleLoader
{
    /// <summary>
    /// Attribute class that registers your CSS preprocessors.
    /// </summary>
    private class CustomCSSProcessorAttribute : CMSLoaderAttribute
    {
        /// <summary>
        /// Called automatically when the application starts.
        /// </summary>
        public override void Init()
        {
            // Registers the 'Upper case CSS processor'
            CssStylesheetInfoProvider.RegisterCssPreprocessor("customCss", ".css", "Upper case CSS processor", ParseCss);
        }

        // Callback method that defines the processor's functionality
        private string ParseCss(CssEventArgs parsingArguments)
        {
            string cssOutput = String.Empty;

            try
            {
                // Call the API of your preprocessor or implement custom processing logic
                // The example only converts the final CSS code into upper case
                cssOutput = parsingArguments.Code.ToUpperCSafe();
            }
            catch (Exception e)
            {
                // Sets a message that the stylesheet editing UI displays if an error occurs during the CSS processing
                parsingArguments.ErrorMessage = e.Message;
            }

            // Returns the plain CSS output of the processor
            return cssOutput;
        }
    }
}


Assigning CSS processors to stylesheets

Once you register one or more CSS preprocessors, you can create stylesheets that use the added functionality. See Creating CSS stylesheets for general information about managing stylesheets.

  1. Log in to the Kentico administration interface.
  2. Open the CSS stylesheets application.
  3. Add a New CSS stylesheet.
  4. Select the Language. The available options include all registered CSS preprocessors (display names) and Plain CSS.
  5. Write the stylesheet code. You can use any syntax supported by the selected preprocessor.
  6. Click Save.

When you save the stylesheet, the selected preprocessor generates the plain CSS equivalent of the actual code. The system stores both types of code for the stylesheet.

  • You work with the unprocessed code in the editing interface (for example the code of a dynamic stylesheet language)
  • Browsers always receive the plain CSS version when rendering pages that use the stylesheet

Tip: To preview the plain CSS output of a stylesheet’s code, select the Plain CSS preview radio button above the editor.

Editing a stylesheet that uses a custom preprocessor (language)

Changing the language of stylesheets

If you have multiple CSS processors registered in the system, you can switch stylesheets to a different language:

Warning: When you change a stylesheet’s language, the system permanently converts the code to plain CSS.

  1. Edit the stylesheet.
  2. Click Change next to the Language field.
  3. Select the new language (preprocessor).
  4. Click Change language.

The original processor converts the stylesheet’s code to plain CSS. You need to manually adjust the code according to the new language.

Implementing client-side CSS processing

The system allows you to add CSS processing that runs directly in client browsers. For example, you can integrate dynamic stylesheet languages with client-side compilers.

To register a client-side CSS preprocessor, use the same basic approach as for server-side processing. Call the CssStylesheetInfoProvider.RegisterCssPreprocessor method with additional callback method parameters:

  • The first extra callback renders the required scripts on the CSS stylesheet editing page. The client scripts must always define a GetCss method that converts stylesheet code into plain CSS.
  • The second callback detects errors in the client-side CSS processing. Use the callback to check the result of the GetCss client script method, and set an error message if necessary. The CSS processing finishes only if this callback returns an empty string.

Even when using a client-side preprocessor, we strongly recommend implementing equivalent functionality on the server. The server-side logic serves as a backup for scenarios where client-side processing is not possible (for example when using the API to update stylesheet code or during content staging).

The system performs the processing in the following order:

  1. Processing via the GetCss client script method
  2. If the result of GetCss is empty, the preprocessor runs the server-side callback

Example

The following example creates a client-side preprocessor that converts the final CSS code of stylesheets into lower case.

  1. Prepare a JavaScript file that defines the GetCss method. For example, create cssclientside.js in the ~/CMSScripts/Custom folder.

    cssclientside.js
    
    
    
     // Returns processed CSS code as a string, or an error message (starting with 'error|')
     // If the result is empty, the preprocessor runs the server-side callback method
     function GetCss(originalCode)
     {
         var returnCode;
    
         try
         {
             // Implement your client-side processing of the CSS code
             // The example only coverts the code to lower case
             returnCode = originalCode.toLowerCase();
         }
         catch (ex)
         {
             // Returns an error message in the format recognizable by the 'DetectClientSideErrors' callback method
             returnCode = 'error|' + ex.message;
         }
    
         return returnCode;
     }
    
    
     
  2. Register the CSS preprocessor and define the required callback methods. See Registering server-side CSS processors for information about the basic process.

    
    
    
     using System.Web.UI;
    
     using CMS.Base;
     using CMS.PortalEngine;
     using CMS.Helpers;
    
     [CustomClientCSSProcessor]
     public partial class CMSModuleLoader
     {
         /// <summary>
         /// Attribute class that registers your CSS preprocessors.
         /// </summary>
         private class CustomClientCSSProcessorAttribute : CMSLoaderAttribute
         {
             /// <summary>
             /// Called automatically when the application starts.
             /// </summary>
             public override void Init()
             {
                 // Registers the 'Client-side CSS processor'
                 CssStylesheetInfoProvider.RegisterCssPreprocessor("customClientCss", ".css", "Client-side CSS processor",
                 ServerParseCss, RegisterClientScripts, DetectClientSideErrors);
             }
    
             /// <summary>
             /// Registers JavaScript code and files required for client-side processing.
             /// </summary>
             private static void RegisterClientScripts(Page page)
             {
                 // Links 'cssclientside.js' onto the editing page for stylesheets using the "Client-side CSS processor" language
                 // The client script must always define the 'GetCss' method
                 ScriptHelper.RegisterClientScriptInclude(page, typeof(string),
                 "ProcessCss", URLHelper.ResolveUrl("~/CMSScripts/Custom/cssclientside.js"));
             }
    
             /// <summary>
             /// Called whenever client-side CSS processing occurs. Checks if the 'GetCss' JavaScript method returned an error.
             /// The system completes the CSS processing only if the method's return value is an empty string.
             /// </summary>
             private static string DetectClientSideErrors(string getCssOutput)
             {
                 // Detects errors in the client-side CSS processing
                 if (getCssOutput.StartsWithCSafe("error|", true))
                 {
                     // Returns the error message result of the 'GetCss' JavaScript method
                     // The system displays the error message in the CSS editing user interface              
                     string[] errorParts = getCssOutput.Split(new[] {'|'});
                     return errorParts[1];
                 }
    
                 // Returns an empty string if the client-side processing was successful
                 // In this case, the system uses the output of the 'GetCss' JavaScript method as the result of the CSS processing
                 return String.Empty;
             }
    
             // Callback method that defines server-side processing
             // Used if the 'GetCss' JavaScript method returns an empty value
             private string ServerParseCss(CssEventArgs parsingArguments)
             {
                 // Converts the CSS code to lower case
                 return parsingArguments.Code.ToLowerCSafe();
             }
         }
     }
    
    
     

You can now assign the preprocessor to a stylesheet and try out the functionality.