Compactez vos css

Contenu du snippet

Bonjour à tous !

Si vous êtes un webmaster consciencieux, vous devez livrer un site web léger afin de satisfaire vos clients les plus démunis (56k, 28k!) ainsi que d'économiser la bande passante qui vous est gracieusement louée contre une belle poignée de billets.

1-Pour ceux qui ont la possibilité de le faire, activer premièrement gzip sur votre serveur afin que les pages envoyées soient compressées. Si vous ne savez pas si votre serveur compresse, utilisez cet outil http://www.pipeboost.com/report.asp.

2-La deuxième solution qui peut être mis en place est un compacteur de CSS. J'en entend déjà qui commencent à marmonner que gzip est largement suffisant et je les invite à tester ;-). L'idée du compacteur de CSS est de supprimer les espaces et sauts de ligne inutiles grâce à de bonnes vieilles expressions régulières. En plus de compacter le fichier css, ça permet de le rendre plutôt illisible

Pour la mise en place, il faut ajouter dans la configuration du répertoire virtuel de IIS l'extension css et mettre comme exécutable la dll isapi d'asp.net 2. Si vous ne faîte pas ça, le HttpHandler que nous allons développer ne fonctionnera pas.

Nous allons créer notre HttpHandler dans le répertoire App_Code mais il est possible de le créer dans une dll externe...c'est une affaire de goût, à vous de voir.

Vous devez aussi déclarer le HttpHandler dans le fichier Web.config comme ceci:

<httpHandlers>
<add verb="POST,GET" path="*.css" type="CSSHandler"/>
</httpHandlers>

Au niveau du gain j'ai personnellement gagné ~10% avec gzip activé en aval, ce qui n'est pas rien. Notez que c'est à vous d'ouvrir le fichier CSS dans ProcessRequest et que les compactages effectués peuvent être améliorés, quoique :-P.

------------------------------------------------------------------
Tableau des performances avec une CSS :

Originale : 36661 octets
Compactée : 25,240 octets
GZIP : 7,365 octets
GZIP + Compactée : 5,054 octets

Source / Exemple :


using System;
using System.Data;
using System.Collections;
using System.IO;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Text.RegularExpressions;

/// <summary>
/// CSSHandler Compacteur de CSS
/// </summary>
public class CSSHandler : IHttpHandler
{
     /// <summary> 
    /// Compacte la CSS, sinon on envoie une erreur 404 si le fichier css n'existe pas
    /// </summary> 
    /// <param name="context">Context</param> 
    public void ProcessRequest(HttpContext context)
    {
    	//on test l'existence du fichier et on déclenche une erreur 404
    	//s'il n'existe pas
        if (!new FileInfo(context.Request.PhysicalPath).Exists)
            throw new HttpException(404, context.Request.Path + " not found");
        else //le fichier exist
        {
            string strCssContenu = "";
            
            //on lit le fichier entièrement
            using (TextReader hFile = new StreamReader(context.Request.PhysicalPath))
            {
                strCssContenu = hFile.ReadToEnd();
                hFile.Close();
            }
            
            //on compacte
            
            
           //supprime les sauts de ligne 
            strCssContenu = new Regex("\xd\xa").Replace(strCssContenu,"");
            //supprime les commentaires
            strCssContenu = new Regex(@"(/\*.+?\*/)").Replace(strCssContenu, "");

            //1: On isole les chaines "    "
            string regChaine = @""".+?[^\\]""";
            MatchCollection MatchesStrings = new Regex(regChaine, RegexOptions.IgnoreCase | RegexOptions.Singleline).Matches(strCssContenu);
            //2: On supprime les chaines
            strCssContenu = new Regex(regChaine, RegexOptions.IgnoreCase | RegexOptions.Singleline).Replace(strCssContenu, "<STRING_CACHE/>");

            strCssContenu = new Regex(@"\t").Replace(strCssContenu,"");
            strCssContenu = new Regex(@" {2,}").Replace(strCssContenu, " ");
            strCssContenu = new Regex(@" *({|}|:|!|;) *").Replace(strCssContenu, "$1");

            //Bug d'iE avec les attributs first-letter, first-line-> il faut un espace avant la parenthèse
            //du coup on le rajoute devant chaque parenthèse ouverte
                    
            strCssContenu = new Regex(@"([^ ]){", optCompile).Replace(strCssContenu, @"$1 {");

            //On replace les chaines
            foreach (Match oneString in MatchesStrings)
            {
                strCssContenu = new Regex(@"<STRING_CACHE/>",
                                         RegexOptions.IgnoreCase | RegexOptions.Singleline)
                                         .Replace(strCssContenu, oneString.Value, 1);
            }

            //Important pour FireFox oubien il ne reconnait pas la css
            context.Response.ContentType = "text/css"; 
            
            //on écrit la css compactée dans le flux de reponse
            context.Response.Write(strCssContenu);
            //on envoie explicitement le buffer en cache
            context.Response.Flush();
            //on ferme la connexion
            context.Response.End();
        }
    } 

    
    public bool IsReusable
    {
       get { return true; }
    }

}

Conclusion :


Je remercie Sebastien "Regexp" Ferrand pour son aide.
Autre chose, je ne l'ai pas mis dans le code, mais dans le cas où la css n'est pas générée dynamiquement, mettez la css compactée dans le Cache, le serveur vous en sera reconnaissant !

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.