Utiliser PHP pour gérer vos styles CSS

Astuce par (Développeur/Intégrateur web, France voisine de Genève)
Créé le , mis à jour le (84336 lectures)
Tags : css, php, sass, less

Certaines limites de CSS peuvent parfois être gênantes. Des frameworks plus ou moins poussés comme LESS ou SASS tentent de pallier à ces petits soucis. Une autre solution est d'utiliser simplement PHP pour générer des feuilles de styles CSS.

Les avantages sont multiples :

  • Hormis quelques connaissances basiques en PHP, pas besoin d'apprendre de nouvelle syntaxe pour gérer la CSS, c'est d'une simplicité à l'épreuve des balles,
  • Il n'y a rien à installer sur le serveur,
  • Comme c'est PHP qui est utilisé, la CSS est créée côté serveur, il n'y a pas de problème de CSS à compiler côté client (avec tous les inconvénients que cela pose),
  • Cela permet de garder la maîtrise absolue de ses CSS, le code généré n'obéit qu'à son créateur.

Créer la CSS proprement dite

Le fichier CSS s'appellera donc styles.php, et se présente ainsi :

<?php
   header('content-type: text/css');
   ob_start('ob_gzhandler');
   header('Cache-Control: max-age=31536000, must-revalidate');
   // etc. 
?>
/* ici vos styles statiques */

L'entête (header) indique que le fichier PHP est bien de type CSS, et les autres permettent la mise en cache, la compression afin que les performances ne soient pas oubliées (en supposant que les fichiers PHP ne soient pas déjà paramétrés pour être mis en cache).

L'appel à la CSS se fera ainsi :

<link href="../layout/css/styles.php" rel="stylesheet" type="text/css" media="all" />

Quelques possibilités données par PHP

Une variable pourra s'écrire ainsi :

<?php
   $couleur_texte='#fc4022';
?> 
body {
   color:<?php echo $couleur_texte; ?>;
}  
#page {
   color:<?php echo $couleur_texte; ?>;
}

Supposons qu'il faille un style prévoyant des transitions à reprendre sur divers éléments :

<?php
   $transition = '-webkit-transition:  all 1s;
   -moz-transition: all 1s;
   -ms-transition: all 1s;
   -o-transition: all 1s;
   transition: all 1s;';
?>
  
img {
   <?php echo $transition; ?>
}
/* [...] */
.mabox {
   border:1px solid #fff;
<?php echo $transition; ?>
}

On peut même imaginer un tableau contenant les préfixes en début de fichier, et une simple boucle permettra de créer tous les préfixes, vous simplifiant la vie pour ces derniers.

<?php
   $tab_prefixes = array('-webkit-','-moz-','-ms-','-o-','');
   /** ... **/
   foreach($tab_prefixes as $prefix){
      echo $prefix.'transition: all 1s;';
   }
   ?>

Autre idée, on peut imaginer une fonction se basant sur le tableau des préfixes ci-dessus et générant un dégradé linéaire avec tous les préfixes.

<?php
   function linearGradient($prefixes, $xy, $cStart, $cEnd, $pStart, $pEnd) {
      foreach($prefixes as $prefix){
         echo 'background-image: '.$prefix.'linear-gradient('.$xy.', '.$cStart.' '.$pStart.', '.$cEnd.' '.$pEnd.');';
      }
   }
   $tab_prefixes = array('-webkit-','-moz-','-ms-','-o-','');
?>
  
div {
   <?php linearGradient($tab_prefixes, 'left bottom', '#B8B8B8', '#A8683E', '0%', '87%'); ?>
   /** par exemple : background-image: -moz-linear-gradient(left bottom, #B8B8B8 0%, #A8683E 87%); **/
}

Note : l'idée n'est pas de réinventer un framework comme SASS ou LESS, juste de montrer quelques possibilités basiques immédiatement utilisables, très facilement créables et qui permettent de gagner du temps.

Autre exemple pratique : un site multilingue

En supposant que l'on ne conserve qu'une CSS, il est possible de passer un paramètre en querystring, ainsi, on pourra savoir dans le fichier quelles propriétés/parties modifier selon le paramètre :

Pour une CSS en langue chinoise :

<link href="../layout/css/styles.php?lang=cn" rel="stylesheet" type="text/css" media="all" />

Pour la langue anglaise :

<link href="../layout/css/styles.php?lang=en" rel="stylesheet" type="text/css" media="all" />

La CSS peut donc être structurée ainsi :

<?php
   if (!empty($_GET['lang'])){
      $lang=$_GET['lang'];
   }
   else {$lang='fr';} // sinon langue par défaut : cocoricoo
?>
#navigation {
   height:60px;
<?php
   echo '  background:#262223 url(../images/menu-' . $lang . '.jpg) 0 0 no-repeat;';
?>
   width:713px;
   /* ici les autres propriétés */
}

Autre avantage, comme la mise en cache se fait sur le nom de fichier et la querystring (imaginez que styles.php?lang=cn est différent de styles.php?lang=fr), il n'y a aucun souci en cas de changement de langue durant la navigation.

Autre exemple : imaginons que vous ayez un menu de navigation, certains textes peuvent être très long en allemand ou en russe là où ils peuvent être très courts (2 caractères) en chinois. Selon le positionnement, il est possible d'avoir quelques petits soucis désagréables.
L'utilisation de if peut également permettre d'adapter certaines propriétés de manière très locale afin de pallier à ces petits soucis.

#menuaccess a {
   <?php
   if ($lang=='ru' OR $lang=='de')
      echo '    font-size:80%;';
   else
      echo '    font-size:90%;';
   ?>
}

Site à fort trafic : des solutions simples

Le principal inconvénient de cette méthode est de mobiliser PHP pour générer la CSS - même si les ressources mobilisées sont très légères - cela peut poser problème dans le cas d'un site à fort trafic où le serveur peut être déjà bien sollicité. Dans ce cas, il faudra sérieusement envisager la mise en cache.

Une simple convention de notation permettra de générer directement les fichiers statiques de vos CSS, par exemple style_<lang>.css. Pour que la mise en cache soit possible à chaque mise à jour des CSS, il suffira de prévoir une date unique qui sera passée en querystring, ce qui donnerait :

<link href="../layout/css/style_fr.css?v=201202231234" rel="stylesheet" type="text/css" media="all" />

Conclusion

Pour des problèmes simples ou certains cas bien précis, l'utilisation de PHP pour générer des CSS est une solution pratique, nécessitant peu de connaissances, simple et efficace : la maîtrise des CSS est totale. C'est un juste milieu entre la CSS totalement statique et des frameworks plus évolués.

Commentaires

jeanphix a dit le

Bonjour,

selon moi cette solution reste à éviter:
* un fichier css pouvoir être servi directement par un proxy et doit donc rester statique, la compilation doit se faire hors d'un cycle de requête.
* php n'est pas un language de template très adapté pour ce genre d'usage: un des intérêts d'utiliser un compilateur css est d'avoir des feuilles de styles facilement maintenables et de gagner en productivité.
Au passage, il faudrait provilégier l'utilisation de syntaxes du type <?php if(): ?><?php endif; ?>
* un bon compilateur css (sass, stylus...) n'est pas difficile à prendre en main est permet de produire rapidement des styles. Exemples (les deux premiers cas) avec stylus:

couleur-text = #fc4022

body
page
color couleur-text

img
.ma-box
transition(all 1s)

.ma-box
border 1px solid #fff

Plus sympa visuellement, non?

Nico3333fr a dit le

Comme je l'ai écrit, c'est à utiliser dans certains cas bien précis, ça n'a pas vocation de remplacer LESS ou SASS (je ne dis même pas que c'est meilleur ou pire), c'est une solution alternative.

Sur la syntaxe type <?php if(): ?><?php endif; ?>, je ne suis vraiment pas convaincu : lire http://stackoverflow.com/a/2715153 à ce suje... (bon, c'est minime).

jeanphix a dit le

@Nico3333fr : bein, je ne vois pas trop dans quels cas en fait. Pour la langue, tu dois pouvoir faire ce genre de chose:

.fr #menuaccess a {...}

html[lang=fr] #menuaccess a {...}

non?

Nico3333fr a dit le

Tout à fait, c'est une excellente solution. :)

Seul inconvénient (minime) : le second sélecteur n'est pas supporté par l'abominable IE6. ^^

Après, j'ai vraiment pas écrit cette astuce en disant que c'est à utiliser partout (d'où le paragraphe sur le site à fort trafic), c'est à utiliser avec des pincettes et dans certains cas bien particuliers (j'ai utilisé ça sur qq sites multilingues à très faible trafic, où il y avait impossibilité d'utiliser correctement un LESS...).

MoOx a dit le

Idem que jeanphix, cette solution est vraiment pas justifié. Sachant que avec Less ou Sass (via la syntaxe Scss), la syntaxe CSS est totalement compatible. On peut donc renommer un fichier .css en .scss ou .less et ça fonctionne (pas de modification majeur de syntaxe).

Apprendre à mettre un $/@ pour faire un nom de variable et comment écrire if est certainement plus rapide que à la longue se taper des <?php ?> à tire-larigot...

Surtout qu'avec des solutions comme Compass.app (pour Sass/Scss), Less.app, Scout.app, ou encore Codekit et j'en passe, ceci couplé à guard ou Livereload (pour avoir les modifications instantanément dans la page sans rafraichissement), on sera beaucoup plus efficient pour produire des feuilles de styles évolutives.

jeremy-p a dit le

C'est intéressant d'imaginer des mécanismes de ce type pour automatiser un peu nos CSS, je n'aurai jamais pensé faire un tel usage de PHP. Et puis comme c'est du PHP basique, ça me parle bien ! :) Merci pour cette astuce en tout cas !

yogoo a dit le

Astuce intéressante, mais je ne vois pas dans quel cas concrets cela pourrait être utilisé. D'autre part, mélanger du php dans du css, c'est comme mélanger du php dans de l'html, ça mène inévitablement à des bugs et à des temps de maintenance élevés... Sans compter que c'est illisible.

Y'a d'autres problèmes et les solutions existent :

* Comme le dis jeanphix, les css doivent être statiques pour les personnes qui sont derrière un proxy. La solution existe. Voir la technique de cache busting d'HTML5Boilerplate.

* Pour le sélecteur [attr=value] et IE6, un polyfill tel que selectivizr règle le problème tout en limitant l'impact sur le temps de chargement (4ko). Ca assure une transition plus douce quand le support d'IE6 sera stoppé en Chine ;o) et ça ne pénalise pas les navigateurs récents. Ceci dit, même en Chine IE6 est minoritaire avec 23,8% de PDM

* Concernant LESS, les fichiers peuvent être *automatiquement* compilés et minifiés en local en tâche de fond à chaque modification (!) Reste plus qu'à uploader le fichier css résultant comme n'importe quel fichier css. J'imagine que c'est également possible avec SASS/Compas.

* Sur un site complexe, les css deviendront très vite illisibles et impossibles à maintenir.

Bref, à part à l'appliquer sur une petite poignée de styles, cette astuce ressemble à l'exemple parfait de ce qui est à éviter.

Olivier C a dit le

Et bien moi c'est pareil. Je préfère de loin la solution de générer en php des class dans la balise body pour cibler les éléments d'une page. Je trouve cela plus cohérent. Et encore, je n'utilise cette solution qu'en dernier recours.

Planplan a dit le

Une autre façon d'utiliser PHP pour gérer le CSS :
http://oldblog.pixarea.com/index.php/2007/01/...

doc mcfly a dit le

J'utilise le PHP pour "compresser" le css en enlevant les retours à la ligne en "live". Donc la partie Gzipage m'intéresse !

kim_doudou a dit le

Je trouve ça extrêmement intéressant même si comme le dit Nico c'est pas à implémenter partout. Malgré les nombreux inconvénients cités dans les commentaires précédents, je garde cette astuce sous le coude. :)

Skoua a dit le

J'ai déjà fais ça pour des fichiers javascripts, pour les localiser par exemple.

Mais c'est pas facile à gérer par la suite et je préfère éviter autant que faire se peut personnellement.

jmlapam a dit le

Salut,

Merci de l'astuce.
PHP peut tout faire et c'est vrai que l'on économise des écritures assez pénibles notamment avec les préfixes vendeurs où tu dois réécrire 4 fois la même chose !

En revanche je n'ai pas compris la notion de "maîtrise absolue de ses CSS"

Nico3333fr a dit le

@jmlapam : PHP est bête : il n'ajoutera comme code que ce que tu lui indiqueras de faire.

Darklg a dit le

Je me permets de remonter un vieil article que j'avais fait sur ce sujet :
http://darklg.me/2010/02/compresser-ranger-cs...

Le principal intérêt de cette méthode étant de concaténer ses fichiers CSS, de les compresser, pour ensuite produire un fichier statique qui sera appelé, afin de profiter de toutes les performances de son serveur (Apache, nginx ou autre)

syndrael a dit le

Le sujet est intéressant surtout pour les débutants dans le développement Web. Les gens aguérris connaissent d'autres alternatives qui offrent des souplesses de développement ou qui sont plus respectueuses des archi n-tiers..
Et puis il ne faut pas être plus royaliste que le roi.. surtout dans le monde de l'optimisation. Optimiser une page pour 4 visites / jour, c'est de la confiture aux cochons pour un gain nul, sauf la satisfaction du développeur.. ce qui peut être tout à fait louable, car il se couche moins bête le soir..
N'oublions pas que LESS et SASS n'existent que depuis qqs années, et encore.
On a tous débuté un jour ou l'autre..

KyleKatarn a dit le

jeanphix > Il suffit de coupler ceci avec une mise en cache et cela revient à utiliser des fichiers statiques.

Sinon, je me permets de vous parler de mon outil : webftp.selfbuild.fr
LessCSS y est intégré et vous pouvez donc modifier votre fichier en utilisant les raccourcis Less sans vous préoccuper de la compilation, l'astuce, c'est que ce webFTP va enregistrer une version compilée (et minifiée) : celle qui sera ensutie chargée par vos visiteurs et une version source dans un dossier .src/ qui permet de retrouver le code d'origine, ainsi lorsque vous souhaitez modifier le fichier, la source est chargée à la place, ce qui rend l'opération totalement transparente pour le codeur et ne consomme aucune ressource (les visiteurs chargent bien des fichiers statiques).

J'ai aussi rajouté quelques raccourcis du style :
size:23 45; > width:23px; height:45px;
[[propriete:valeur]] > propriete:valeur; -moz-propriete:valeur; -webkit-propriete:valeur; (et 2, 3 autres préfixes de compatibilité)

Personnellement, ça me permet de gagner beaucoup de temps. Que pensez-vous de cette solution ?

piwaille a dit le

bonjour

Je suis principalement "consommateur" de vos astuces et tutos ..
Pour une fois je réagis : taka utiliser php, autant y aller franco. Par exemple la partie
<?php
$transition = '-webkit-transition: all 1s;
-moz-transition: all 1s;
-ms-transition: all 1s;
-o-transition: all 1s;
transition: all 1s;';
?>
peut être simplifiée en demandant à php de ne sortir que le code de transition qui correspond au navigateur ! On ne va peut être pas diviser la taille du CSS par 5, mais ça sera déjà bien plus léger (et beaucoup plus lisible)

arnolem a dit le

Ca choque tout le monde de générer un css ou un js avec du php mais pourtant, vous générez tous du html.
les problematiques sont exactement les meme : architecture (mvc), performance, cache, maintenabilité, ...
PHP peut etre utilisé pour le html, le css, le javascript, les pdf, les images, les csv, les vcard, ...
A vous de rèflechir